- 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; 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; 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 // Wraps around a FileReader to decompress a zlib stream
class FileReaderZ : public FileReaderBase 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 #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; MIDISource *source = nullptr;
switch (miditype) switch (miditype)
@ -452,11 +452,14 @@ MusInfo *I_RegisterSong (FileReader *reader, MidiDeviceSetting *device)
EMIDIType miditype = IdentifyMIDIType(id, sizeof(id)); EMIDIType miditype = IdentifyMIDIType(id, sizeof(id));
if (miditype != MIDI_NOTMIDI) 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 == nullptr) return 0;
if (!source->isValid()) if (!source->isValid())
{ {
delete reader;
delete source; delete source;
return 0; return 0;
} }
@ -719,10 +722,10 @@ static MIDISource *GetMIDISource(const char *fn)
return nullptr; return nullptr;
} }
FWadLump wlump = Wads.OpenLumpNum(lump); auto wlump = Wads.OpenLumpReader(lump);
uint32_t id[32 / 4]; 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()); Printf("Unable to read lump %s\n", src.GetChars());
return nullptr; return nullptr;

View file

@ -83,7 +83,9 @@ OPLMIDIDevice::OPLMIDIDevice(const char *args)
{ {
OPL_SetCore(args); OPL_SetCore(args);
FullPan = opl_fullpan; 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]; uint8_t filehdr[8];
data.Read(filehdr, 8); data.Read(filehdr, 8);

View file

@ -76,7 +76,7 @@ public:
class MUSSong2 : public MIDISource class MUSSong2 : public MIDISource
{ {
public: public:
MUSSong2(FileReader &reader); MUSSong2(FileRdr &reader);
~MUSSong2(); ~MUSSong2();
protected: protected:
@ -99,7 +99,7 @@ private:
class MIDISong2 : public MIDISource class MIDISong2 : public MIDISource
{ {
public: public:
MIDISong2(FileReader &reader); MIDISong2(FileRdr &reader);
~MIDISong2(); ~MIDISong2();
protected: protected:
@ -153,7 +153,7 @@ protected:
class HMISong : public MIDISource class HMISong : public MIDISource
{ {
public: public:
HMISong(FileReader &reader); HMISong(FileRdr &reader);
~HMISong(); ~HMISong();
protected: protected:
@ -193,7 +193,7 @@ private:
class XMISong : public MIDISource class XMISong : public MIDISource
{ {
public: public:
XMISong(FileReader &reader); XMISong(FileRdr &reader);
~XMISong(); ~XMISong();
protected: 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) if (len < 0x100)
{ // Way too small to be HMI. { // Way too small to be HMI.
return; return;

View file

@ -33,11 +33,6 @@
// HEADER FILES ------------------------------------------------------------ // HEADER FILES ------------------------------------------------------------
#if !defined(__FreeBSD__) && !defined(__APPLE__) && !defined(__OpenBSD__)
#include <malloc.h>
#else
#include <stdlib.h>
#endif
#include "i_musicinterns.h" #include "i_musicinterns.h"
#include "templates.h" #include "templates.h"
#include "doomdef.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) : MusHeader(0), MusBuffer(0)
{ {
uint8_t front[32]; 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) : MusHeader(0), Tracks(0)
{ {
int p; int p;
int i; int i;
SongLen = reader.GetLength(); SongLen = (int)reader.GetLength();
MusHeader = new uint8_t[SongLen]; MusHeader = new uint8_t[SongLen];
if (reader.Read(MusHeader, SongLen) != SongLen) if (reader.Read(MusHeader, SongLen) != SongLen)
return; return;

View file

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

View file

@ -590,7 +590,7 @@ int LoadDMXGUS()
if (lump == -1) lump = Wads.CheckNumForName("DMXGUSC"); if (lump == -1) lump = Wads.CheckNumForName("DMXGUSC");
if (lump == -1) return LoadConfig(midi_config); 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); if (data.GetLength() == 0) return LoadConfig(midi_config);
// Check if we got some GUS data before using it. // Check if we got some GUS data before using it.
@ -613,7 +613,7 @@ int LoadDMXGUS()
gus_sfreader.reset(psreader); gus_sfreader.reset(psreader);
char readbuffer[1024]; char readbuffer[1024];
long size = data.GetLength(); auto size = data.GetLength();
long read = 0; long read = 0;
uint8_t remap[256]; uint8_t remap[256];
@ -624,7 +624,7 @@ int LoadDMXGUS()
int status = -1; int status = -1;
int gusbank = (gus_memsize >= 1 && gus_memsize <= 4) ? gus_memsize : -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) 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); 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 (int lump);
FMemLump ReadLump (const char *name) { return ReadLump (GetNumForName (name)); } 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 OpenLumpNum (int lump);
FWadLump OpenLumpName (const char *name) { return OpenLumpNum (GetNumForName (name)); }
FWadLump *ReopenLumpNum (int lump); // Opens a new, independent FILE FWadLump *ReopenLumpNum (int lump); // Opens a new, independent FILE
FWadLump *ReopenLumpNumNewFile (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 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 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 bool CheckLumpName (int lump, const char *name); // [RH] True if lump's name == name
@ -237,6 +237,7 @@ private:
void RenameNerve(); void RenameNerve();
void FixMacHexen(); void FixMacHexen();
void DeleteAll(); void DeleteAll();
FileReader * GetFileReader(int wadnum); // Gets a FileReader object to the entire WAD
}; };
extern FWadCollection Wads; extern FWadCollection Wads;