For previous discussion on this topic, see this thread:
http://www.sfml-dev.org/forum/viewtopic.php?p=32631#32631Specifically, I'm interested in custom file/stream I/O support for resource loading in SFML. Mainly because I have interest in using zip file "packages" for game modules in my projects, and I want to be able to load resources directly from those packages without having to dump the file into memory first.
The current LoadFromFile and LoadFromMemory options available in SFML are unsuitable for this goal, so I suggest the below abstract class as well as "LoadFromStream" functions added to any and all resource loading classes.
As mentioned in the above thread, I am entirely willing to work towards wrapping existing libs (like libsndfile, etc) to use the below class.
namespace sf
{
class ResourceStream : public NonCopyable
{
public:
//=============================================
// enums and typedefs
typedef Int64 Offset;
enum Mode
{
SeekOrigin,
SeekOffset,
SeekEnd
};
//=============================================
// construction / destruction
virtual ~ResourceStream() { }
//=============================================
// stream I/O
virtual Offset Read(void* data, Offset size) = 0; // returns bytes read
virtual Offset Write(const void* data, Offset size) = 0; // returns bytes written
virtual Offset Seek(Offset pos,Mode = SeekOrigin) = 0; // returns position seeked to (-1 on error)
virtual Offset Tell() = 0; // returns -1 on error
virtual Offset GetSize() = 0; // returns total file size (-1 on error)
};
} // namespace sf
Not very complicated. KISS.
Design decisions:
1) no const functions. (precedent: STL). You typically don't have const streams anyway. Additionally, even tasks that seem const may not be. (GetSize for example, may involve seeking, violating const rules)
2) no error reporting. (precedent: SFML). Getting bogged down with error reporting would make the class complicated and the minimal requirements for deriving your own class more difficult. As it stands now, implementing the above is very straightforward and simple.
And considering this class is designed to be used in SFML resource loading classes, and those classes don't have detailed error reporting anyway, the information would likely be lost.
3) I did my best to mimic SFML naming conventions. I'm not sure about the enum, though. Maybe that could be better.
4) typedeffing Offset seemed to add clarity. It also allows for the possibility of support for future platforms which may not have 64-bit capabilities (maybe some hand-held devices?)
5) I didn't make Doxygen style comments because I'm lazy. That wasn't really a design decision
6) I was torn as to whether or not GetSize should be included. I also considered giving it a body that did the Seek/Tell/Seek approach instead of making it pure virtual. However Seek/Tell/Seek leaves room for problems (what if the 2nd seek fails?).
Plus at least one lib needs such a function. And it shouldn't be hard to implement in derived classes anyway.
Overall I think the simplicity says it all.
Laurent: I hope you give this your consideration, and I am eager to hear your thoughts / feedback.
EDIT:
so I took a look at stb_image.c to see how much work will need to be put into it. Looks like it is going to take a pretty decent chunk of effort in some areas, but in other areas, maybe not so much. He seems to have compartmentalized file I/O (which is good), but the thing that's tripping me up is that there's #ifdef blocks
everywhere and seemingly no indication of exactly what the defines are supposed to do.
It's definitely doable, though.
If he had used a callback mechanism from day 1 of this, he would have saved himself lots of duplicate code. I see 2 sets of functions for pretty much everything -- one for memory loads and one for stdio loads. He could have just implemented one callback set, and then employed it to implement the memory/stdio sets.
Though I suppose that would have an ever-so-slight performance hit.
But whatever. I won't get started on this until I hear back from Laurent anyway. No sense in doing all that work if it will be for naught.