Search code examples
csdlstdio

Why use the SDL I/O functions over the stdio functions?


SDL contains many functions for dealing with I/O centering around the SDL_RWops struct. Alot of them are very similar to the stdio I/O functions, to the point where they use the same style of string. For example, fopen vs SDLRWFromfile.

Why is this the case and should I aim to use SDL I/O functions over the standard library? Are the SDL functions more portable?


Solution

  • The interest of the SDL_RWops is that it's just an interface structure with function pointers used to read/write/seek/close...

    typedef struct SDL_RWops {
        /** Seek to 'offset' relative to whence, one of stdio's whence values:
         *  SEEK_SET, SEEK_CUR, SEEK_END
         *  Returns the final offset in the data source.
         */
        int (SDLCALL *seek)(struct SDL_RWops *context, int offset, int whence);
    
        /** Read up to 'maxnum' objects each of size 'size' from the data
         *  source to the area pointed at by 'ptr'.
         *  Returns the number of objects read, or -1 if the read failed.
         */
        int (SDLCALL *read)(struct SDL_RWops *context, void *ptr, int size, int maxnum);
    
        /** Write exactly 'num' objects each of size 'objsize' from the area
         *  pointed at by 'ptr' to data source.
         *  Returns 'num', or -1 if the write failed.
         */
        int (SDLCALL *write)(struct SDL_RWops *context, const void *ptr, int size, int num);
    
        /** Close and free an allocated SDL_FSops structure */
        int (SDLCALL *close)(struct SDL_RWops *context);
      // ... there are other internal fields too
     }
    

    When using for instance SDL_LoadBMP, SDL creates a SDL_RWops object from a file handle, but you can also create SDL_RWops object from other sources, for instance a memory location, for instance for systems that don't provide a filesystem natively (Nintendo DS comes to mind, even if homebrew linker carts like R4 or M3 are generally able to provide such a service).

    From SDL_Video.h:

    /**
     * Load a surface from a seekable SDL data source (memory or file.)
       ...
     */
    extern DECLSPEC SDL_Surface * SDLCALL SDL_LoadBMP_RW(SDL_RWops *src, int freesrc);
    
    /** Convenience macro -- load a surface from a file */
    #define SDL_LoadBMP(file)   SDL_LoadBMP_RW(SDL_RWFromFile(file, "rb"), 1)
    

    So SDL_LoadBMP is a macro that invokes SDL_RWFromFile(file, "rb"), which certainly uses standard library to create a handle to a file and creates a SDL_RWop object with function pointers initialized to standard library existing read,write,seek,close functions.

    In that case, you could have your assets hardcoded in the executable binary as array of bytes, and map a SDL_RWops object on that memory.

    So in the case of SDL functions, you have to use them (even if their use is hidden). But if you have other resource files (like audio, configuration files) that you're not feeding to SDL, you can use standard library to read them.