diff --git a/common/archive.cpp b/common/archive.cpp index 2df42fdd312..ca42afd3a0e 100644 --- a/common/archive.cpp +++ b/common/archive.cpp @@ -239,7 +239,7 @@ SeekableReadStream *MemcachingCaseInsensitiveArchive::createReadStreamForMemberI return memStream; } -SharedArchiveContents MemcachingCaseInsensitiveArchive::readContentsForPathAltStream(const String &translatedPath, AltStreamType altStreamType) const { +SharedArchiveContents MemcachingCaseInsensitiveArchive::readContentsForPathAltStream(const Path &translatedPath, AltStreamType altStreamType) const { return SharedArchiveContents(); } @@ -251,7 +251,7 @@ bool MemcachingCaseInsensitiveArchive::CacheKey_EqualTo::operator()(const CacheK } uint MemcachingCaseInsensitiveArchive::CacheKey_Hash::operator()(const CacheKey &x) const { - return static_cast(hashit_lower(x.path) * 1000003u) ^ static_cast(x.altStreamType); + return static_cast(x.path.hashIgnoreCase() * 1000003u) ^ static_cast(x.altStreamType); }; SearchSet::ArchiveNodeList::iterator SearchSet::find(const String &name) { diff --git a/common/archive.h b/common/archive.h index fb066b8ff14..f46686e545b 100644 --- a/common/archive.h +++ b/common/archive.h @@ -272,20 +272,18 @@ public: SeekableReadStream *createReadStreamForMember(const Path &path) const; SeekableReadStream *createReadStreamForMemberAltStream(const Path &path, Common::AltStreamType altStreamType) const; - virtual String translatePath(const Path &path) const { - // Most of users of this class implement DOS-like archives. - // Others override this method. - return normalizePath(path.toString('\\'), '\\'); + virtual Path translatePath(const Path &path) const { + return path.normalize(); } - virtual SharedArchiveContents readContentsForPath(const String &translatedPath) const = 0; - virtual SharedArchiveContents readContentsForPathAltStream(const String &translatedPath, AltStreamType altStreamType) const; + virtual SharedArchiveContents readContentsForPath(const Path &translatedPath) const = 0; + virtual SharedArchiveContents readContentsForPathAltStream(const Path &translatedPath, AltStreamType altStreamType) const; private: struct CacheKey { CacheKey(); - String path; + Path path; AltStreamType altStreamType; }; diff --git a/common/compression/clickteam.cpp b/common/compression/clickteam.cpp index 8a525ebd430..451bcf2ed47 100644 --- a/common/compression/clickteam.cpp +++ b/common/compression/clickteam.cpp @@ -61,7 +61,7 @@ ClickteamInstaller::ClickteamFileDescriptor::ClickteamFileDescriptor(const Click char *strings = (char *)tag + stringsOffset; char *p; for (p = strings; p < (char*)tag + lmax && *p; p++); - _fileName = Common::String(strings, p - strings); + _fileName = Common::Path(Common::String(strings, p - strings), Common::Path::kNoSeparator); _fileDescriptorOffset = off; _supported = true; _isPatchFile = false; @@ -81,7 +81,7 @@ ClickteamInstaller::ClickteamFileDescriptor::ClickteamFileDescriptor(const Click byte type = tag[7]; if (type != 0) { _supported = false; - _fileName = ""; + _fileName.clear(); _fileDataOffset = 0; _fileDescriptorOffset = off; _compressedSize = 0; @@ -119,7 +119,7 @@ ClickteamInstaller::ClickteamFileDescriptor::ClickteamFileDescriptor(const Click char *strings = (char *)tag + stringsOffset; char *p; for (p = strings; p < (char*)tag + lmax && *p; p++); - _fileName = Common::String(strings, p - strings); + _fileName = Common::Path(Common::String(strings, p - strings), Common::Path::kNoSeparator); _fileDescriptorOffset = off; _compressedSize = 0; _fileDataOffset = 0; @@ -305,7 +305,7 @@ struct TagHead { }; int ClickteamInstaller::findPatchIdx(const ClickteamFileDescriptor &desc, Common::SeekableReadStream *refStream, - const Common::String &fileName, + const Common::Path &fileName, uint32 crcXor, bool doWarn) { bool hasMatching = refStream->size() == desc._uncompressedSize; // Maybe already patched? for (uint i = 0; !hasMatching && i < desc._patchEntries.size(); i++) @@ -315,7 +315,7 @@ int ClickteamInstaller::findPatchIdx(const ClickteamFileDescriptor &desc, Common } if (!hasMatching) { if (doWarn) - warning("Couldn't find matching patch entry for file %s size %d", fileName.c_str(), (int)refStream->size()); + warning("Couldn't find matching patch entry for file %s size %d", fileName.toString().c_str(), (int)refStream->size()); return -1; } uint32 crcOriginal = 0; @@ -336,7 +336,7 @@ int ClickteamInstaller::findPatchIdx(const ClickteamFileDescriptor &desc, Common if (patchDescIdx == -1 && refStream->size() == desc._uncompressedSize && crcOriginal == desc._expectedCRC) return -2; if (patchDescIdx < 0 && doWarn) { - warning("Couldn't find matching patch entry for file %s size %d and CRC 0x%x", fileName.c_str(), (int)refStream->size(), crcOriginal); + warning("Couldn't find matching patch entry for file %s size %d and CRC 0x%x", fileName.toString().c_str(), (int)refStream->size(), crcOriginal); } return patchDescIdx; } @@ -348,7 +348,7 @@ ClickteamInstaller* ClickteamInstaller::open(Common::SeekableReadStream *stream, ClickteamInstaller* ClickteamInstaller::openPatch(Common::SeekableReadStream *stream, bool verifyOriginal, bool verifyAllowSkip, Common::Archive *reference, DisposeAfterUse::Flag dispose) { - Common::HashMap files; + Common::HashMap files; HashMap> tags; uint32 crc_xor; @@ -435,10 +435,10 @@ ClickteamInstaller* ClickteamInstaller::openPatch(Common::SeekableReadStream *st return nullptr; if (verifyOriginal && reference) { - for (Common::HashMap::iterator i = files.begin(), end = files.end(); + for (Common::HashMap::iterator i = files.begin(), end = files.end(); i != end; ++i) { if (i->_value._isPatchFile) { - Common::ScopedPtr refStream(reference->createReadStreamForMember(Common::Path(i->_key, '\\'))); + Common::ScopedPtr refStream(reference->createReadStreamForMember(i->_key)); if (!refStream) { if (verifyAllowSkip) { i->_value._isReferenceMissing = true; @@ -453,7 +453,7 @@ ClickteamInstaller* ClickteamInstaller::openPatch(Common::SeekableReadStream *st } if (!reference) { - for (Common::HashMap::iterator i = files.begin(), end = files.end(); + for (Common::HashMap::iterator i = files.begin(), end = files.end(); i != end; ++i) { if (i->_value._isPatchFile) { i->_value._isReferenceMissing = true; @@ -471,7 +471,7 @@ bool ClickteamInstaller::hasFile(const Path &path) const { int ClickteamInstaller::listMembers(ArchiveMemberList &list) const { int members = 0; - for (Common::HashMap::const_iterator i = _files.begin(), end = _files.end(); + for (Common::HashMap::const_iterator i = _files.begin(), end = _files.end(); i != end; ++i) { if (!i->_value._isReferenceMissing) { list.push_back(ArchiveMemberList::value_type(new GenericArchiveMember(i->_key, *this))); @@ -483,7 +483,7 @@ int ClickteamInstaller::listMembers(ArchiveMemberList &list) const { } const ArchiveMemberPtr ClickteamInstaller::getMember(const Path &path) const { - Common::String translated = translatePath(path); + Common::Path translated = translatePath(path); ClickteamFileDescriptor el; if (!_files.tryGetVal(translated, el)) return nullptr; @@ -494,7 +494,7 @@ const ArchiveMemberPtr ClickteamInstaller::getMember(const Path &path) const { return Common::SharedPtr(new GenericArchiveMember(el._fileName, *this)); } -Common::SharedArchiveContents ClickteamInstaller::readContentsForPath(const Common::String& translated) const { +Common::SharedArchiveContents ClickteamInstaller::readContentsForPath(const Common::Path &translated) const { ClickteamFileDescriptor desc; byte *uncompressedBuffer = nullptr; @@ -504,9 +504,9 @@ Common::SharedArchiveContents ClickteamInstaller::readContentsForPath(const Comm return Common::SharedArchiveContents(); if (desc._isPatchFile) { - Common::ScopedPtr refStream(_reference->createReadStreamForMemberNext(Common::Path(translated, '\\'), this)); + Common::ScopedPtr refStream(_reference->createReadStreamForMemberNext(translated, this)); if (!refStream) { - warning("Couldn't open reference file for %s. Skipping", translated.c_str()); + warning("Couldn't open reference file for %s. Skipping", translated.toString('\\').c_str()); return Common::SharedArchiveContents(); } int patchDescIdx = findPatchIdx(desc, refStream.get(), translated, _crcXor, true); @@ -608,7 +608,7 @@ Common::SharedArchiveContents ClickteamInstaller::readContentsForPath(const Comm uint32 actualCrc = computeCRC(uncompressedBuffer, desc._uncompressedSize, 0); if (actualCrc != expectedCrc) { - warning("CRC mismatch for %s: expected=%08x (obfuscated %08x), actual=%08x (back %08x)", desc._fileName.c_str(), expectedCrc, desc._expectedCRC, actualCrc, actualCrc ^ _crcXor); + warning("CRC mismatch for %s: expected=%08x (obfuscated %08x), actual=%08x (back %08x)", desc._fileName.toString().c_str(), expectedCrc, desc._expectedCRC, actualCrc, actualCrc ^ _crcXor); delete[] uncompressedBuffer; return Common::SharedArchiveContents(); } diff --git a/common/compression/clickteam.h b/common/compression/clickteam.h index 20f6979fdf4..57e983369e1 100644 --- a/common/compression/clickteam.h +++ b/common/compression/clickteam.h @@ -57,7 +57,7 @@ public: bool hasFile(const Common::Path &path) const override; int listMembers(Common::ArchiveMemberList&) const override; const ArchiveMemberPtr getMember(const Common::Path &path) const override; - Common::SharedArchiveContents readContentsForPath(const Common::String& translated) const override; + Common::SharedArchiveContents readContentsForPath(const Common::Path &translated) const override; ClickteamTag* getTag(ClickteamTagId tagId) const; @@ -74,7 +74,7 @@ private: }; class ClickteamFileDescriptor { private: - Common::String _fileName; + Common::Path _fileName; // Offset of the file contents relative to the beginning of block3 uint32 _fileDataOffset; @@ -97,8 +97,8 @@ private: ClickteamFileDescriptor() : _fileDataOffset(0), _fileDescriptorOffset(0), _compressedSize(0), _uncompressedSize(0) {} }; - ClickteamInstaller(Common::HashMap files, - Common::HashMap> tags, + ClickteamInstaller(const Common::HashMap &files, + const Common::HashMap> &tags, uint32 crcXor, uint32 block3Offset, uint32 block3Size, Common::SeekableReadStream *stream, Common::Archive *reference, DisposeAfterUse::Flag dispose) @@ -106,9 +106,9 @@ private: _reference(reference) { } - static int findPatchIdx(const ClickteamFileDescriptor &desc, Common::SeekableReadStream *refStream, const Common::String &fileName, + static int findPatchIdx(const ClickteamFileDescriptor &desc, Common::SeekableReadStream *refStream, const Common::Path &fileName, uint32 crcXor, bool doWarn); - Common::HashMap _files; + Common::HashMap _files; Common::HashMap> _tags; Common::DisposablePtr _stream; uint32 _crcXor, _block3Offset/*, _block3Size*/; diff --git a/common/compression/gentee_installer.cpp b/common/compression/gentee_installer.cpp index 620482e2ab7..a8cf832a5e3 100644 --- a/common/compression/gentee_installer.cpp +++ b/common/compression/gentee_installer.cpp @@ -581,29 +581,26 @@ bool DecompressingStream::rewind() { class ArchiveItem : public Common::ArchiveMember { public: - ArchiveItem(Common::SeekableReadStream *stream, Common::Mutex *guardMutex, const Common::String &path, const Common::String &name, int64 filePos, uint compressedSize, uint decompressedSize, bool isCompressed); + ArchiveItem(Common::SeekableReadStream *stream, Common::Mutex *guardMutex, const Common::Path &path, int64 filePos, uint compressedSize, uint decompressedSize, bool isCompressed); Common::SeekableReadStream *createReadStream() const override; Common::SeekableReadStream *createReadStreamForAltStream(Common::AltStreamType altStreamType) const override; - Common::String getName() const override; - Common::Path getPathInArchive() const override { return getName(); } - Common::String getFileName() const override { return getName(); } - - const Common::String &getPath() const; + Common::String getName() const override { return getFileName(); } + Common::Path getPathInArchive() const override { return _path; } + Common::String getFileName() const override { return _path.getLastComponent().toString(); } private: Common::SeekableReadStream *_stream; Common::Mutex *_guardMutex; - Common::String _path; - Common::String _name; + Common::Path _path; int64 _filePos; uint _compressedSize; uint _decompressedSize; bool _isCompressed; }; -ArchiveItem::ArchiveItem(Common::SeekableReadStream *stream, Common::Mutex *guardMutex, const Common::String &path, const Common::String &name, int64 filePos, uint compressedSize, uint decompressedSize, bool isCompressed) - : _stream(stream), _guardMutex(guardMutex), _path(path), _name(name), _filePos(filePos), _compressedSize(compressedSize), _decompressedSize(decompressedSize), _isCompressed(isCompressed) { +ArchiveItem::ArchiveItem(Common::SeekableReadStream *stream, Common::Mutex *guardMutex, const Common::Path &path, int64 filePos, uint compressedSize, uint decompressedSize, bool isCompressed) + : _stream(stream), _guardMutex(guardMutex), _path(path), _filePos(filePos), _compressedSize(compressedSize), _decompressedSize(decompressedSize), _isCompressed(isCompressed) { } Common::SeekableReadStream *ArchiveItem::createReadStream() const { @@ -627,14 +624,6 @@ Common::SeekableReadStream *ArchiveItem::createReadStreamForAltStream(Common::Al return nullptr; } -Common::String ArchiveItem::getName() const { - return _name; -} - -const Common::String &ArchiveItem::getPath() const { - return _path; -} - class PackageArchive : public Common::Archive { public: explicit PackageArchive(Common::SeekableReadStream *stream); @@ -656,7 +645,7 @@ private: static Common::String normalizePath(const Common::Path &path); Common::Array > _items; - Common::HashMap _pathToItemIndex; + Common::HashMap _pathToItemIndex; Common::SeekableReadStream *_stream; }; @@ -792,23 +781,12 @@ bool PackageArchive::load(const char *prefix) { if (fileName.hasPrefix(prefix)) { fileName = fileName.substr(strlen(prefix)); + fileName.replace('\\', '/'); + Common::Path path(fileName, '/'); - size_t bsPos = fileName.findFirstOf('\\'); - while (bsPos != Common::String::npos) { - fileName.replace(bsPos, 1, "/"); - bsPos = fileName.findFirstOf('\\'); - } + Common::SharedPtr item(new ArchiveItem(_stream, getGuardMutex(), path, dataStart, static_cast(dataEnd - dataStart), decompressedSize, isCompressed)); - Common::String fileNameNoDir = fileName; - - size_t lastSlashPos = fileNameNoDir.findLastOf('/'); - if (lastSlashPos != Common::String::npos) - fileNameNoDir = fileNameNoDir.substr(lastSlashPos + 1); - - Common::SharedPtr item(new ArchiveItem(_stream, getGuardMutex(), fileName, fileNameNoDir, dataStart, static_cast(dataEnd - dataStart), decompressedSize, isCompressed)); - - fileName.toLowercase(); - _pathToItemIndex[fileName] = _items.size(); + _pathToItemIndex[path] = _items.size(); _items.push_back(item); } @@ -852,7 +830,7 @@ Common::String PackageArchive::normalizePath(const Common::Path &path) { } bool PackageArchive::hasFile(const Common::Path &path) const { - return _pathToItemIndex.find(normalizePath(path)) != _pathToItemIndex.end(); + return _pathToItemIndex.find(path) != _pathToItemIndex.end(); } int PackageArchive::listMembers(Common::ArchiveMemberList &list) const { @@ -863,12 +841,11 @@ int PackageArchive::listMembers(Common::ArchiveMemberList &list) const { } int PackageArchive::listMatchingMembers(Common::ArchiveMemberList &list, const Common::Path &pattern, bool matchPathComponents) const { - Common::String patternString = pattern.toString(); int matches = 0; const char *wildcardExclusions = matchPathComponents ? NULL : "/"; for (const Common::SharedPtr &item : _items) { - if (item->getPath().matchString(patternString, true, wildcardExclusions)) { + if (normalizePath(item->getPathInArchive()).matchString(normalizePath(pattern), false, wildcardExclusions)) { list.push_back(item.staticCast()); matches++; } @@ -878,7 +855,7 @@ int PackageArchive::listMatchingMembers(Common::ArchiveMemberList &list, const C } const Common::ArchiveMemberPtr PackageArchive::getMember(const Common::Path &path) const { - Common::HashMap::const_iterator it = _pathToItemIndex.find(normalizePath(path)); + Common::HashMap::const_iterator it = _pathToItemIndex.find(path); if (it == _pathToItemIndex.end()) return nullptr; diff --git a/common/compression/installshield_cab.cpp b/common/compression/installshield_cab.cpp index 52319028407..45bd16e23a2 100644 --- a/common/compression/installshield_cab.cpp +++ b/common/compression/installshield_cab.cpp @@ -87,7 +87,7 @@ class InstallShieldCabinet : public Archive { public: InstallShieldCabinet(); - bool open(const String *baseName, const FSNode *node); + bool open(const Path *baseName, const FSNode *node); void close(); // Archive API implementation @@ -123,22 +123,22 @@ private: }; int _version; - typedef HashMap FileMap; + typedef HashMap FileMap; FileMap _map; - String _baseName; + Path _baseName; Common::Array _volumeHeaders; bool _useSearchMan; static bool readVolumeHeader(SeekableReadStream *volumeStream, VolumeHeader &inVolumeHeader); - String getHeaderName() const; - String getVolumeName(uint volume) const; + Path getHeaderName() const; + Path getVolumeName(uint volume) const; }; InstallShieldCabinet::InstallShieldCabinet() : _version(0), _useSearchMan(false) { } -bool InstallShieldCabinet::open(const String *baseName, const FSNode *node) { +bool InstallShieldCabinet::open(const Path *baseName, const FSNode *node) { // Store the base name so we can generate file names if (baseName) { _baseName = *baseName; @@ -150,8 +150,10 @@ bool InstallShieldCabinet::open(const String *baseName, const FSNode *node) { return false; } - if (_baseName.hasSuffix(".cab") || _baseName.hasSuffix(".hdr")) { - _baseName.erase(_baseName.size() - 5, String::npos); + String strippedName = _baseName.baseName(); + if (strippedName.hasSuffix(".cab") || strippedName.hasSuffix(".hdr")) { + strippedName.erase(strippedName.size() - 5, String::npos); + _baseName = _baseName.getParent().appendComponent(strippedName); } uint fileIndex = 0; @@ -250,7 +252,7 @@ bool InstallShieldCabinet::open(const String *baseName, const FSNode *node) { // Then let's get the string file->seek(headerHeader.cabDescriptorOffset + fileTableOffset + nameOffset); - String fileName = file->readString(); + Path fileName(file->readString(), '\\'); // Entries can appear in multiple volumes (sometimes erroneously). // We keep the one with the lowest volume ID @@ -303,10 +305,10 @@ bool InstallShieldCabinet::open(const String *baseName, const FSNode *node) { // Then let's get the string file->seek(headerHeader.cabDescriptorOffset + fileTableOffset + nameOffset); - String fileName = file->readString(); + Path fileName(file->readString(), '\\'); if (entry.volume == 0) { - warning("Couldn't find the volume for file %s", fileName.c_str()); + warning("Couldn't find the volume for file %s", fileName.toString('\\').c_str()); close(); return false; } @@ -331,8 +333,7 @@ void InstallShieldCabinet::close() { } bool InstallShieldCabinet::hasFile(const Path &path) const { - String name = path.toString(); - return _map.contains(name); + return _map.contains(path); } int InstallShieldCabinet::listMembers(ArchiveMemberList &list) const { @@ -347,14 +348,13 @@ const ArchiveMemberPtr InstallShieldCabinet::getMember(const Path &path) const { } SeekableReadStream *InstallShieldCabinet::createReadStreamForMember(const Path &path) const { - String name = path.toString(); - if (!_map.contains(name)) + if (!_map.contains(path)) return nullptr; - const FileEntry &entry = _map[name]; + const FileEntry &entry = _map[path]; if (entry.flags & kObfuscated) { - warning("Cannot extract obfuscated file %s", name.c_str()); + warning("Cannot extract obfuscated file %s", path.toString().c_str()); return nullptr; } @@ -369,7 +369,7 @@ SeekableReadStream *InstallShieldCabinet::createReadStreamForMember(const Path & } if (!stream) { - warning("Failed to open volume for file '%s'", name.c_str()); + warning("Failed to open volume for file '%s'", path.toString().c_str()); return nullptr; } @@ -396,7 +396,7 @@ SeekableReadStream *InstallShieldCabinet::createReadStreamForMember(const Path & } if (!stream.get()) { - warning("Failed to read split file %s", name.c_str()); + warning("Failed to read split file %s", path.toString().c_str()); free(src); return nullptr; } @@ -428,7 +428,7 @@ SeekableReadStream *InstallShieldCabinet::createReadStreamForMember(const Path & // Entries with size 0 are valid, and do not need to be inflated if (entry.compressedSize != 0) { if (!inflateZlibInstallShield(dst, entry.uncompressedSize, src, entry.compressedSize)) { - warning("failed to inflate CAB file '%s'", name.c_str()); + warning("failed to inflate CAB file '%s'", path.toString().c_str()); free(dst); free(src); return nullptr; @@ -499,17 +499,17 @@ bool InstallShieldCabinet::readVolumeHeader(SeekableReadStream *volumeStream, In return true; } -String InstallShieldCabinet::getHeaderName() const { - return _baseName + "1.hdr"; +Path InstallShieldCabinet::getHeaderName() const { + return _baseName.append("1.hdr"); } -String InstallShieldCabinet::getVolumeName(uint volume) const { - return String::format("%s%d.cab", _baseName.c_str(), volume); +Path InstallShieldCabinet::getVolumeName(uint volume) const { + return _baseName.append(String::format("%d.cab", volume)); } } // End of anonymous namespace -Archive *makeInstallShieldArchive(const String &baseName) { +Archive *makeInstallShieldArchive(const Path &baseName) { InstallShieldCabinet *cab = new InstallShieldCabinet(); if (!cab->open(&baseName, nullptr)) { delete cab; diff --git a/common/compression/installshield_cab.h b/common/compression/installshield_cab.h index 1115429f67d..b6ef5dcb82f 100644 --- a/common/compression/installshield_cab.h +++ b/common/compression/installshield_cab.h @@ -49,7 +49,7 @@ class SeekableReadStream; * * @param baseName The base filename, e.g. the "data" in "data1.cab" */ -Archive *makeInstallShieldArchive(const Common::String &baseName); +Archive *makeInstallShieldArchive(const Common::Path &baseName); /** * This factory method creates an Archive instance corresponding to the content diff --git a/common/compression/installshieldv3_archive.cpp b/common/compression/installshieldv3_archive.cpp index 3a8354b1387..47205249c6c 100644 --- a/common/compression/installshieldv3_archive.cpp +++ b/common/compression/installshieldv3_archive.cpp @@ -34,7 +34,7 @@ InstallShieldV3::~InstallShieldV3() { close(); } -bool InstallShieldV3::open(const Common::String &filename) { +bool InstallShieldV3::open(const Common::Path &filename) { close(); _stream = SearchMan.createReadStreamForMember(filename); @@ -74,8 +74,7 @@ void InstallShieldV3::close() { } bool InstallShieldV3::hasFile(const Common::Path &path) const { - Common::String name = path.toString(); - return _map.contains(name); + return _map.contains(path); } int InstallShieldV3::listMembers(Common::ArchiveMemberList &list) const { @@ -86,20 +85,14 @@ int InstallShieldV3::listMembers(Common::ArchiveMemberList &list) const { } const Common::ArchiveMemberPtr InstallShieldV3::getMember(const Common::Path &path) const { - Common::String name = path.toString(); - return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, *this)); + return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(path, *this)); } Common::SeekableReadStream *InstallShieldV3::createReadStreamForMember(const Common::Path &path) const { - Common::String name = path.toString(); - // Make sure "/" is converted to "\" - while (name.contains("/")) - Common::replace(name, "/", "\\"); - - if (!_stream || !_map.contains(name)) + if (!_stream || !_map.contains(path)) return nullptr; - const FileEntry &entry = _map[name]; + const FileEntry &entry = _map[path]; // Seek to our offset and then send it off to the decompressor _stream->seek(entry.offset); @@ -178,7 +171,7 @@ bool InstallShieldV3::read() { if (!dirNames[i].empty()) name = dirNames[i] + "\\" + name; - _map[name] = entry; + _map[Path(name, '\\')] = entry; debug(3, "Found file '%s' at 0x%08x (Comp: 0x%08x, Uncomp: 0x%08x)", name.c_str(), entry.offset, entry.compressedSize, entry.uncompressedSize); } diff --git a/common/compression/installshieldv3_archive.h b/common/compression/installshieldv3_archive.h index 34318f1228c..98df7de7a0c 100644 --- a/common/compression/installshieldv3_archive.h +++ b/common/compression/installshieldv3_archive.h @@ -37,7 +37,7 @@ public: InstallShieldV3(); ~InstallShieldV3() override; - bool open(const Common::String &filename); + bool open(const Common::Path &filename); bool open(const Common::FSNode &node); bool open(Common::SeekableReadStream *stream); void close(); @@ -61,7 +61,7 @@ private: Common::SeekableReadStream *_stream; - typedef Common::HashMap FileMap; + typedef Common::HashMap FileMap; FileMap _map; }; diff --git a/common/compression/stuffit.cpp b/common/compression/stuffit.cpp index 704b1882d5c..dddfa254a29 100644 --- a/common/compression/stuffit.cpp +++ b/common/compression/stuffit.cpp @@ -43,7 +43,7 @@ public: StuffItArchive(); ~StuffItArchive() override; - bool open(const Common::String &filename, bool flattenTree); + bool open(const Common::Path &filename, bool flattenTree); bool open(Common::SeekableReadStream *stream, bool flattenTree); void close(); bool isOpen() const { return _stream != nullptr; } @@ -52,9 +52,9 @@ public: bool hasFile(const Common::Path &path) const override; int listMembers(Common::ArchiveMemberList &list) const override; const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override; - Common::SharedArchiveContents readContentsForPath(const Common::String &name) const override; - Common::SharedArchiveContents readContentsForPathAltStream(const String &translatedPath, Common::AltStreamType altStreamType) const override; - Common::String translatePath(const Common::Path &path) const override; + Common::SharedArchiveContents readContentsForPath(const Common::Path &name) const override; + Common::SharedArchiveContents readContentsForPathAltStream(const Common::Path &translatedPath, Common::AltStreamType altStreamType) const override; + Common::Path translatePath(const Common::Path &path) const override; char getPathSeparator() const override; private: @@ -82,10 +82,10 @@ private: Common::SeekableReadStream *_stream; - typedef Common::HashMap FileMap; + typedef Common::HashMap FileMap; FileMap _map; - typedef Common::HashMap MetadataMap; + typedef Common::HashMap MetadataMap; MetadataMap _metadataMap; bool _flattenTree; @@ -98,7 +98,7 @@ private: void update14(uint16 first, uint16 last, byte *code, uint16 *freq) const; void readTree14(Common::BitStream8LSB *bits, SIT14Data *dat, uint16 codesize, uint16 *result) const; - Common::SharedArchiveContents readContentsForPathFork(const String &translatedPath, bool isResFork) const; + Common::SharedArchiveContents readContentsForPathFork(const Common::Path &translatedPath, bool isResFork) const; }; StuffItArchive::StuffItArchive() : Common::MemcachingCaseInsensitiveArchive(), _flattenTree(false) { @@ -117,7 +117,7 @@ static const uint32 s_magicNumbers[] = { MKTAG('S', 'T', 'i', '3'), MKTAG('S', 'T', 'i', '4'), MKTAG('S', 'T', '4', '6') }; -bool StuffItArchive::open(const Common::String &filename, bool flattenTree) { +bool StuffItArchive::open(const Common::Path &filename, bool flattenTree) { Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(filename); return open(stream, flattenTree); } @@ -237,12 +237,14 @@ bool StuffItArchive::open(Common::SeekableReadStream *stream, bool flattenTree) if (!flattenTree) name = dirPrefix + name; - _metadataMap[name] = finfo.toData(); + Common::Path path(name, ':'); + + _metadataMap[path] = finfo.toData(); if (dataForkUncompressedSize != 0) { // We have a data fork - FileEntryFork &entryFork = _map[name].dataFork; + FileEntryFork &entryFork = _map[path].dataFork; entryFork.compression = dataForkCompression; entryFork.uncompressedSize = dataForkUncompressedSize; entryFork.compressedSize = dataForkCompressedSize; @@ -255,7 +257,7 @@ bool StuffItArchive::open(Common::SeekableReadStream *stream, bool flattenTree) if (resForkUncompressedSize != 0) { // We have a resource fork - FileEntryFork &entryFork = _map[name].resFork; + FileEntryFork &entryFork = _map[path].resFork; entryFork.compression = resForkCompression; entryFork.uncompressedSize = resForkUncompressedSize; entryFork.compressedSize = resForkCompressedSize; @@ -279,8 +281,7 @@ void StuffItArchive::close() { } bool StuffItArchive::hasFile(const Common::Path &path) const { - Common::String name = path.toString(':'); - return _map.contains(name); + return _map.contains(path); } int StuffItArchive::listMembers(Common::ArchiveMemberList &list) const { @@ -294,11 +295,11 @@ const Common::ArchiveMemberPtr StuffItArchive::getMember(const Common::Path &pat return Common::ArchiveMemberPtr(new StuffItArchiveMember(path, *this)); } -Common::SharedArchiveContents StuffItArchive::readContentsForPath(const Common::String &name) const { - return readContentsForPathFork(name, false); +Common::SharedArchiveContents StuffItArchive::readContentsForPath(const Common::Path &path) const { + return readContentsForPathFork(path, false); } -Common::SharedArchiveContents StuffItArchive::readContentsForPathAltStream(const String &translatedPath, Common::AltStreamType altStreamType) const { +Common::SharedArchiveContents StuffItArchive::readContentsForPathAltStream(const Common::Path &translatedPath, Common::AltStreamType altStreamType) const { if (altStreamType == Common::AltStreamType::MacFinderInfo) { if (_metadataMap.contains(translatedPath)) { const Common::MacFinderInfoData &metadata = _metadataMap[translatedPath]; @@ -315,13 +316,13 @@ Common::SharedArchiveContents StuffItArchive::readContentsForPathAltStream(const return Common::SharedArchiveContents(); } -Common::SharedArchiveContents StuffItArchive::readContentsForPathFork(const Common::String &name, bool isResFork) const { - FileMap::const_iterator entryIt = _map.find(name); +Common::SharedArchiveContents StuffItArchive::readContentsForPathFork(const Common::Path &path, bool isResFork) const { + FileMap::const_iterator entryIt = _map.find(path); if (entryIt == _map.end()) return Common::SharedArchiveContents(); - const FileEntry &entry = _map[name]; + const FileEntry &entry = entryIt->_value; const FileEntryFork &entryFork = isResFork ? entry.resFork : entry.dataFork; if (entryFork.uncompressedSize == 0) { @@ -358,14 +359,14 @@ Common::SharedArchiveContents StuffItArchive::readContentsForPathFork(const Comm uint16 actualCRC = Common::CRC16().crcFast(uncompressedBlock, entryFork.uncompressedSize); if (actualCRC != entryFork.crc) { - error("StuffItArchive::readContentsForPath(): CRC mismatch: %04x vs %04x for file %s %s fork", actualCRC, entryFork.crc, name.c_str(), (isResFork ? "res" : "data")); + error("StuffItArchive::readContentsForPath(): CRC mismatch: %04x vs %04x for file %s %s fork", actualCRC, entryFork.crc, path.toString().c_str(), (isResFork ? "res" : "data")); } return Common::SharedArchiveContents(uncompressedBlock, entryFork.uncompressedSize); } -Common::String StuffItArchive::translatePath(const Common::Path &path) const { - return _flattenTree ? path.getLastComponent().toString() : path.toString(':'); +Common::Path StuffItArchive::translatePath(const Common::Path &path) const { + return _flattenTree ? path.getLastComponent() : path; } char StuffItArchive::getPathSeparator() const { @@ -1133,7 +1134,7 @@ bool StuffItArchive::StuffItArchiveMember::isInMacArchive() const { return true; } -Common::Archive *createStuffItArchive(const Common::String &fileName, bool flattenTree) { +Common::Archive *createStuffItArchive(const Common::Path &fileName, bool flattenTree) { StuffItArchive *archive = new StuffItArchive(); if (!archive->open(fileName, flattenTree)) { diff --git a/common/compression/stuffit.h b/common/compression/stuffit.h index fa234106e71..2e74f2fbaf5 100644 --- a/common/compression/stuffit.h +++ b/common/compression/stuffit.h @@ -43,7 +43,7 @@ namespace Common { */ class Archive; -class String; +class Path; class SeekableReadStream; /** @@ -55,7 +55,7 @@ class SeekableReadStream; * * @return The StuffIt archive */ -Archive *createStuffItArchive(const String &fileName, bool flattenTree = false); +Archive *createStuffItArchive(const Path &fileName, bool flattenTree = false); Archive *createStuffItArchive(SeekableReadStream *stream, bool flattenTree = false); /** @} */ diff --git a/common/compression/unarj.cpp b/common/compression/unarj.cpp index 4329877809f..007f4018a15 100644 --- a/common/compression/unarj.cpp +++ b/common/compression/unarj.cpp @@ -697,24 +697,24 @@ struct ArjFileChunk { ArjFileChunk(ArjHeader* header, uint volume) : _header(header), _volume(volume) {} }; -typedef HashMap, IgnoreCase_Hash, IgnoreCase_EqualTo> ArjHeadersMap; +typedef HashMap, Path::IgnoreCase_Hash, Path::IgnoreCase_EqualTo> ArjHeadersMap; class ArjArchive : public MemcachingCaseInsensitiveArchive { ArjHeadersMap _headers; - Array _arjFilenames; + Array _arjFilenames; bool _flattenTree; public: - ArjArchive(const Array &names, bool flattenTree); + ArjArchive(const Array &names, bool flattenTree); virtual ~ArjArchive(); // Archive implementation bool hasFile(const Path &path) const override; int listMembers(ArchiveMemberList &list) const override; const ArchiveMemberPtr getMember(const Path &path) const override; - Common::SharedArchiveContents readContentsForPath(const Common::String& translated) const override; - Common::String translatePath(const Common::Path &path) const override { - return _flattenTree ? path.getLastComponent().toString() : path.toString(); + Common::SharedArchiveContents readContentsForPath(const Common::Path &translated) const override; + Common::Path translatePath(const Common::Path &path) const override { + return _flattenTree ? path.getLastComponent() : path; } }; @@ -727,7 +727,7 @@ ArjArchive::~ArjArchive() { } } -ArjArchive::ArjArchive(const Array &filenames, bool flattenTree) : _arjFilenames(filenames), _flattenTree(flattenTree) { +ArjArchive::ArjArchive(const Array &filenames, bool flattenTree) : _arjFilenames(filenames), _flattenTree(flattenTree) { for (uint i = 0; i < _arjFilenames.size(); i++) { File arjFile; @@ -753,21 +753,28 @@ ArjArchive::ArjArchive(const Array &filenames, bool flattenTree) : _arjF while ((header = readHeader(arjFile)) != nullptr) { const char *name = header->filename; - if (_flattenTree) - for (const char *p = header->filename; *p; p++) - if (*p == '\\' || *p == '/') + if (_flattenTree) { + for (const char *p = header->filename; *p; p++) { + if (*p == '\\' || *p == '/') { name = p + 1; - _headers[name].push_back(ArjFileChunk(header, i)); + } + } + } else { + for (char *p = header->filename; *p; p++) { + if (*p == '\\') + *p = '/'; + } + } + _headers[Path(name)].push_back(ArjFileChunk(header, i)); arjFile.seek(header->compSize, SEEK_CUR); } } - debug(0, "ArjArchive::ArjArchive(%d volume(s) starting with %s): Located %d files", filenames.size(), filenames.empty() ? "" : filenames[0].c_str(), _headers.size()); + debug(0, "ArjArchive::ArjArchive(%d volume(s) starting with %s): Located %d files", filenames.size(), filenames.empty() ? "" : filenames[0].toString(Common::Path::kNativeSeparator).c_str(), _headers.size()); } bool ArjArchive::hasFile(const Path &path) const { - String name = path.toString(); - return _headers.contains(name); + return _headers.contains(path); } int ArjArchive::listMembers(ArchiveMemberList &list) const { @@ -775,7 +782,7 @@ int ArjArchive::listMembers(ArchiveMemberList &list) const { ArjHeadersMap::const_iterator it = _headers.begin(); for ( ; it != _headers.end(); ++it) { - list.push_back(ArchiveMemberList::value_type(new GenericArchiveMember(Common::String(it->_value[0]._header->filename), *this))); + list.push_back(ArchiveMemberList::value_type(new GenericArchiveMember(Path(it->_value[0]._header->filename), *this))); matches++; } @@ -783,19 +790,18 @@ int ArjArchive::listMembers(ArchiveMemberList &list) const { } const ArchiveMemberPtr ArjArchive::getMember(const Path &path) const { - String name = path.toString(); - if (!hasFile(name)) + if (!hasFile(path)) return ArchiveMemberPtr(); - return ArchiveMemberPtr(new GenericArchiveMember(name, *this)); + return ArchiveMemberPtr(new GenericArchiveMember(path, *this)); } -Common::SharedArchiveContents ArjArchive::readContentsForPath(const Common::String& name) const { - if (!_headers.contains(name)) { +Common::SharedArchiveContents ArjArchive::readContentsForPath(const Common::Path &path) const { + if (!_headers.contains(path)) { return Common::SharedArchiveContents(); } - const Array & hdrs = _headers[name]; + const Array & hdrs = _headers[path]; uint64 uncompressedSize = 0; uint totalChunks; @@ -848,11 +854,11 @@ Common::SharedArchiveContents ArjArchive::readContentsForPath(const Common::Stri return Common::SharedArchiveContents(uncompressedData, uncompressedSize); } -Archive *makeArjArchive(const String &name, bool flattenTree) { +Archive *makeArjArchive(const Path &name, bool flattenTree) { return new ArjArchive({name}, flattenTree); } -Archive *makeArjArchive(const Array &names, bool flattenTree) { +Archive *makeArjArchive(const Array &names, bool flattenTree) { return new ArjArchive(names, flattenTree); } diff --git a/common/compression/unarj.h b/common/compression/unarj.h index ba90f028de8..8773a01fc5b 100644 --- a/common/compression/unarj.h +++ b/common/compression/unarj.h @@ -49,12 +49,12 @@ class Archive; * * May return 0 in case of a failure. */ -Archive *makeArjArchive(const String &name, bool flattenTree = false); +Archive *makeArjArchive(const Path &name, bool flattenTree = false); /** * Similar to previous but for multi-volume archives */ -Archive *makeArjArchive(const Array &names, bool flattenTree = false); +Archive *makeArjArchive(const Array &names, bool flattenTree = false); /** @} */ diff --git a/common/compression/unzip.cpp b/common/compression/unzip.cpp index df49edcca57..39276b1699d 100644 --- a/common/compression/unzip.cpp +++ b/common/compression/unzip.cpp @@ -318,8 +318,8 @@ typedef struct { unz_file_info_internal cur_file_info_internal; /* private info about it*/ } cached_file_in_zip; -typedef Common::HashMap ZipHash; +typedef Common::HashMap ZipHash; /* unz_s contain internal information about the zipfile */ @@ -535,12 +535,14 @@ unzFile unzOpen(Common::SeekableReadStream *stream, bool flattenTree) { fe.cur_file_info = us->cur_file_info; fe.cur_file_info_internal = us->cur_file_info_internal; - Common::String name(szCurrentFileName); - bool isDirectory = false; - if (name.hasSuffix("/") || name.hasSuffix("\\")) { - isDirectory = true; - name = name.substr(0, name.size() - 1); + if (*szCurrentFileName) { + char *szCurrentFileNameSuffix = szCurrentFileName + strlen(szCurrentFileName) - 1; + if (*szCurrentFileNameSuffix == '/' || *szCurrentFileNameSuffix == '\\') { + isDirectory = true; + // Strip trailing path terminator + *szCurrentFileNameSuffix = '\0'; + } } // If platform is specified as MS-DOS or Unix, check the directory flag @@ -564,20 +566,21 @@ unzFile unzOpen(Common::SeekableReadStream *stream, bool flattenTree) { } } + const char *name = szCurrentFileName; if (flattenTree) { if (isDirectory) continue; - size_t slashPos = name.findLastOf('\\'); - if (slashPos != Common::String::npos) - name = name.substr(slashPos + 1); - - slashPos = name.findLastOf('/'); - if (slashPos != Common::String::npos) - name = name.substr(slashPos + 1); + for (const char *p = szCurrentFileName; *p; p++) + if (*p == '\\' || *p == '/') + name = p + 1; + } else { + for (char *p = szCurrentFileName; *p; p++) + if (*p == '\\') + *p = '/'; } - us->_hash[name] = fe; + us->_hash[Common::Path(name)] = fe; // Move to the next file err = unzGoToNextFile((unzFile)us); @@ -832,21 +835,18 @@ int unzGoToNextFile(unzFile file) { UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ -int unzLocateFile(unzFile file, const char *szFileName, int iCaseSensitivity) { +int unzLocateFile(unzFile file, const Common::Path &szFileName, int iCaseSensitivity) { unz_s *s; if (file == nullptr) return UNZ_PARAMERROR; - if (strlen(szFileName) >= UNZ_MAXFILENAMEINZIP) - return UNZ_PARAMERROR; - s=(unz_s *)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; // Check to see if the entry exists - ZipHash::iterator i = s->_hash.find(Common::String(szFileName)); + ZipHash::iterator i = s->_hash.find(szFileName); if (i == s->_hash.end()) return UNZ_END_OF_LIST_OF_FILE; @@ -1039,9 +1039,9 @@ public: bool isPathDirectory(const Path &path) const override; int listMembers(ArchiveMemberList &list) const override; const ArchiveMemberPtr getMember(const Path &path) const override; - Common::SharedArchiveContents readContentsForPath(const Common::String& translated) const override; - Common::String translatePath(const Common::Path &path) const override { - return _flattenTree ? path.getLastComponent().toString() : path.toString(); + Common::SharedArchiveContents readContentsForPath(const Common::Path &translated) const override; + Common::Path translatePath(const Common::Path &path) const override { + return _flattenTree ? path.getLastComponent() : path; } }; @@ -1072,14 +1072,11 @@ ZipArchive::~ZipArchive() { } bool ZipArchive::hasFile(const Path &path) const { - String name = path.toString(); - return (unzLocateFile(_zipFile, name.c_str(), 2) == UNZ_OK); + return (unzLocateFile(_zipFile, path, 2) == UNZ_OK); } bool ZipArchive::isPathDirectory(const Path &path) const { - String name = path.toString(); - - if (unzLocateFile(_zipFile, name.c_str(), 2) != UNZ_OK) + if (unzLocateFile(_zipFile, path, 2) != UNZ_OK) return false; unz_file_info fi; @@ -1103,15 +1100,14 @@ int ZipArchive::listMembers(ArchiveMemberList &list) const { } const ArchiveMemberPtr ZipArchive::getMember(const Path &path) const { - String name = path.toString(); - if (!hasFile(name)) + if (!hasFile(path)) return ArchiveMemberPtr(); return ArchiveMemberPtr(new GenericArchiveMember(path, *this)); } -Common::SharedArchiveContents ZipArchive::readContentsForPath(const Common::String& name) const { - if (unzLocateFile(_zipFile, name.c_str(), 2) != UNZ_OK) +Common::SharedArchiveContents ZipArchive::readContentsForPath(const Common::Path &path) const { + if (unzLocateFile(_zipFile, path, 2) != UNZ_OK) return Common::SharedArchiveContents(); #ifndef USE_ZLIB return unzOpenCurrentFile(_zipFile, _crc); @@ -1120,7 +1116,7 @@ Common::SharedArchiveContents ZipArchive::readContentsForPath(const Common::Stri #endif } -Archive *makeZipArchive(const String &name, bool flattenTree) { +Archive *makeZipArchive(const Path &name, bool flattenTree) { return makeZipArchive(SearchMan.createReadStreamForMember(name), flattenTree); } diff --git a/common/compression/unzip.h b/common/compression/unzip.h index ee9b070faa3..3e942802b59 100644 --- a/common/compression/unzip.h +++ b/common/compression/unzip.h @@ -45,7 +45,7 @@ class SeekableReadStream; * * May return 0 in case of a failure. */ -Archive *makeZipArchive(const String &name, bool flattenTree = false); +Archive *makeZipArchive(const Path &name, bool flattenTree = false); /** * This factory method creates an Archive instance corresponding to the content diff --git a/common/formats/prodos.cpp b/common/formats/prodos.cpp index 78b7c0ad2c0..29c78088825 100644 --- a/common/formats/prodos.cpp +++ b/common/formats/prodos.cpp @@ -351,7 +351,7 @@ void ProDOSDisk::getVolumeBitmap(VolHeader *h) { /* Gets the volume information and parses the filesystem, adding file objects to a map as it goes */ -bool ProDOSDisk::open(const Common::String filename) { +bool ProDOSDisk::open(const Common::Path &filename) { _disk.open(filename); _disk.read(_loader1, kBlockSize); _disk.read(_loader2, kBlockSize); @@ -371,7 +371,7 @@ bool ProDOSDisk::open(const Common::String filename) { /* Constructor simply calls open(), and if it is successful it prints a statement */ -ProDOSDisk::ProDOSDisk(const Common::String filename) { +ProDOSDisk::ProDOSDisk(const Common::Path &filename) { if (open(filename)) { //debug("%s has been loaded", filename.c_str()); } diff --git a/common/formats/prodos.h b/common/formats/prodos.h index f71db7ebfea..92502e96e4f 100644 --- a/common/formats/prodos.h +++ b/common/formats/prodos.h @@ -116,11 +116,11 @@ class ProDOSDisk : public Common::Archive { public: static const int kBlockSize = 512; // A ProDOS block is always 512 bytes (should this be an enum?) - ProDOSDisk(const Common::String filename); + ProDOSDisk(const Common::Path &filename); ~ProDOSDisk(); // Frees the memory used in the dictionary and the volume bitmap // Called from the constructor, it parses the volume and fills the hashmap with files - bool open(const Common::String filename); + bool open(const Common::Path &filename); // These are the Common::Archive related methods bool hasFile(const Common::Path &path) const override; diff --git a/common/formats/winexe.cpp b/common/formats/winexe.cpp index 510ef615856..a34e4302514 100644 --- a/common/formats/winexe.cpp +++ b/common/formats/winexe.cpp @@ -82,7 +82,7 @@ String WinResourceID::toString() const { return ""; } -bool WinResources::loadFromEXE(const String &fileName) { +bool WinResources::loadFromEXE(const Path &fileName) { if (fileName.empty()) return false; @@ -96,7 +96,7 @@ bool WinResources::loadFromEXE(const String &fileName) { return loadFromEXE(file); } -bool WinResources::loadFromCompressedEXE(const String &fileName) { +bool WinResources::loadFromCompressedEXE(const Path &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 @@ -172,7 +172,7 @@ bool WinResources::loadFromCompressedEXE(const String &fileName) { } -WinResources *WinResources::createFromEXE(const String &fileName) { +WinResources *WinResources::createFromEXE(const Path &fileName) { WinResources *exe; // First try loading via the NE code diff --git a/common/formats/winexe.h b/common/formats/winexe.h index 93ca7a0f83d..0ca57d58319 100644 --- a/common/formats/winexe.h +++ b/common/formats/winexe.h @@ -37,6 +37,7 @@ namespace Common { * @{ */ +class Path; class SeekableReadStream; /** The default Windows resources. */ @@ -114,10 +115,10 @@ public: virtual void clear() = 0; /** Load from an EXE file. */ - virtual bool loadFromEXE(const String &fileName); + virtual bool loadFromEXE(const Path &fileName); /** Load from a Windows compressed EXE file. */ - virtual bool loadFromCompressedEXE(const String &fileName); + virtual bool loadFromCompressedEXE(const Path &fileName); /** Load from a stream. */ virtual bool loadFromEXE(SeekableReadStream *stream, DisposeAfterUse::Flag disposeFileHandle = DisposeAfterUse::YES) = 0; @@ -139,7 +140,7 @@ public: return getResource(type, id); } - static WinResources *createFromEXE(const String &fileName); + static WinResources *createFromEXE(const Path &fileName); static WinResources *createFromEXE(SeekableReadStream *stream); typedef Common::HashMap VersionHash; diff --git a/common/formats/xmlparser.cpp b/common/formats/xmlparser.cpp index 66026a8f549..22a25764e39 100644 --- a/common/formats/xmlparser.cpp +++ b/common/formats/xmlparser.cpp @@ -41,7 +41,7 @@ XMLParser::~XMLParser() { _layoutList.clear(); } -bool XMLParser::loadFile(const String &filename) { +bool XMLParser::loadFile(const Path &filename) { _stream = SearchMan.createReadStreamForMember(filename); if (!_stream) return false; @@ -96,7 +96,7 @@ bool XMLParser::parserError(const String &errStr) { assert(_stream->pos() == startPosition); currentPosition = startPosition; - Common::String errorMessage = Common::String::format("\n File <%s>, line %d:\n", _fileName.c_str(), lineCount); + Common::String errorMessage = Common::String::format("\n File <%s>, line %d:\n", _fileName.toString().c_str(), lineCount); if (startPosition > 1) { int keyOpening = 0; diff --git a/common/formats/xmlparser.h b/common/formats/xmlparser.h index 49b4b5c8915..db68719145f 100644 --- a/common/formats/xmlparser.h +++ b/common/formats/xmlparser.h @@ -168,7 +168,7 @@ public: * * @param filename Name of the file to load. */ - bool loadFile(const String &filename); + bool loadFile(const Path &filename); bool loadFile(const FSNode &node); @@ -377,7 +377,7 @@ private: char _char; bool _allowText; /** Allow text nodes in the doc (default false) */ SeekableReadStream *_stream; - String _fileName; + Path _fileName; ParserState _state; /** Internal state of the parser */ diff --git a/common/lua/scummvm_file.cpp b/common/lua/scummvm_file.cpp index 1c651c85ab7..ca2fc12ddd1 100644 --- a/common/lua/scummvm_file.cpp +++ b/common/lua/scummvm_file.cpp @@ -29,7 +29,7 @@ LuaFileProxy *LuaFileProxy::create(const Common::String &filename, const Common: if (filename.contains("config.lua")) return new LuaFileConfig(filename, mode); - return new LuaFileRead(filename, mode); + return new LuaFileRead(Common::Path(filename, '/'), mode); } LuaFileConfig::LuaFileConfig(const Common::String &filename, const Common::String &mode) : _readPos(0) { @@ -235,10 +235,10 @@ void LuaFileConfig::setLanguage(const Common::String &lang) { } -LuaFileRead::LuaFileRead(const Common::String &filename, const Common::String &mode) { +LuaFileRead::LuaFileRead(const Common::Path &filename, const Common::String &mode) { assert(mode == "r"); if (!_file.open(filename)) - error("Could not open file %s", filename.c_str()); + error("Could not open file %s", filename.toString().c_str()); _size = _file.size(); } diff --git a/common/lua/scummvm_file.h b/common/lua/scummvm_file.h index 51cb771dca3..35a95f13c1b 100644 --- a/common/lua/scummvm_file.h +++ b/common/lua/scummvm_file.h @@ -69,7 +69,7 @@ private: Common::File _file; int32 _size; public: - LuaFileRead(const Common::String &filename, const Common::String &mode); + LuaFileRead(const Common::Path &filename, const Common::String &mode); public: virtual ~LuaFileRead() {} diff --git a/common/macresman.cpp b/common/macresman.cpp index 5432e82d367..8a26d448b2a 100644 --- a/common/macresman.cpp +++ b/common/macresman.cpp @@ -177,7 +177,7 @@ SeekableReadStream *MacResManager::openAppleDoubleWithAppleOrOSXNaming(Archive& const Common::FSNode *plainFsNode = dynamic_cast(archiveMember.get()); // Try finding __MACOSX - Common::StringArray components = (plainFsNode ? Common::Path(plainFsNode->getPath(), '/') : fileName).splitComponents(); + Common::StringArray components = (plainFsNode ? plainFsNode->getPath() : fileName).splitComponents(); if (components.empty() || components[components.size() - 1].empty()) return nullptr; for (int i = components.size() - 1; i >= 0; i--) { @@ -512,20 +512,20 @@ bool MacResManager::getFileFinderInfo(const Path &fileName, MacFinderInfo &outFi return getFileFinderInfo(fileName, SearchMan, outFinderInfo, outFinderExtendedInfo); } -void MacResManager::listFiles(StringArray &files, const String &pattern) { +void MacResManager::listFiles(Array &files, const Path &pattern) { // Base names discovered so far. - typedef HashMap BaseNameSet; + typedef HashMap BaseNameSet; BaseNameSet baseNames; // List files itself. ArchiveMemberList memberList; SearchMan.listMatchingMembers(memberList, pattern); - SearchMan.listMatchingMembers(memberList, pattern + ".rsrc"); - SearchMan.listMatchingMembers(memberList, pattern + ".bin"); + SearchMan.listMatchingMembers(memberList, pattern.append(".rsrc")); + SearchMan.listMatchingMembers(memberList, pattern.append(".bin")); SearchMan.listMatchingMembers(memberList, constructAppleDoubleName(pattern)); for (ArchiveMemberList::const_iterator i = memberList.begin(), end = memberList.end(); i != end; ++i) { - String filename = (*i)->getName(); + String filename = (*i)->getFileName(); // For raw resource forks and MacBinary files we strip the extension // here to obtain a valid base name. @@ -560,12 +560,13 @@ void MacResManager::listFiles(StringArray &files, const String &pattern) { // Strip AppleDouble '._' prefix if applicable. bool isAppleDoubleName = false; - const String filenameAppleDoubleStripped = disassembleAppleDoubleName(filename, &isAppleDoubleName).toString(); + const Path filenameAppleDoubleStripped = disassembleAppleDoubleName( + Common::Path(filename, Common::Path::kNoSeparator), &isAppleDoubleName); if (isAppleDoubleName) { SeekableReadStream *stream = (*i)->createReadStream(); if (stream->readUint32BE() == 0x00051607) { - filename = filenameAppleDoubleStripped; + filename = filenameAppleDoubleStripped.baseName(); } // TODO: Should we really keep filenames suggesting AppleDouble // but not being AppleDouble around? This might depend on the @@ -573,7 +574,8 @@ void MacResManager::listFiles(StringArray &files, const String &pattern) { delete stream; } - baseNames[filename] = true; + Common::Path basePath((*i)->getPathInArchive().getParent().appendComponent(filename)); + baseNames[basePath] = true; } // Append resulting base names to list to indicate found files. @@ -1011,25 +1013,28 @@ void MacResManager::readMap() { } } -Path MacResManager::constructAppleDoubleName(Path name) { +Path MacResManager::constructAppleDoubleName(const Path &name) { // Insert "._" before the last portion of a path name - Path parent = name.getParent(); + Path ret = name.getParent(); Path lastComponent = name.getLastComponent(); - return parent.append("._").append(lastComponent); + return ret.appendInPlace("._").appendInPlace(lastComponent); } -Path MacResManager::disassembleAppleDoubleName(Path name, bool *isAppleDouble) { +Path MacResManager::disassembleAppleDoubleName(const Path &name, bool *isAppleDouble) { if (isAppleDouble) { *isAppleDouble = false; } // Remove "._" before the last portion of a path name. - Path parent = name.getParent(); - Path lastComponent = name.getLastComponent(); - String lastComponentString = lastComponent.toString(); - if (!lastComponentString.hasPrefix("._")) + Path ret = name.getParent(); + String lastComponent = name.baseName(); + if (!lastComponent.hasPrefix("._")) return name; - return parent.appendComponent(lastComponentString.substr(2)); + ret = ret.appendComponent(lastComponent.substr(2)); + if (name.isSeparatorTerminated()) { + ret.appendInPlace("/"); + } + return ret; } void MacResManager::dumpRaw() { @@ -1048,10 +1053,10 @@ void MacResManager::dumpRaw() { dataSize = len; } - Common::String filename = Common::String::format("./dumps/%s-%s-%d", _baseFileName.toString().c_str(), tag2str(_resTypes[i].id), j); + Common::String filename = Common::String::format("./dumps/%s-%s-%d", _baseFileName.baseName().c_str(), tag2str(_resTypes[i].id), j); _stream->read(data, len); - if (!out.open(filename)) { + if (!out.open(Common::Path(filename, '/'))) { warning("MacResManager::dumpRaw(): Can not open dump file %s", filename.c_str()); return; } diff --git a/common/macresman.h b/common/macresman.h index 8bc20dcf082..68cc593716c 100644 --- a/common/macresman.h +++ b/common/macresman.h @@ -193,7 +193,7 @@ public: * @param pattern Pattern to match against. Taking String::matchPattern's * format. */ - static void listFiles(StringArray &files, const String &pattern); + static void listFiles(Array &files, const Path &pattern); /** * Close the Mac data/resource fork pair. @@ -321,8 +321,8 @@ private: static bool readAndValidateMacBinaryHeader(SeekableReadStream &stream, byte (&outMacBinaryHeader)[MBI_INFOHDR]); - static Path constructAppleDoubleName(Path name); - static Path disassembleAppleDoubleName(Path name, bool *isAppleDouble); + static Path constructAppleDoubleName(const Path &name); + static Path disassembleAppleDoubleName(const Path &name, bool *isAppleDouble); static SeekableReadStream *openAppleDoubleWithAppleOrOSXNaming(Archive& archive, const Path &fileName); diff --git a/common/translation.cpp b/common/translation.cpp index a1ea14f8b6e..a829f28ce1d 100644 --- a/common/translation.cpp +++ b/common/translation.cpp @@ -227,7 +227,7 @@ bool TranslationManager::openTranslationsFile(File &inFile) { // Then try to open it using the SearchMan. ArchiveMemberList fileList; - SearchMan.listMatchingMembers(fileList, _translationsFileName); + SearchMan.listMatchingMembers(fileList, Common::Path(_translationsFileName, Common::Path::kNoSeparator)); for (ArchiveMemberList::iterator it = fileList.begin(); it != fileList.end(); ++it) { ArchiveMember const &m = **it; SeekableReadStream *const stream = m.createReadStream(); diff --git a/engines/dreamweb/rnca_archive.cpp b/engines/dreamweb/rnca_archive.cpp index d90c15a4dd3..806bc8ef780 100644 --- a/engines/dreamweb/rnca_archive.cpp +++ b/engines/dreamweb/rnca_archive.cpp @@ -59,7 +59,7 @@ RNCAArchive* RNCAArchive::open(Common::SeekableReadStream *stream, DisposeAfterU ptr++; uint32 off = READ_BE_UINT32(ptr); eptr = ptr + 4; - files[fileName] = RNCAFileDescriptor(fileName, off); + files[Common::Path(fileName, Common::Path::kNoSeparator)] = RNCAFileDescriptor(fileName, off); } delete[] metadata; @@ -80,14 +80,14 @@ int RNCAArchive::listMembers(Common::ArchiveMemberList &list) const { } const Common::ArchiveMemberPtr RNCAArchive::getMember(const Common::Path &path) const { - Common::String translated = translatePath(path); + Common::Path translated = translatePath(path); if (!_files.contains(translated)) return nullptr; return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(_files.getVal(translated)._fileName, *this)); } -Common::SharedArchiveContents RNCAArchive::readContentsForPath(const Common::String& translated) const { +Common::SharedArchiveContents RNCAArchive::readContentsForPath(const Common::Path &translated) const { if (!_files.contains(translated)) return Common::SharedArchiveContents(); const RNCAFileDescriptor& desc = _files.getVal(translated); diff --git a/engines/dreamweb/rnca_archive.h b/engines/dreamweb/rnca_archive.h index e808f8d6972..090a1158aa3 100644 --- a/engines/dreamweb/rnca_archive.h +++ b/engines/dreamweb/rnca_archive.h @@ -34,7 +34,7 @@ public: bool hasFile(const Common::Path &path) const override; int listMembers(Common::ArchiveMemberList&) const override; const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override; - Common::SharedArchiveContents readContentsForPath(const Common::String& translated) const override; + Common::SharedArchiveContents readContentsForPath(const Common::Path &translated) const override; static RNCAArchive* open(Common::SeekableReadStream *stream, DisposeAfterUse::Flag dispose = DisposeAfterUse::NO); @@ -53,7 +53,7 @@ private: RNCAFileDescriptor() : _fileDataOffset(0) {} }; - typedef Common::HashMap FileMap; + typedef Common::HashMap FileMap; RNCAArchive(FileMap files, Common::SeekableReadStream *stream, DisposeAfterUse::Flag dispose) : _files(files), _stream(stream, dispose) { diff --git a/engines/mads/mps_installer.cpp b/engines/mads/mps_installer.cpp index 06d52e1bbf0..c640c608faf 100644 --- a/engines/mads/mps_installer.cpp +++ b/engines/mads/mps_installer.cpp @@ -76,14 +76,14 @@ int MpsInstaller::listMembers(Common::ArchiveMemberList &list) const { } const Common::ArchiveMemberPtr MpsInstaller::getMember(const Common::Path &path) const { - Common::String translated = translatePath(path); + Common::Path translated = translatePath(path); if (!_files.contains(translated)) return nullptr; return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(_files.getVal(translated)._fileName, *this)); } -Common::SharedArchiveContents MpsInstaller::readContentsForPath(const Common::String& translated) const { +Common::SharedArchiveContents MpsInstaller::readContentsForPath(const Common::Path &translated) const { if (!_files.contains(translated)) return Common::SharedArchiveContents(); FileDescriptor desc = _files.getVal(translated); diff --git a/engines/mads/mps_installer.h b/engines/mads/mps_installer.h index 487ffa076c1..46cef05d95e 100644 --- a/engines/mads/mps_installer.h +++ b/engines/mads/mps_installer.h @@ -33,11 +33,11 @@ namespace MADS { class MpsInstaller : public Common::MemcachingCaseInsensitiveArchive { public: bool hasFile(const Common::Path &path) const override; - int listMembers(Common::ArchiveMemberList&) const override; + int listMembers(Common::ArchiveMemberList &) const override; const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override; - Common::SharedArchiveContents readContentsForPath(const Common::String& translatedPath) const override; + Common::SharedArchiveContents readContentsForPath(const Common::Path &translatedPath) const override; - static MpsInstaller* open(const Common::Path& baseName); + static MpsInstaller* open(const Common::Path &baseName); private: // Similar to FileDescriptionBin but in native-endian and native strings. @@ -73,7 +73,7 @@ private: friend class MpsInstaller; }; - typedef Common::HashMap FileMap; + typedef Common::HashMap FileMap; MpsInstaller(const FileMap& files, const Common::Path& baseName) : _files(files), _baseName(baseName) {} diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp index 76b2dd71e37..561f2caa225 100644 --- a/engines/saga/saga.cpp +++ b/engines/saga/saga.cpp @@ -349,12 +349,12 @@ Common::Error SagaEngine::run() { setTotalPlayTime(0); if (getFeatures() & GF_INSTALLER) { - Common::Array filenames; + Common::Array filenames; for (const ADGameFileDescription *gameArchiveDescription = getArchivesDescriptions(); gameArchiveDescription->fileName; gameArchiveDescription++) filenames.push_back(gameArchiveDescription->fileName); Common::Archive *archive = nullptr; - if (filenames.size() == 1 && filenames[0].hasSuffix(".exe")) + if (filenames.size() == 1 && filenames[0].baseName().hasSuffix(".exe")) archive = Common::makeZipArchive(filenames[0], true); else archive = Common::makeArjArchive(filenames, true); diff --git a/engines/sci/resource/resource.cpp b/engines/sci/resource/resource.cpp index 59ae2119701..c328004ffdb 100644 --- a/engines/sci/resource/resource.cpp +++ b/engines/sci/resource/resource.cpp @@ -655,12 +655,13 @@ int ResourceManager::addAppropriateSources() { #endif } else if (Common::MacResManager::exists("Data1")) { // Mac SCI1.1+ file naming scheme - Common::StringArray files; + Common::Array files; Common::MacResManager::listFiles(files, "Data#"); Common::MacResManager::listFiles(files, "Data##"); - for (Common::StringArray::const_iterator x = files.begin(); x != files.end(); ++x) { - addSource(new MacResourceForkResourceSource(*x, atoi(x->c_str() + 4))); + for (Common::Array::const_iterator x = files.begin(); x != files.end(); ++x) { + Common::String path(x->toString()); + addSource(new MacResourceForkResourceSource(path, atoi(path.c_str() + 4))); } #ifdef ENABLE_SCI32