1

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.

matthias_h
  • 11,356
  • 9
  • 22
  • 40
laura
  • 51
  • 5
  • "IMG_Init seems to work fine" So you passed in `IMG_INIT_PNG` & verified that bit was also returned? – genpfault Apr 06 '20 at 19:40
  • Using the debugger, is the pair of lines `zip_fclose(file);` `SDL_FreeRW(rwop);` reached? – Ripi2 Apr 06 '20 at 19:46
  • genpfault: yes I did that in an initailization function that ran successfuly before this ripi2: the last zip_fclose(file); is reached, there's no SDL_FreeRW(rwop) before the SDL_Surface* surf_load = IMG_Load_RW(rwop, 0); that gets executed because no errors occur before then. I didn't check after the IMG_Load_RW error occurs but I'm not getting a segfault or anything. – laura Apr 06 '20 at 20:20

2 Answers2

3

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;
  }
laura
  • 51
  • 5
  • I am glad @laura, it is a good practice to post code example and make it clear for all. Just like you did in your question. – Nikola Lukic Apr 07 '20 at 08:56
  • Thank you for the help piecing it together, you made sure I went through all the simpler things and I double checked all my data because of that. – laura Apr 07 '20 at 23:06
0

If you call SDL_FreeRW(rwop); before IMG_Load_RW(rwop, 0); then you get nothing from memory.

If is not problem freeRW then use :

IMG_LoadPNG_RW instread IMG_Load_RW also IMG_isPNG can be good for checking.

In other way looks like you have bug with version correlation betwean SDL i SDL_Image . If you use SDL2 then also use SDL2_image lib.

UPDATED

  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_LoadPNG_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;
  }
Nikola Lukic
  • 4,001
  • 6
  • 44
  • 75
  • I'm confused, I don't think I did that in the code I posted outside of an error if statement. Can you point it out in specific? – laura Apr 06 '20 at 20:33
  • Looks like you call `SDL_FreeRW(rwop);` when while loop finish the job. – Nikola Lukic Apr 06 '20 at 20:46
  • 1
    That should also be accompanied with an error message, and on top of that I double checked to make sure I can still get a pointer to the vector using rwop->hidden.unknown.data1 which matches rwbuffer.data(). Do you know why it would fail to call the associated error? – laura Apr 06 '20 at 20:53
  • I update answer . Try `IMG_LoadPNG_RW` it is from SDL Image 1.2.8 – Nikola Lukic Apr 06 '20 at 21:01
  • I tried that as well, the IMG_LoadPNG_RW gave me a "Not a PNG" error, and IMG_isPNG returned false when I checked that. – laura Apr 06 '20 at 21:08
  • Ok check all libs version now! – Nikola Lukic Apr 06 '20 at 21:13
  • I seem to have updated SDL2 and SDL2 Image. I found that my rwops has an abnormally large size much greater than the vector's array data, and I'm thinking that's the cause, but I don't know why the SDL_RWFromMem(rwbuffer.data(), filestat.size); gives it that size – laura Apr 06 '20 at 21:28