Bug in SDL_RWops?

Started by
1 comment, last by Koshmaar 18 years, 8 months ago
Hi guys, I have "little" problem with SDL_RWops. If you don't know what's this, I tell you: it's part of SDL responsible for abstracting reading/writing operations on various streams (ie. file, memory). Wiki is here and here. As to my problem - you see, I'm trying to load config file (which is normal text file) line by line (cause it's the way parser is working) from SDL_RWops source. That source is created using this code, borrowed from SDL_Image: SDL_RWops *source = SDL_RWFromFile(filename.c_str(), "r"); Since lines can be of any sizes (could be 10, 1024 or 1, no limits), I need a way to determine where are '\n' located. That way, I can dynamically mallocate enough memory and fill it with all characters up to '\n' - which will be passed to parser, then we deallocate that memory, move to next line and so on. Seeking for char inside SDL_RWops is performed by this "little" function. I know it's far from perfect, but it *should* be working - however, output I get from stderr shows that it isn't, and I suspect nasty bug in SDL_RWread() or SDL_RWtell().


#define CFG_DEBUG(x, y) fprintf(stderr, x, y);

// returns size of line to create, counting from current read-ptr position
//  xxx -char we're looking for
int SDL_RWfind( SDL_RWops * source, char xxx, int * last_line_length)
 {
  const int buffer_size = 512;

  // we're reading up to buffer_size characters to this buffer
  char buffer [buffer_size];
  
  // number of bytes read during last SDL_RWread()
  int read;

 // number of bytes that were read up to now
  int read_all = 0;
  char * buffer_ptr;
  
  do
   {

    // -------------------------------- start of the most important part !

    // get current offset (before reading)
    CFG_DEBUG("\nSDL_RWfind: Current offset before RWread: %i.\n", SDL_RWtell(source));

    // according to SDL Wiki, SDL_RWread: "It returns the number of memory blocks read"
    // and here blocks have size of 1 - so it should return the number of characters read
    read = SDL_RWread(source, buffer, 1, buffer_size ); 
    
    CFG_DEBUG("SDL_RWfind: Read characters: %i.\n", read);
    
    // get current offset (after reading)
    CFG_DEBUG("\nSDL_RWfind: Current offset after RWread: %i.\n", SDL_RWtell(source));

    // -------------------------------- end of the most important part,  next lines of this function were added just for completness sake


    if (read < 0) { CFG_DEBUG("Couldn't read even one block from stream while seeking: %c.\n", xxx); return -2; }
    
    buffer_ptr = buffer;
    read_all += read;

    while ( (buffer_ptr - buffer) < read )
     { 
      if ( (*buffer_ptr) == xxx) // we've found it
       {     
        SDL_RWseek(source, -read_all, SEEK_CUR);
        return ( buffer_ptr - buffer);
       }
       
     ++buffer_ptr;
    }
     
  } while ( read == buffer_size );

  *last_line_length = read_all; 
  SDL_RWseek(source, -read_all - 1 , SEEK_CUR);
  return -1;
 }



And now, most important part of this mail: After using that function for this file:

bad_integer = 1234
good_integer = 1234


... I get in stderr this:


1) SDL_RWfind: Current offset before RWread: 0.
2) SDL_RWfind: Read characters: 41.
3) SDL_RWfind: Current offset after RWread: 45.



Do you see what's going on? We have read 41 characters (line 2) starting from offset 0 (line 1), so we should be at position 41, right? But line 3 says that we're at position 45!!!! And as you can see, there weren't ANY reading / writing / seeking etc. going on! The only logic I could see after this behaviour: whole file has size of 45 bytes. But that shouldn't change anything... If someone could tell me whether this is SDL_RWops bug, it's my code's failure, or has working function for finding char in SDL_RWops stream or sth similiar, I would be really gratefull for sharing it with me ( you know, ++rating etc. ;-) )
Advertisement
Looks like it might be a bug that's been fixed in CVS. Any way you could build the CVS version of SDL and check?
I like the DARK layout!
You're right, I remember from SDL mailinglist that there were thread about possible bug in SDL_RWops, that has been fixed in CVS - what a shame I can't google it up now :-/

(after a minute)

Ok, I've found it :-) it's here: http://www.devolution.com/pipermail/sdl/2005-May/068922.html.

and quoting part:

Quote:
SDL_RWops changes

Bugs:
-Reading from memory was not consistant with how reading from files worked.
A file of 55 bytes stored into 'ptr' by using 6 sets of 10 bytes would copy
55 bytes into 'ptr' and SDL_RWread would return 5. But the same act done on
mem RWop would result in 50 bytes copied and 5 returned.

-Seems that SDL_RWclose should return fclose's return value instead of 0

-Since there is no feof or ferror wrappers... if read or write return less
than requested... it was not known why. Added SDL_RWeof, SDL_RWerror, and
SDL_RWclearerr

-mem_writeconst() would return a -1... but fwrite nor mem_write would return
a -1 on an error... especially since the concept of knowing an error occured
didnt exist... return 0 now and sets flags as error.

-since it is obvious RWops is based off stdio FILE's... it would make sense
to use the same data types.
> ftell returns a long... RWseek returns ftell so RWseek returns long
> seek's offset argument is now a long
> read and write take size_t's instead of int's and return size_t's

-where RWop was free'd in RWclose functions... appears it should have been
using SDL_FreeRW since RWFromX's use SDL_AllocRW

-In unix_to_mac function... called from SDL_RWFromFile with a
const char* file = NULL would try to strlen(NULL)

-No check on the malloc used in unix_to_mac... put in check.

-mem_read and mem_write didnt check for overflows the same way fread/fwrite
do (at least how dietlibc impliments them)... if num or size are 0
return 0... if ((num * size) / num) != size) return 0

Misc:
-Fixed some comments in SDL_rwops.h

-renamed a few arguments for consistancy

-SDL_RWops.type is completely unused... removed.

-SDL_RWops.unknown also unused... removed.

-Added SDL_OutOfMemory error setting to any malloc's

-unknown values for 'whence' now also set RWerror

Enhancements:
-Added the concept of SDL_RWeof, SDL_RWerror, and SDL_RWclearerr

-Created SDL_RWFromMallocedMem(void* ptr, size_t size)
If 'ptr' is NULL... it allocates 'size' bytes for you, otherwise
'ptr' must be from standard malloc. If you attempt to write past the
end of the buffer it will realloc the buffer. You may also treat it
like a file stream works... you can seek past the actual end and
when you attempt to write data it will realloc and copy the data. Area
between the original end and the seeked position will contain '\0''s
just as a write performed on a file which was seeked past it's end.
If realloc fails the buffer stays the same and the error flag is set.




First entry in Bugs section looks somewhat similiar (reading from file stream, wrong values) and that's probably what happened to my code.


I think I could build SDL from CVS on my own... but that's the last thing I would like to do, since it would take (too) much time and made some not-trivial changes to my coding enviroment. And knowing that last version of SDL was released more than half a year ago, and it's time for 1.2.9 now...


So, do you see any way to work-around this bug? Yes, I want to hack it, but I don't know exactly what is causing it. Any thoughts? Thx for help :-)

This topic is closed to new replies.

Advertisement