aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Schickel2016-03-01 19:14:50 +0100
committerJohannes Schickel2016-03-01 19:16:10 +0100
commit91b5c5a413af1e2a61d3f8457deff54a75a8d754 (patch)
tree11715d349c45f973208dde5c211c86381dbca690
parent1ae2e0594d45a43c5502e3b8e8b68aec26b64d7f (diff)
downloadscummvm-rg350-91b5c5a413af1e2a61d3f8457deff54a75a8d754.tar.gz
scummvm-rg350-91b5c5a413af1e2a61d3f8457deff54a75a8d754.tar.bz2
scummvm-rg350-91b5c5a413af1e2a61d3f8457deff54a75a8d754.zip
COMMON: Add a method to list files to MacResManager.
-rw-r--r--common/macresman.cpp111
-rw-r--r--common/macresman.h18
2 files changed, 129 insertions, 0 deletions
diff --git a/common/macresman.cpp b/common/macresman.cpp
index d83bde8fd8..e28bd963df 100644
--- a/common/macresman.cpp
+++ b/common/macresman.cpp
@@ -29,6 +29,7 @@
#include "common/md5.h"
#include "common/substream.h"
#include "common/textconsole.h"
+#include "common/archive.h"
#ifdef MACOSX
#include "common/config-manager.h"
@@ -261,6 +262,76 @@ bool MacResManager::exists(const String &fileName) {
return false;
}
+void MacResManager::listFiles(Array<String> &files, const String &pattern) {
+ // Base names discovered so far.
+ typedef HashMap<String, bool, IgnoreCase_Hash, IgnoreCase_EqualTo> 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, constructAppleDoubleName(pattern));
+
+ for (ArchiveMemberList::const_iterator i = memberList.begin(), end = memberList.end(); i != end; ++i) {
+ String filename = (*i)->getName();
+
+ // For raw resource forks and MacBinary files we strip the extension
+ // here to obtain a valid base name.
+ int lastDotPos = filename.size() - 1;
+ for (; lastDotPos >= 0; --lastDotPos) {
+ if (filename[lastDotPos] == '.') {
+ break;
+ }
+ }
+
+ if (lastDotPos != -1) {
+ const char *extension = filename.c_str() + lastDotPos + 1;
+ bool removeExtension = false;
+
+ // TODO: Should we really keep filenames suggesting raw resource
+ // forks or MacBinary files but not being such around? This might
+ // depend on the pattern the client requests...
+ if (!scumm_stricmp(extension, "rsrc")) {
+ SeekableReadStream *stream = (*i)->createReadStream();
+ removeExtension = stream && isRawFork(*stream);
+ delete stream;
+ } else if (!scumm_stricmp(extension, "bin")) {
+ SeekableReadStream *stream = (*i)->createReadStream();
+ removeExtension = stream && isMacBinary(*stream);
+ delete stream;
+ }
+
+ if (removeExtension) {
+ filename.erase(lastDotPos);
+ }
+ }
+
+ // Strip AppleDouble '._' prefix if applicable.
+ bool isAppleDoubleName = false;
+ const String filenameAppleDoubleStripped = disassembleAppleDoubleName(filename, &isAppleDoubleName);
+
+ if (isAppleDoubleName) {
+ SeekableReadStream *stream = (*i)->createReadStream();
+ if (stream->readUint32BE() == 0x00051607) {
+ filename = filenameAppleDoubleStripped;
+ }
+ // TODO: Should we really keep filenames suggesting AppleDouble
+ // but not being AppleDouble around? This might depend on the
+ // pattern the client requests...
+ delete stream;
+ }
+
+ baseNames[filename] = true;
+ }
+
+ // Append resulting base names to list to indicate found files.
+ for (BaseNameSet::const_iterator i = baseNames.begin(), end = baseNames.end(); i != end; ++i) {
+ files.push_back(i->_key);
+ }
+}
+
bool MacResManager::loadFromAppleDouble(SeekableReadStream &stream) {
if (stream.readUint32BE() != 0x00051607) // tag
return false;
@@ -314,6 +385,18 @@ bool MacResManager::isMacBinary(SeekableReadStream &stream) {
return true;
}
+bool MacResManager::isRawFork(SeekableReadStream &stream) {
+ // TODO: Is there a better way to detect whether this is a raw fork?
+ const uint32 dataOffset = stream.readUint32BE();
+ const uint32 mapOffset = stream.readUint32BE();
+ const uint32 dataLength = stream.readUint32BE();
+ const uint32 mapLength = stream.readUint32BE();
+
+ return !stream.eos() && !stream.err()
+ && dataOffset < (uint32)stream.size() && dataOffset + dataLength <= (uint32)stream.size()
+ && mapOffset < (uint32)stream.size() && mapOffset + mapLength <= (uint32)stream.size();
+}
+
bool MacResManager::loadFromMacBinary(SeekableReadStream &stream) {
byte infoHeader[MBI_INFOHDR];
stream.read(infoHeader, MBI_INFOHDR);
@@ -592,4 +675,32 @@ String MacResManager::constructAppleDoubleName(String name) {
return name;
}
+String MacResManager::disassembleAppleDoubleName(String name, bool *isAppleDouble) {
+ if (isAppleDouble) {
+ *isAppleDouble = false;
+ }
+
+ // Remove "._" before the last portion of a path name.
+ for (int i = name.size() - 1; i >= 0; --i) {
+ if (i == 0) {
+ if (name.size() > 2 && name[0] == '.' && name[1] == '_') {
+ name.erase(0, 2);
+ if (isAppleDouble) {
+ *isAppleDouble = true;
+ }
+ }
+ } else if (name[i] == '/') {
+ if ((uint)(i + 2) < name.size() && name[i + 1] == '.' && name[i + 2] == '_') {
+ name.erase(i + 1, 2);
+ if (isAppleDouble) {
+ *isAppleDouble = true;
+ }
+ }
+ break;
+ }
+ }
+
+ return name;
+}
+
} // End of namespace Common
diff --git a/common/macresman.h b/common/macresman.h
index 43ec8d8e2c..5cc2542433 100644
--- a/common/macresman.h
+++ b/common/macresman.h
@@ -82,6 +82,16 @@ public:
static bool exists(const String &fileName);
/**
+ * List all filenames matching pattern for opening with open().
+ *
+ * @param files Array containing all matching filenames discovered. Only
+ * adds to the list.
+ * @param pattern Pattern to match against. Taking String::matchPattern's
+ * format.
+ */
+ static void listFiles(Array<String> &files, const String &pattern);
+
+ /**
* Close the Mac data/resource fork pair.
*/
void close();
@@ -176,6 +186,7 @@ private:
bool loadFromAppleDouble(SeekableReadStream &stream);
static String constructAppleDoubleName(String name);
+ static String disassembleAppleDoubleName(String name, bool *isAppleDouble);
/**
* Check if the given stream is in the MacBinary format.
@@ -183,6 +194,13 @@ private:
*/
static bool isMacBinary(SeekableReadStream &stream);
+ /**
+ * Do a sanity check whether the given stream is a raw resource fork.
+ *
+ * @param stream Stream object to check. Will not preserve its position.
+ */
+ static bool isRawFork(SeekableReadStream &stream);
+
enum {
kResForkNone = 0,
kResForkRaw,