[Scummvm-devel] New File(Manager) API

Max Horn max at quendi.de
Sun Apr 11 04:32:04 CEST 2004


Am 11.04.2004 um 07:28 schrieb Pawel Kolodziejski:

[...]

>> There are three parts to this:
>>
>> 1) ReadStream & WriteStream interfaces and subclasses which implement
>> them.
>>    These are meant to abstract away reading/writing from "streams",
>> which can be files, or memory buffers, or anything else you might come
>> up with. The File class implements both. And there is a XORReadStream
>> which wraps around any ReadStream, adding "XOR encryption" to that
>> stream (which can be used by the SCUMM frontend, and allows us to get
>> rid of the SCUMM specific XOR encryption code in the File class)
>> These are actually mostly independent of my other changes. I'd like to
>> see those (or a variation of them) in whether we do the rest or not.
>> They'll allow us to unify the code in sound/voc.cpp, for example.
>
> that XXXReadStream will be inside/transparent to read() func ?
>
> it will select stream while creating File class constructor ?

No, that wasn't the plan. Rather you can wrap the XORStream around any 
other ReadStream (including File's). So you can have code like this:

   class ScummEngine {
     File *_dataFile;
     ReadStream *_dataStream;
     ...
   };
   ...
   _dataFile = ...;
   if (useEncryption)
     _dataStream = new XORStream(_dataFile);
   else
     _dataStream = _dataFile;

   ...
   _dataFile.seek(pos);
   int32 data = _dataStream.readSInt32();
   ...


[...]

>> The thing which is a bit more complicated is that you can't create 
>> File
>> instances directly on the stack anymore. If that is bothering people a
>> lot, it wouldn't be too hard to "Fix" this, though. Just tell me.
>
> That would be usefull when there is much more 'ifs' in func with 
> closing
> file while something goes wrong. at stack it will be only once when 
> func
> finish.

Yes, that is my main concern, too. However, to allow stack instances of 
the File class  would require us to make the File class a lot more 
complicated (we'd have to introduce a new internal class 
FileImplementation and use some voodoo, etc).

The easy solution, IMO, would be to introduce something similar to the 
Std C++ libs auto_ptr class. An auto_ptr is a bit similar to our 
StackLock in concept: it's a template class which holds a pointer to a 
C++ object; and it's destructor deletes that pointer. I think a simple 
example highlights what I mean better than many words:

bool dummyFunc() {
   FilePath filepath("answer");
   AutoPtr<File> myFile = filepath.makeFile();
   myFile->seek(42);
   if (myFile->readByte() != 42)
     return false;
   theAnswer = 42;
   return true;
}

This function has to exit points, yet there is no leak. Because when 
exiting the scope, myFile's destructor executes, which deletes the File 
object returned my filepath.makeFile().

The added bonus is that we can use this autoptr thing for other 
purposes, too. I.e. whenever you have a temporarily allocated pointer 
sitting around.

>
>> Search path handling would also be very easy, I provided a convenience
>> method tryOpenFile(), which does it. You can use it like this:
>>
>>    PathList searchPaths;
>>    const char *dirs[] = { "", "video", "VIDEO", "data/", "DATA/", 
>> ..., 0
>> };
>>    int i = 0;
>>    while (dirs[i]) {
>>      FilePath path(dirs[i]);
>>      if (path.exists() && path.isDirectory()) {
>>        searchPaths.push_back(path);
>>      }
>>    }
>>    ...
>>    File *myFile = tryOpen("MONKEY.000", searchPaths, kFileReadMode);
>
> is it client code ?

Yes, this would be typical client code. The above could be an excerpt 
of the SCUMM engine.

> in previous example instance is created from filepath , now this is
> created    from what instance ?

I assume you mean: how does tryOpen() create the File pointer? Look at 
newfile.h, the implementation of tryOpen() is given there. I'll paste 
it here again for reference:

File *tryOpenFile(String name, PathList searchPaths, File::AccessMode 
mode = kFileReadMode) {
	for (PathList::Iterator iter = searchPaths.begin(); iter != 
searchPaths.end(); ++iter) {
		// TODO: Maybe also try case variations of the given 'name', i.e. also
		// try with 'name' converted to lower/upper case.
		FilePath path(*iter, name);
		if (path.exists() && path.isFile() && path.isReadable())
			return path.makeFile(mode);
	}
	return 0;
}

  Essentially, it loops over all paths in searchPaths, then checks 
whether a readable file with the specified name exists there, and if 
so, returns a File pointer to it. Otherwise, 0 is returned.


>
>>    if (!myFile)
>>      error("Couldn't open MONKEY.000");
>>    byte firstByte = myFile->readByte();
>>    ...
>>
>> Of course the computation of "searchPaths" only has to be done once.
>
> Does that search path will be initialized at engine initialization ?

For example, yes. But it's completely up to the client code how this is 
done. I.e. nothing stops us from having multiple "searchPaths" (e.g. 
one for game data files, one for video, etc.). This is IMO a very nice 
improvement over the current hard-coded list of "search paths" in 
file.cpp. Moreover, the path list is of course not restricted to 
pointing at subdirs of one directory. If we want to fulfill that one 
feature request and add a "secondary_path" config variable (so you can 
e.g. share the music files between your two versions of The Dig, which 
would be nice e.g. for me :-), then supporting that is trivial in the 
new setup.

>
>>
>> Cheers,
>>
>> Max
>>
>
> This draft explain only few area of code.
> Can you draft full example of implementation ? not necessary C++ :) too
> have full image of implementation.
>
If you mean whether I can implement the specs outlined in the header 
file? Of course I can, but it's of course quite some work, and I first 
want to gauge how people perceive the draft. I.e. no fun in 
implementing this if I am then told it's all crap and have to throw 
away my work :-)

Although so far the two replies I got (by you, Pawel, and by Sev) where 
(in my impression) more positive than negative :-).

If you mean you would like to see more examples of how this new code 
would be used: I tried to give some more in this email, and if you want 
to see more, just ask me about specific things, and I can write an 
example demonstrating how you'd do it.


Cheers,

Max





More information about the Scummvm-devel mailing list