c++sdlsdl-imagelibzip

Using SDL_image and SDL_RWops with LibZip to load pngs from a zip onto a surface, but won't recognize png


Relevant code:

  zip_stat_t filestat;
  uint64_t filetotal = 0;
  SDL_RWops* rwop = SDL_AllocRW();

//bunch of code that's not relevant to the matter goes here

  std::vector<char> rwbuffer(filestat.size);
  rwop = SDL_RWFromMem(rwbuffer.data(), filestat.size);
  while(filetotal < filestat.size)
  {
    char buffer[256];
    int64_t length;
    //read the file into the buffer
    length = zip_fread(file, buffer, 256);
    if (length == -1)
    {
      u_error(std::cerr, CC_ERROR_ZIP, "zip_fread");
      zip_fclose(file);
      SDL_FreeRW(rwop);
      return false;
    }
    //write the buffer into the rwop stream
    if ( (uint16_t)length != SDL_RWwrite(rwop, buffer, 1, (size_t)length) )
    {
      u_error(std::cerr, CC_ERROR_SDL, "SDL_RWwrite");
      zip_fclose(file);
      SDL_FreeRW(rwop);
      return false;
    }
    //Increment the count so that the loop ends
    filetotal += length;
  }
  zip_fclose(file);
  //Put it onto a surface
  SDL_Surface* surf_load = IMG_Load_RW(rwop, 0);
  if(surf_load == NULL)
  {
    u_error(std::cerr, CC_ERROR_IMAGE, "IMG_Load_RW");
    SDL_FreeRW(rwop);
    u_cleanup(surf_load);
    return false;
  }

//...

I've dumped the contents of the vector rwbuffer with a debugger and it's a valid png, but IMG_Load_RW still gives me an error "Unsupported image format." I've got libpng installed and IMG_Init seems to work fine so the SDL_image library must be working. Clearly libzip is giving me correct data. I'm very confused as to why I'm getting an error.


Solution

  • I figured it out. At the end of my while loop for the data reading, the seek value for the RWops stream is at the end of the file, and IMG_LoadPNG_RW doesn't reset it, so I have to manually SDL_RWseek(rwop, 0, RW_SEEK_SET); after the while loop is finished in order to read the png data.

      //Return the seek pointer of the RWop to the beginning so that the file can be read
      SDL_RWseek(rwop,0,RW_SEEK_SET);
      //Put it onto a surface
      SDL_Surface* surf_load = IMG_Load_RW(rwop, 0);
      if(surf_load == NULL)
      {
        u_error(std::cerr, CC_ERROR_IMAGE, "IMG_Load_RW");
        SDL_FreeRW(rwop);
        u_cleanup(surf_load);
        return false;
      }