PLMBase Component : Resources and Archives
The goal of the classes in this part is to simplify
data access to the application. The first mean is by
using a Resource manager that will find and load the
files for you, and maintain a list of loaded
resources. The second mean is by creating archives,
that a big file that contains all the resource files
needed by an application such as images, fonts, text
files, sounds, ... The last mean is to use the
PLMResFile class to easily handle files (read / write
with automatic conversion in little endian format).
-
PLMResource : A simple virtual class that
defines the interface of all resources, in other
words Load() and Save() methods. Most "loadable"
classes in PLM derives from it so that it can be
used with the resource manager.
-
PLMResMgr : The main class of this part,
designed to be simple to use. You can define
multiple sources (standard directories or
archives), then just ask to load a file.
-
PLMResFile : A File class designed to ease
the data conversions (little/big endian), to
precisely read or write any integer size, and most
of all to simulate small files inside bigger ones
(when used to load data from archives).
-
PLMFileProvider : A virtual class
implemented here by PLMArchiveLoader and in the
Base section by PLMDir. Gives a uniform way to
PLMResMgr to find files.
-
PLMArchiveLoader : Read-only part of the
archive interface. Allow to load (extract) data
from archives. Standard applications usually only
need this interface.
-
PLMArchiveMaker : Read-Write part of the
archive interface. Allows to create and modify
archives (add, remove and update files). Only used
by archives managers.
-
PLMArchiveHandler : A virtual class to give
a uniform access to archives. The two previous
classes use an object of this class. Real archives
are implemented by the following classes, that
derives from this one.
-
PLMAH_PLM : Implementation of the PLM
archive file format.
-
PLMAH_PAK : Implementation of the PAK
archive file format (Quake 1 and 2, and other games
relative to Quake engine).
First, let's see an example about PLMResFile :
// try to open the file toto in read-only mode
PLMResFile f ("toto");
// check that all is ok
if (! f.Good())
{ cerr << "Can not open file toto\n"; return; }
// compute the length of the file (in bytes)
f.SeekEnd ();
u32 size = f.GetPos ();
f.SeekStart ();
cout << "File size = " << size << " bytes.\n";
// read some data
u8 Char = f.Read8 (); // read 1 byte
u16 Short = f.Read16 (); // read 2 bytes (little endian conversion)
u32 Int = f.Read32 (); // read 4 bytes (little endian conversion)
// close the file (optional, done by the destructor)
f.Close ();
|
Note that PLMResFiles are automatically closed when
the object is deleted, but you may need to close it
before, to delete or rename it for example.
A classical example of PLMResMgr use :
// simple creation
PLMResMgr resmgr;
// then add some sources (should test return value)
resmgr.AddSource ("./data"); // add "data" directory
resmgr.AddSource ("./data/sprites.dat"); // add sprites.dat archive file
// later in the program
PLMImage *sprite1 = (PLMImage*) resmgr.Load ("spr1.pcx", ORES_PCX);
if (sprite1 == NULL) ... error
PLMSound *sound1 = (PLMSound*) resmgr.Load ("snd1.wav", ORES_WAV);
if (sound1 == NULL) ... error
|
Notes:
-
The files spr1.pcx and snd1.wav can be anywhere in
the sources (in the data directory or in the data/sprites.dat
archive file).
-
The first instance found is returned.
-
A common error is to use the current working
directory as a source instead of the executable
directory.
-
You do not have to delete a resource loaded by the
resource manager, since it can be used by other
objects.
-
They are automatically deleted when the manager's
destructor is called. If you must delete one
absolutly, simply call its Remove() method (and
make sure no objects use it before).
-
A 3D version of the manager exists, able to load
the same resource types, plus 3D fonts and
textures.
The next example shows how to open and print the
content of a PLMFileProvider (can be a directory or
an archive) :
// create an archive loader as file provider
// we could have used a PLMDir object instead
PLMFileProvider *source = new PLMArchiveLoader;
ASSERT (source);
// try to open an archive
if (! source->Open ("sprites.dat"))
{ delete source; cerr << "Can not open sprites.dat\n"; return; }
// sort its content by name, case sensitive and directories first
source->Sort (PLM::SORT_NAME | PLM::SORT_CASE | PLM::SORT_DIRS);
// use an iterator to print every entry
PLMFileProvider::SortedIterator it = source->GetSortedIterator ();
for (; it.IsNotEnd (); it.Next ())
{
cout.setf (ios::left, ios::adjustfield);
cout << " - " << setw(40) << it.Name() << ' ';
cout.setf (ios::right, ios::adjustfield);
cout << setw(10) << it.Size() << '\t';
if (it.IsDir()) cout << "/ ";
if (it.IsHidden()) cout << "H ";
if (it.IsLink()) cout << "->";
cout << endl;
}
|
|