From a6307b768c1d1771c031cc8061a929b45a3d66ac Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Mon, 6 Jan 2020 13:31:58 +0100 Subject: COMMON: Fix reading beyond array pointers in toString() --- common/str.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'common') diff --git a/common/str.cpp b/common/str.cpp index 0082dc1bec..ad9e17806e 100644 --- a/common/str.cpp +++ b/common/str.cpp @@ -1097,7 +1097,7 @@ size_t strnlen(const char *src, size_t maxSize) { String toPrintable(const String &in, bool keepNewLines) { Common::String res; - const char *tr = "\x01\x02\x03\x04\x05\x06" "a" + const char *tr = "\x01\x01\x02\x03\x04\x05\x06" "a" //"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"; "b" "t" "n" "v" "f" "r\x0e\x0f" "\x10\x11\x12\x13\x14\x15\x16\x17" @@ -1117,10 +1117,10 @@ String toPrintable(const String &in, bool keepNewLines) { res += '\\'; if (*p < 0x20) { - if (tr[*p + 1] < 0x20) + if (tr[*p] < 0x20) res += Common::String::format("x%02x", *p); else - res += tr[*p + 1]; + res += tr[*p]; } else { res += *p; // We will escape it } -- cgit v1.2.3 From b8e94e1acd207771098bcb5c1a882b13740a850c Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Tue, 31 Dec 2019 19:02:48 +0000 Subject: COMMON: Rename PEResources::getNameList() to getIDList() --- common/winexe_pe.cpp | 34 +++++++++++++++++----------------- common/winexe_pe.h | 18 +++++++++--------- 2 files changed, 26 insertions(+), 26 deletions(-) (limited to 'common') diff --git a/common/winexe_pe.cpp b/common/winexe_pe.cpp index 042c347c47..a79b0c4d50 100644 --- a/common/winexe_pe.cpp +++ b/common/winexe_pe.cpp @@ -151,7 +151,7 @@ void PEResources::parseResourceLevel(Section §ion, uint32 offset, int level) if (level == 0) _curType = id; else if (level == 1) - _curName = id; + _curID = id; else if (level == 2) _curLang = id; @@ -166,9 +166,9 @@ void PEResources::parseResourceLevel(Section §ion, uint32 offset, int level) resource.size = _exe->readUint32LE(); debug(4, "Found resource '%s' '%s' '%s' at %d of size %d", _curType.toString().c_str(), - _curName.toString().c_str(), _curLang.toString().c_str(), resource.offset, resource.size); + _curID.toString().c_str(), _curLang.toString().c_str(), resource.offset, resource.size); - _resources[_curType][_curName][_curLang] = resource; + _resources[_curType][_curID][_curLang] = resource; } _exe->seek(lastOffset); @@ -187,32 +187,32 @@ const Array PEResources::getTypeList() const { return array; } -const Array PEResources::getNameList(const WinResourceID &type) const { +const Array PEResources::getIDList(const WinResourceID &type) const { Array array; if (!_exe || !_resources.contains(type)) return array; - const NameMap &nameMap = _resources[type]; + const IDMap &idMap = _resources[type]; - for (NameMap::const_iterator it = nameMap.begin(); it != nameMap.end(); it++) + for (IDMap::const_iterator it = idMap.begin(); it != idMap.end(); it++) array.push_back(it->_key); return array; } -const Array PEResources::getLangList(const WinResourceID &type, const WinResourceID &name) const { +const Array PEResources::getLangList(const WinResourceID &type, const WinResourceID &id) const { Array array; if (!_exe || !_resources.contains(type)) return array; - const NameMap &nameMap = _resources[type]; + const IDMap &idMap = _resources[type]; - if (!nameMap.contains(name)) + if (!idMap.contains(id)) return array; - const LangMap &langMap = nameMap[name]; + const LangMap &langMap = idMap[id]; for (LangMap::const_iterator it = langMap.begin(); it != langMap.end(); it++) array.push_back(it->_key); @@ -220,27 +220,27 @@ const Array PEResources::getLangList(const WinResourceID &type, c return array; } -SeekableReadStream *PEResources::getResource(const WinResourceID &type, const WinResourceID &name) { - Array langList = getLangList(type, name); +SeekableReadStream *PEResources::getResource(const WinResourceID &type, const WinResourceID &id) { + Array langList = getLangList(type, id); if (langList.empty()) return nullptr; - const Resource &resource = _resources[type][name][langList[0]]; + const Resource &resource = _resources[type][id][langList[0]]; _exe->seek(resource.offset); return _exe->readStream(resource.size); } -SeekableReadStream *PEResources::getResource(const WinResourceID &type, const WinResourceID &name, const WinResourceID &lang) { +SeekableReadStream *PEResources::getResource(const WinResourceID &type, const WinResourceID &id, const WinResourceID &lang) { if (!_exe || !_resources.contains(type)) return nullptr; - const NameMap &nameMap = _resources[type]; + const IDMap &idMap = _resources[type]; - if (!nameMap.contains(name)) + if (!idMap.contains(id)) return nullptr; - const LangMap &langMap = nameMap[name]; + const LangMap &langMap = idMap[id]; if (!langMap.contains(lang)) return nullptr; diff --git a/common/winexe_pe.h b/common/winexe_pe.h index 6f92cde6dc..875ec898ad 100644 --- a/common/winexe_pe.h +++ b/common/winexe_pe.h @@ -54,17 +54,17 @@ public: /** Return a list of resource types. */ const Array getTypeList() const; - /** Return a list of names for a given type. */ - const Array getNameList(const WinResourceID &type) const; + /** Return a list of IDs for a given type. */ + const Array getIDList(const WinResourceID &type) const; - /** Return a list of languages for a given type and name. */ - const Array getLangList(const WinResourceID &type, const WinResourceID &name) const; + /** Return a list of languages for a given type and ID. */ + const Array getLangList(const WinResourceID &type, const WinResourceID &id) const; /** Return a stream to the specified resource, taking the first language found (or 0 if non-existent). */ - SeekableReadStream *getResource(const WinResourceID &type, const WinResourceID &name); + SeekableReadStream *getResource(const WinResourceID &type, const WinResourceID &id); /** Return a stream to the specified resource (or 0 if non-existent). */ - SeekableReadStream *getResource(const WinResourceID &type, const WinResourceID &name, const WinResourceID &lang); + SeekableReadStream *getResource(const WinResourceID &type, const WinResourceID &id, const WinResourceID &lang); private: struct Section { @@ -78,7 +78,7 @@ private: SeekableReadStream *_exe; void parseResourceLevel(Section §ion, uint32 offset, int level); - WinResourceID _curType, _curName, _curLang; + WinResourceID _curType, _curID, _curLang; struct Resource { uint32 offset; @@ -86,8 +86,8 @@ private: }; typedef HashMap LangMap; - typedef HashMap NameMap; - typedef HashMap TypeMap; + typedef HashMap IDMap; + typedef HashMap TypeMap; TypeMap _resources; }; -- cgit v1.2.3 From aa9a41545ad331acb37dde0790adfa8298b1f8b5 Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Thu, 2 Jan 2020 21:23:35 +0000 Subject: COMMON: Add a common base class for the Windows resource classes --- common/winexe.cpp | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++ common/winexe.h | 40 +++++++++++++++++++++++++ common/winexe_ne.cpp | 82 ---------------------------------------------------- common/winexe_ne.h | 7 ++--- common/winexe_pe.cpp | 15 ---------- common/winexe_pe.h | 4 +-- 6 files changed, 126 insertions(+), 104 deletions(-) (limited to 'common') diff --git a/common/winexe.cpp b/common/winexe.cpp index fc389f6ea6..fd1d565036 100644 --- a/common/winexe.cpp +++ b/common/winexe.cpp @@ -20,6 +20,8 @@ * */ +#include "common/file.h" +#include "common/memstream.h" #include "common/str.h" #include "common/winexe.h" @@ -78,4 +80,84 @@ String WinResourceID::toString() const { return ""; } +bool WinResources::loadFromEXE(const String &fileName) { + if (fileName.empty()) + return false; + + File *file = new File(); + + if (!file->open(fileName)) { + delete file; + return false; + } + + return loadFromEXE(file); +} + +bool WinResources::loadFromCompressedEXE(const String &fileName) { + // Based on http://www.cabextract.org.uk/libmspack/doc/szdd_kwaj_format.html + + // TODO: Merge this with with loadFromEXE() so the handling of the compressed + // EXE's is transparent + + File file; + + if (!file.open(fileName)) + return false; + + // First part of the signature + if (file.readUint32BE() != MKTAG('S','Z','D','D')) + return false; + + // Second part of the signature + if (file.readUint32BE() != 0x88F02733) + return false; + + // Compression mode must be 'A' + if (file.readByte() != 'A') + return false; + + file.readByte(); // file name character change + uint32 unpackedLength = file.readUint32LE(); + + byte *window = new byte[0x1000]; + int pos = 0x1000 - 16; + memset(window, 0x20, 0x1000); // Initialize to all spaces + + byte *unpackedData = (byte *)malloc(unpackedLength); + assert(unpackedData); + byte *dataPos = unpackedData; + + // Apply simple LZSS decompression + for (;;) { + byte controlByte = file.readByte(); + + if (file.eos()) + break; + + for (byte i = 0; i < 8; i++) { + if (controlByte & (1 << i)) { + *dataPos++ = window[pos++] = file.readByte(); + pos &= 0xFFF; + } else { + int matchPos = file.readByte(); + int matchLen = file.readByte(); + matchPos |= (matchLen & 0xF0) << 4; + matchLen = (matchLen & 0xF) + 3; + while (matchLen--) { + *dataPos++ = window[pos++] = window[matchPos++]; + pos &= 0xFFF; + matchPos &= 0xFFF; + } + } + + } + } + + delete[] window; + SeekableReadStream *stream = new MemoryReadStream(unpackedData, unpackedLength); + + return loadFromEXE(stream); +} + } // End of namespace Common diff --git a/common/winexe.h b/common/winexe.h index 9aeea379ed..cdbc0f6d13 100644 --- a/common/winexe.h +++ b/common/winexe.h @@ -28,6 +28,8 @@ namespace Common { +class SeekableReadStream; + /** The default Windows resources. */ enum WinResourceType { kWinCursor = 0x01, @@ -90,6 +92,44 @@ struct WinResourceID_EqualTo { bool operator()(const WinResourceID &id1, const WinResourceID &id2) const { return id1 == id2; } }; +/** + * A class able to load resources from a Windows Executable, such + * as cursors, bitmaps, and sounds. + */ +class WinResources { +public: + virtual ~WinResources() {}; + + /** Clear all information. */ + virtual void clear() = 0; + + /** Load from an EXE file. */ + virtual bool loadFromEXE(const String &fileName); + + /** Load from a Windows compressed EXE file. */ + virtual bool loadFromCompressedEXE(const String &fileName); + + /** Load from a stream. */ + virtual bool loadFromEXE(SeekableReadStream *stream) = 0; + + /** Return a list of IDs for a given type. */ + virtual const Array getIDList(const WinResourceID &type) const = 0; + + /** Return a list of languages for a given type and ID. */ + virtual const Array getLangList(const WinResourceID &type, const WinResourceID &id) const { + Array array; + return array; + } + + /** Return a stream to the specified resource, taking the first language found (or 0 if non-existent). */ + virtual SeekableReadStream *getResource(const WinResourceID &type, const WinResourceID &id) = 0; + + /** Return a stream to the specified resource (or 0 if non-existent). */ + virtual SeekableReadStream *getResource(const WinResourceID &type, const WinResourceID &id, const WinResourceID &lang) { + return getResource(type, id); + } +}; + } // End of namespace Common #endif diff --git a/common/winexe_ne.cpp b/common/winexe_ne.cpp index 2d46cb2554..66b5e0911a 100644 --- a/common/winexe_ne.cpp +++ b/common/winexe_ne.cpp @@ -21,8 +21,6 @@ */ #include "common/debug.h" -#include "common/file.h" -#include "common/memstream.h" #include "common/str.h" #include "common/stream.h" #include "common/winexe_ne.h" @@ -46,20 +44,6 @@ void NEResources::clear() { _resources.clear(); } -bool NEResources::loadFromEXE(const String &fileName) { - if (fileName.empty()) - return false; - - File *file = new File(); - - if (!file->open(fileName)) { - delete file; - return false; - } - - return loadFromEXE(file); -} - bool NEResources::loadFromEXE(SeekableReadStream *stream) { clear(); @@ -80,72 +64,6 @@ bool NEResources::loadFromEXE(SeekableReadStream *stream) { return true; } -bool NEResources::loadFromCompressedEXE(const String &fileName) { - // Based on http://www.cabextract.org.uk/libmspack/doc/szdd_kwaj_format.html - - // TODO: Merge this with with loadFromEXE() so the handling of the compressed - // EXE's is transparent - - File file; - - if (!file.open(fileName)) - return false; - - // First part of the signature - if (file.readUint32BE() != MKTAG('S','Z','D','D')) - return false; - - // Second part of the signature - if (file.readUint32BE() != 0x88F02733) - return false; - - // Compression mode must be 'A' - if (file.readByte() != 'A') - return false; - - file.readByte(); // file name character change - uint32 unpackedLength = file.readUint32LE(); - - byte *window = new byte[0x1000]; - int pos = 0x1000 - 16; - memset(window, 0x20, 0x1000); // Initialize to all spaces - - byte *unpackedData = (byte *)malloc(unpackedLength); - assert(unpackedData); - byte *dataPos = unpackedData; - - // Apply simple LZSS decompression - for (;;) { - byte controlByte = file.readByte(); - - if (file.eos()) - break; - - for (byte i = 0; i < 8; i++) { - if (controlByte & (1 << i)) { - *dataPos++ = window[pos++] = file.readByte(); - pos &= 0xFFF; - } else { - int matchPos = file.readByte(); - int matchLen = file.readByte(); - matchPos |= (matchLen & 0xF0) << 4; - matchLen = (matchLen & 0xF) + 3; - while (matchLen--) { - *dataPos++ = window[pos++] = window[matchPos++]; - pos &= 0xFFF; - matchPos &= 0xFFF; - } - } - - } - } - - delete[] window; - SeekableReadStream *stream = new MemoryReadStream(unpackedData, unpackedLength); - - return loadFromEXE(stream); -} - uint32 NEResources::getResourceTableOffset() { if (!_exe) return 0xFFFFFFFF; diff --git a/common/winexe_ne.h b/common/winexe_ne.h index 1a845864b2..118629abe1 100644 --- a/common/winexe_ne.h +++ b/common/winexe_ne.h @@ -38,7 +38,7 @@ class SeekableReadStream; * * See http://en.wikipedia.org/wiki/New_Executable for more info. */ -class NEResources { +class NEResources : public WinResources { public: NEResources(); ~NEResources(); @@ -47,10 +47,7 @@ public: void clear(); /** Load from an EXE file. */ - bool loadFromEXE(const String &fileName); - - /** Load from a Windows compressed EXE file. */ - bool loadFromCompressedEXE(const String &fileName); + using WinResources::loadFromEXE; /** Load from a stream. */ bool loadFromEXE(SeekableReadStream *stream); diff --git a/common/winexe_pe.cpp b/common/winexe_pe.cpp index a79b0c4d50..5e962dd139 100644 --- a/common/winexe_pe.cpp +++ b/common/winexe_pe.cpp @@ -23,7 +23,6 @@ #include "common/array.h" #include "common/debug.h" #include "common/endian.h" -#include "common/file.h" #include "common/str.h" #include "common/stream.h" #include "common/winexe_pe.h" @@ -44,20 +43,6 @@ void PEResources::clear() { delete _exe; _exe = nullptr; } -bool PEResources::loadFromEXE(const String &fileName) { - if (fileName.empty()) - return false; - - File *file = new File(); - - if (!file->open(fileName)) { - delete file; - return false; - } - - return loadFromEXE(file); -} - bool PEResources::loadFromEXE(SeekableReadStream *stream) { clear(); diff --git a/common/winexe_pe.h b/common/winexe_pe.h index 875ec898ad..79b913043a 100644 --- a/common/winexe_pe.h +++ b/common/winexe_pe.h @@ -37,7 +37,7 @@ class SeekableReadStream; * A class able to load resources from a Windows Portable Executable, such * as cursors, bitmaps, and sounds. */ -class PEResources { +class PEResources : public WinResources { public: PEResources(); ~PEResources(); @@ -46,7 +46,7 @@ public: void clear(); /** Load from an EXE file. */ - bool loadFromEXE(const String &fileName); + using WinResources::loadFromEXE; /** Load from a stream. */ bool loadFromEXE(SeekableReadStream *stream); -- cgit v1.2.3 From a692905eb273ae8c33ba1351e519b93dbf10f7fd Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Sat, 4 Jan 2020 15:00:40 +0000 Subject: COMMON: Add a function to simplify loading Windows executables --- common/winexe.cpp | 23 +++++++++++++++++++++++ common/winexe.h | 2 ++ 2 files changed, 25 insertions(+) (limited to 'common') diff --git a/common/winexe.cpp b/common/winexe.cpp index fd1d565036..ad6ff96505 100644 --- a/common/winexe.cpp +++ b/common/winexe.cpp @@ -24,6 +24,8 @@ #include "common/memstream.h" #include "common/str.h" #include "common/winexe.h" +#include "common/winexe_ne.h" +#include "common/winexe_pe.h" namespace Common { @@ -160,4 +162,25 @@ bool WinResources::loadFromCompressedEXE(const String &fileName) { return loadFromEXE(stream); } + +WinResources *WinResources::createFromEXE(const String &fileName) { + WinResources *exe; + + // First try loading via the NE code + exe = new Common::NEResources(); + if (exe->loadFromEXE(fileName)) { + return exe; + } + delete exe; + + // Then try loading via the PE code + exe = new Common::PEResources(); + if (exe->loadFromEXE(fileName)) { + return exe; + } + delete exe; + + return nullptr; +} + } // End of namespace Common diff --git a/common/winexe.h b/common/winexe.h index cdbc0f6d13..2b81a33261 100644 --- a/common/winexe.h +++ b/common/winexe.h @@ -128,6 +128,8 @@ public: virtual SeekableReadStream *getResource(const WinResourceID &type, const WinResourceID &id, const WinResourceID &lang) { return getResource(type, id); } + + static WinResources *createFromEXE(const String &fileName); }; } // End of namespace Common -- cgit v1.2.3