- added an abstract FileReader wrapper.

The idea here is to decouple the actual reader creation from the code using them so that, for example, the Open function can decide if it wants to open the file regularly or memory mapped and return different readers as deemed useful. For that to work the exposed object needs to be an abstract wrapper so that this can be done without having to use pointers and all the drawbacks coming from that.
So far put to use in a few parts of the music code so the general functionality could be tested.
This commit is contained in:
Christoph Oelckers 2018-03-10 13:46:35 +01:00
parent fc981bf5d4
commit 26e948357e
12 changed files with 242 additions and 28 deletions

View file

@ -687,3 +687,31 @@ size_t BufferWriter::Write(const void *buffer, size_t len)
return len;
}
//////////////////////////////////////
//
// The new wrapper
//
//////////////////////////////////////
bool FileRdr::OpenFile(const char *filename)
{
mReader = new FileReader;
if (mReader->Open(filename)) return true;
delete mReader;
mReader = nullptr;
return false;
}
bool FileRdr::OpenMemory(const void *mem, FileRdr::Size length)
{
mReader = new MemoryReader((const char *)mem, (long)length);
return true;
}
bool FileRdr::OpenMemoryArray(const void *mem, FileRdr::Size length)
{
mReader = new MemoryArrayReader((const char *)mem, (long)length);
return true;
}

View file

@ -167,6 +167,61 @@ protected:
bool CloseOnDestruct;
};
// This will need a cleaner implementation once the outer interface is done.
// As a first step this only needs to work properly in the non-error case.
class FileReaderRedirect : public FileReader
{
FileReader *mReader;
public:
FileReaderRedirect(FileReader *parent, long start, long length)
{
mReader = parent;
StartPos = start;
Length = length;
}
virtual long Tell() const
{
auto l = mReader->Tell() - StartPos;
if (l < StartPos || l >= StartPos + Length) return -1; // out of scope
return l - StartPos;
}
virtual long Seek(long offset, int origin)
{
switch (origin)
{
case SEEK_SET:
offset += StartPos;
break;
case SEEK_END:
offset += StartPos + Length;
break;
case SEEK_CUR:
offset += mReader->Tell();
break;
}
if (offset < StartPos || offset >= StartPos + Length) return -1; // out of scope
return mReader->Seek(offset, SEEK_SET);
}
virtual long Read(void *buffer, long len)
{
// This still needs better range checks
return mReader->Read(buffer, len);
}
virtual char *Gets(char *strbuf, int len)
{
return mReader->Gets(strbuf, len);
}
long GetLength() const { return Length; }
};
// Wraps around a FileReader to decompress a zlib stream
class FileReaderZ : public FileReaderBase
{
@ -438,4 +493,106 @@ public:
class FileRdr // this is just a temporary name, until the old FileReader hierarchy can be made private.
{
FileReader *mReader = nullptr;
FileRdr() {}
FileRdr(const FileRdr &r) = delete;
public:
enum ESeek
{
SeekSet = SEEK_SET,
SeekCur = SEEK_CUR,
SeekEnd = SEEK_END
};
typedef ptrdiff_t Size; // let's not use 'long' here.
FileRdr(FileReader *r)
{
mReader = r;
}
FileRdr(FileRdr &&r)
{
mReader = r.mReader;
r.mReader = nullptr;
}
~FileRdr()
{
if (mReader != nullptr) delete mReader;
mReader = nullptr;
}
bool OpenFile(const char *filename);
bool OpenFilePart(FileReader *parent, Size start, Size length); // later
bool OpenMemory(const void *mem, Size length); // read directly from the buffer
bool OpenMemoryArray(const void *mem, Size length); // read from a copy of the buffer.
Size Tell() const
{
return mReader->Tell();
}
Size Seek(Size offset, ESeek origin)
{
return mReader->Seek((long)offset, origin);
}
Size Read(void *buffer, Size len)
{
return mReader->Read(buffer, (long)len);
}
char *Gets(char *strbuf, Size len)
{
return mReader->Gets(strbuf, (int)len);
}
Size GetLength() const
{
return mReader->GetLength();
}
FileRdr &operator>> (uint8_t &v)
{
mReader->Read(&v, 1);
return *this;
}
FileRdr &operator>> (int8_t &v)
{
mReader->Read(&v, 1);
return *this;
}
FileRdr &operator>> (uint16_t &v)
{
mReader->Read(&v, 2);
v = LittleShort(v);
return *this;
}
FileRdr &operator>> (int16_t &v)
{
mReader->Read(&v, 2);
v = LittleShort(v);
return *this;
}
FileRdr &operator>> (uint32_t &v)
{
mReader->Read(&v, 4);
v = LittleLong(v);
return *this;
}
friend class FWadCollection;
};
#endif

View file

@ -309,7 +309,7 @@ MusInfo *MusInfo::GetWaveDumper(const char *filename, int rate)
//
//==========================================================================
static MIDISource *CreateMIDISource(FileReader &reader, EMIDIType miditype)
static MIDISource *CreateMIDISource(FileRdr &reader, EMIDIType miditype)
{
MIDISource *source = nullptr;
switch (miditype)
@ -452,11 +452,14 @@ MusInfo *I_RegisterSong (FileReader *reader, MidiDeviceSetting *device)
EMIDIType miditype = IdentifyMIDIType(id, sizeof(id));
if (miditype != MIDI_NOTMIDI)
{
auto source = CreateMIDISource(*reader, miditype);
// temporary hack so we can test before converting more.
FileRdr rdr(reader);
reader = nullptr;
auto source = CreateMIDISource(rdr, miditype);
if (source == nullptr) return 0;
if (!source->isValid())
{
delete reader;
delete source;
return 0;
}
@ -719,10 +722,10 @@ static MIDISource *GetMIDISource(const char *fn)
return nullptr;
}
FWadLump wlump = Wads.OpenLumpNum(lump);
auto wlump = Wads.OpenLumpReader(lump);
uint32_t id[32 / 4];
if (wlump.Read(id, 32) != 32 || wlump.Seek(-32, SEEK_CUR) != 0)
if (wlump.Read(id, 32) != 32 || wlump.Seek(-32, FileRdr::SeekCur) != 0)
{
Printf("Unable to read lump %s\n", src.GetChars());
return nullptr;

View file

@ -83,7 +83,9 @@ OPLMIDIDevice::OPLMIDIDevice(const char *args)
{
OPL_SetCore(args);
FullPan = opl_fullpan;
FWadLump data = Wads.OpenLumpName("GENMIDI");
auto lump = Wads.CheckNumForName("GENMIDI", ns_global);
if (lump < 0) I_Error("No GENMIDI lump found");
auto data = Wads.OpenLumpReader(lump);
uint8_t filehdr[8];
data.Read(filehdr, 8);

View file

@ -76,7 +76,7 @@ public:
class MUSSong2 : public MIDISource
{
public:
MUSSong2(FileReader &reader);
MUSSong2(FileRdr &reader);
~MUSSong2();
protected:
@ -99,7 +99,7 @@ private:
class MIDISong2 : public MIDISource
{
public:
MIDISong2(FileReader &reader);
MIDISong2(FileRdr &reader);
~MIDISong2();
protected:
@ -153,7 +153,7 @@ protected:
class HMISong : public MIDISource
{
public:
HMISong(FileReader &reader);
HMISong(FileRdr &reader);
~HMISong();
protected:
@ -193,7 +193,7 @@ private:
class XMISong : public MIDISource
{
public:
XMISong(FileReader &reader);
XMISong(FileRdr &reader);
~XMISong();
protected:

View file

@ -126,9 +126,9 @@ struct HMISong::TrackInfo
//
//==========================================================================
HMISong::HMISong (FileReader &reader)
HMISong::HMISong (FileRdr &reader)
{
int len = reader.GetLength();
auto len = reader.GetLength();
if (len < 0x100)
{ // Way too small to be HMI.
return;

View file

@ -33,11 +33,6 @@
// HEADER FILES ------------------------------------------------------------
#if !defined(__FreeBSD__) && !defined(__APPLE__) && !defined(__OpenBSD__)
#include <malloc.h>
#else
#include <stdlib.h>
#endif
#include "i_musicinterns.h"
#include "templates.h"
#include "doomdef.h"
@ -93,7 +88,7 @@ static const uint8_t CtrlTranslate[15] =
//
//==========================================================================
MUSSong2::MUSSong2 (FileReader &reader)
MUSSong2::MUSSong2 (FileRdr &reader)
: MusHeader(0), MusBuffer(0)
{
uint8_t front[32];

View file

@ -99,13 +99,13 @@ struct MIDISong2::TrackInfo
//
//==========================================================================
MIDISong2::MIDISong2 (FileReader &reader)
MIDISong2::MIDISong2 (FileRdr &reader)
: MusHeader(0), Tracks(0)
{
int p;
int i;
SongLen = reader.GetLength();
SongLen = (int)reader.GetLength();
MusHeader = new uint8_t[SongLen];
if (reader.Read(MusHeader, SongLen) != SongLen)
return;

View file

@ -105,10 +105,10 @@ struct XMISong::TrackInfo
//
//==========================================================================
XMISong::XMISong (FileReader &reader)
XMISong::XMISong (FileRdr &reader)
: MusHeader(0), Songs(0)
{
SongLen = reader.GetLength();
SongLen = (int)reader.GetLength();
MusHeader = new uint8_t[SongLen];
if (reader.Read(MusHeader, SongLen) != SongLen)
return;

View file

@ -590,7 +590,7 @@ int LoadDMXGUS()
if (lump == -1) lump = Wads.CheckNumForName("DMXGUSC");
if (lump == -1) return LoadConfig(midi_config);
FWadLump data = Wads.OpenLumpNum(lump);
auto data = Wads.OpenLumpReader(lump);
if (data.GetLength() == 0) return LoadConfig(midi_config);
// Check if we got some GUS data before using it.
@ -613,7 +613,7 @@ int LoadDMXGUS()
gus_sfreader.reset(psreader);
char readbuffer[1024];
long size = data.GetLength();
auto size = data.GetLength();
long read = 0;
uint8_t remap[256];
@ -624,7 +624,7 @@ int LoadDMXGUS()
int status = -1;
int gusbank = (gus_memsize >= 1 && gus_memsize <= 4) ? gus_memsize : -1;
data.Seek(0, SEEK_SET);
data.Seek(0, FileRdr::SeekSet);
while (data.Gets(readbuffer, 1024) && read < size)
{

View file

@ -1352,6 +1352,34 @@ FWadLump *FWadCollection::ReopenLumpNumNewFile (int lump)
return new FWadLump(lump, LumpInfo[lump].lump);
}
//==========================================================================
//
// OpenLumpReader
//
// uses a more abstract interface to allow for easier low level optimization later
//
//==========================================================================
FileRdr FWadCollection::OpenLumpReader(int lump)
{
FileRdr rdr;
if ((unsigned)lump >= (unsigned)LumpInfo.Size())
{
I_Error("W_OpenLumpNum: %u >= NumLumps", lump);
}
rdr.mReader = new FWadLump(LumpInfo[lump].lump);
return rdr;
}
FileRdr FWadCollection::ReopenLumpReader(int lump, bool alwayscache)
{
FileRdr rdr;
rdr.mReader = alwayscache ? ReopenLumpNumNewFile(lump) : ReopenLumpNum(lump);
return rdr;
}
//==========================================================================
//

View file

@ -177,13 +177,13 @@ public:
FMemLump ReadLump (int lump);
FMemLump ReadLump (const char *name) { return ReadLump (GetNumForName (name)); }
FileRdr OpenLumpReader(int lump); // opens a reader that redirects to the containing file's one.
FileRdr ReopenLumpReader(int lump, bool alwayscache = false); // opens an independent reader.
FWadLump OpenLumpNum (int lump);
FWadLump OpenLumpName (const char *name) { return OpenLumpNum (GetNumForName (name)); }
FWadLump *ReopenLumpNum (int lump); // Opens a new, independent FILE
FWadLump *ReopenLumpNumNewFile (int lump); // Opens a new, independent FILE
FileReader * GetFileReader(int wadnum); // Gets a FileReader object to the entire WAD
int FindLump (const char *name, int *lastlump, bool anyns=false); // [RH] Find lumps with duplication
int FindLumpMulti (const char **names, int *lastlump, bool anyns = false, int *nameindex = NULL); // same with multiple possible names
bool CheckLumpName (int lump, const char *name); // [RH] True if lump's name == name
@ -237,6 +237,7 @@ private:
void RenameNerve();
void FixMacHexen();
void DeleteAll();
FileReader * GetFileReader(int wadnum); // Gets a FileReader object to the entire WAD
};
extern FWadCollection Wads;