From 26e948357eaf077818f7f9f3054739462a56c965 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 10 Mar 2018 13:46:35 +0100 Subject: [PATCH] - 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. --- src/files.cpp | 28 ++++ src/files.h | 157 ++++++++++++++++++ src/sound/i_music.cpp | 13 +- .../mididevices/music_opl_mididevice.cpp | 4 +- src/sound/midisources/midisource.h | 8 +- src/sound/midisources/midisource_hmi.cpp | 4 +- src/sound/midisources/midisource_mus.cpp | 7 +- src/sound/midisources/midisource_smf.cpp | 4 +- src/sound/midisources/midisource_xmi.cpp | 4 +- src/sound/timidity/timidity.cpp | 6 +- src/w_wad.cpp | 28 ++++ src/w_wad.h | 7 +- 12 files changed, 242 insertions(+), 28 deletions(-) diff --git a/src/files.cpp b/src/files.cpp index 1b0e5db1f..d429c2080 100644 --- a/src/files.cpp +++ b/src/files.cpp @@ -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; +} + diff --git a/src/files.h b/src/files.h index 808f24d94..5e4b91812 100644 --- a/src/files.h +++ b/src/files.h @@ -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 diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index cbea4ee2c..717bff8de 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -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; diff --git a/src/sound/mididevices/music_opl_mididevice.cpp b/src/sound/mididevices/music_opl_mididevice.cpp index a37358520..48aa8104f 100644 --- a/src/sound/mididevices/music_opl_mididevice.cpp +++ b/src/sound/mididevices/music_opl_mididevice.cpp @@ -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); diff --git a/src/sound/midisources/midisource.h b/src/sound/midisources/midisource.h index 7e7381eae..f7ce85e4c 100644 --- a/src/sound/midisources/midisource.h +++ b/src/sound/midisources/midisource.h @@ -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: diff --git a/src/sound/midisources/midisource_hmi.cpp b/src/sound/midisources/midisource_hmi.cpp index c2ce9b1fc..e0939de27 100644 --- a/src/sound/midisources/midisource_hmi.cpp +++ b/src/sound/midisources/midisource_hmi.cpp @@ -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; diff --git a/src/sound/midisources/midisource_mus.cpp b/src/sound/midisources/midisource_mus.cpp index feddfe67c..9b6fe06bc 100644 --- a/src/sound/midisources/midisource_mus.cpp +++ b/src/sound/midisources/midisource_mus.cpp @@ -33,11 +33,6 @@ // HEADER FILES ------------------------------------------------------------ -#if !defined(__FreeBSD__) && !defined(__APPLE__) && !defined(__OpenBSD__) -#include -#else -#include -#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]; diff --git a/src/sound/midisources/midisource_smf.cpp b/src/sound/midisources/midisource_smf.cpp index 6385bf997..15c5fbabe 100644 --- a/src/sound/midisources/midisource_smf.cpp +++ b/src/sound/midisources/midisource_smf.cpp @@ -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; diff --git a/src/sound/midisources/midisource_xmi.cpp b/src/sound/midisources/midisource_xmi.cpp index b59308176..50e6b06e3 100644 --- a/src/sound/midisources/midisource_xmi.cpp +++ b/src/sound/midisources/midisource_xmi.cpp @@ -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; diff --git a/src/sound/timidity/timidity.cpp b/src/sound/timidity/timidity.cpp index 455ed1713..4c9efe0ac 100644 --- a/src/sound/timidity/timidity.cpp +++ b/src/sound/timidity/timidity.cpp @@ -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) { diff --git a/src/w_wad.cpp b/src/w_wad.cpp index 21c35e669..30b9fdecc 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -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; +} //========================================================================== // diff --git a/src/w_wad.h b/src/w_wad.h index 11e4a954d..73f818564 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -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;