diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/advancedDetector.cpp | 2 | ||||
-rw-r--r-- | common/config-manager.cpp | 381 | ||||
-rw-r--r-- | common/config-manager.h | 12 | ||||
-rw-r--r-- | common/file.cpp | 29 | ||||
-rw-r--r-- | common/file.h | 6 | ||||
-rw-r--r-- | common/fs.cpp | 41 | ||||
-rw-r--r-- | common/fs.h | 67 | ||||
-rw-r--r-- | common/hashmap.h | 10 | ||||
-rw-r--r-- | common/savefile.h | 17 | ||||
-rw-r--r-- | common/stream.h | 16 | ||||
-rw-r--r-- | common/system.cpp | 60 | ||||
-rw-r--r-- | common/system.h | 19 | ||||
-rw-r--r-- | common/unarj.cpp | 7 |
13 files changed, 372 insertions, 295 deletions
diff --git a/common/advancedDetector.cpp b/common/advancedDetector.cpp index 8bd019018a..522b24163e 100644 --- a/common/advancedDetector.cpp +++ b/common/advancedDetector.cpp @@ -94,6 +94,8 @@ static void upgradeTargetIfNecessary(const Common::ADParams ¶ms) { warning("Target upgraded from %s to %s", o->from, o->to); + // WORKAROUND: Fix for bug #1719463: "DETECTOR: Launching + // undefined target adds launcher entry" if (ConfMan.hasKey("id_came_from_command_line")) { warning("Target came from command line. Skipping save"); } else { diff --git a/common/config-manager.cpp b/common/config-manager.cpp index 044474a927..138fcc201f 100644 --- a/common/config-manager.cpp +++ b/common/config-manager.cpp @@ -23,38 +23,13 @@ * */ -#if defined(WIN32) -#include <windows.h> -// winnt.h defines ARRAYSIZE, but we want our own one... -#undef ARRAYSIZE -#endif - #include "common/config-manager.h" #include "common/file.h" #include "common/util.h" +#include "common/system.h" DECLARE_SINGLETON(Common::ConfigManager); -#ifdef __PLAYSTATION2__ -#include "backends/platform/ps2/systemps2.h" -#endif - -#ifdef IPHONE -#include "backends/platform/iphone/osys_iphone.h" -#endif - -#if defined(UNIX) -#ifdef MACOSX -#define DEFAULT_CONFIG_FILE "Library/Preferences/ScummVM Preferences" -#else -#define DEFAULT_CONFIG_FILE ".scummvmrc" -#endif -#else -#define DEFAULT_CONFIG_FILE "scummvm.ini" -#endif - -#define MAXLINELEN 256 - static bool isValidDomainName(const Common::String &domName) { const char *p = domName.c_str(); while (*p && (isalnum(*p) || *p == '-' || *p == '_')) @@ -85,238 +60,180 @@ ConfigManager::ConfigManager() void ConfigManager::loadDefaultConfigFile() { - char configFile[MAXPATHLEN]; - // GP2X is Linux based but Home dir can be read only so do not use it and put the config in the executable dir. - // On the iPhone, the home dir of the user when you launch the app from the Springboard, is /. Which we don't want. -#if defined(UNIX) && !defined(GP2X) && !defined(IPHONE) - const char *home = getenv("HOME"); - if (home != NULL && strlen(home) < MAXPATHLEN) - snprintf(configFile, MAXPATHLEN, "%s/%s", home, DEFAULT_CONFIG_FILE); - else - strcpy(configFile, DEFAULT_CONFIG_FILE); -#else - #if defined (WIN32) && !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) - OSVERSIONINFO win32OsVersion; - ZeroMemory(&win32OsVersion, sizeof(OSVERSIONINFO)); - win32OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&win32OsVersion); - // Check for non-9X version of Windows. - if (win32OsVersion.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) { - // Use the Application Data directory of the user profile. - if (win32OsVersion.dwMajorVersion >= 5) { - if (!GetEnvironmentVariable("APPDATA", configFile, sizeof(configFile))) - error("Unable to access application data directory"); - } else { - if (!GetEnvironmentVariable("USERPROFILE", configFile, sizeof(configFile))) - error("Unable to access user profile directory"); + // Open the default config file + SeekableReadStream *stream = g_system->openConfigFileForReading(); + _filename.clear(); // clear the filename to indicate that we are using the default config file - strcat(configFile, "\\Application Data"); - CreateDirectory(configFile, NULL); - } - - strcat(configFile, "\\ScummVM"); - CreateDirectory(configFile, NULL); - strcat(configFile, "\\" DEFAULT_CONFIG_FILE); - - if (fopen(configFile, "r") == NULL) { - // Check windows directory - char oldConfigFile[MAXPATHLEN]; - GetWindowsDirectory(oldConfigFile, MAXPATHLEN); - strcat(oldConfigFile, "\\" DEFAULT_CONFIG_FILE); - if (fopen(oldConfigFile, "r")) { - printf("The default location of the config file (scummvm.ini) in ScummVM has changed,\n"); - printf("under Windows NT4/2000/XP/Vista. You may want to consider moving your config\n"); - printf("file from the old default location:\n"); - printf("%s\n", oldConfigFile); - printf("to the new default location:\n"); - printf("%s\n\n", configFile); - strcpy(configFile, oldConfigFile); - } - } - } else { - // Check windows directory - GetWindowsDirectory(configFile, MAXPATHLEN); - strcat(configFile, "\\" DEFAULT_CONFIG_FILE); - } - - #elif defined(PALMOS_MODE) - strcpy(configFile,"/PALM/Programs/ScummVM/" DEFAULT_CONFIG_FILE); - #elif defined(IPHONE) - strcpy(configFile, OSystem_IPHONE::getConfigPath()); - #elif defined(__PLAYSTATION2__) - ((OSystem_PS2*)g_system)->makeConfigPath(configFile); - #elif defined(__PSP__) - strcpy(configFile, "ms0:/" DEFAULT_CONFIG_FILE); - #elif defined (__SYMBIAN32__) - strcpy(configFile, Symbian::GetExecutablePath()); - strcat(configFile, DEFAULT_CONFIG_FILE); - #else - strcpy(configFile, DEFAULT_CONFIG_FILE); - #endif -#endif + // ... load it, if available ... + if (stream) + loadFromStream(*stream); + + // ... and close it again. + delete stream; - loadConfigFile(configFile); flushToDisk(); } void ConfigManager::loadConfigFile(const String &filename) { - _appDomain.clear(); - _gameDomains.clear(); - _transientDomain.clear(); - _filename = filename; - _domainSaveOrder.clear(); - loadFile(_filename); - printf("Using configuration file: %s\n", _filename.c_str()); -} -void ConfigManager::loadFile(const String &filename) { File cfg_file; - if (!cfg_file.open(filename)) { printf("Creating configuration file: %s\n", filename.c_str()); } else { - String domain; - String comment; - int lineno = 0; - - // TODO: Detect if a domain occurs multiple times (or likewise, if - // a key occurs multiple times inside one domain). - - while (!cfg_file.eof() && !cfg_file.ioFailed()) { - lineno++; - - // Read a line - String line; - while (line.lastChar() != '\n') { - char buf[MAXLINELEN]; - if (!cfg_file.readLine_NEW(buf, MAXLINELEN)) - break; - line += buf; + printf("Using configuration file: %s\n", _filename.c_str()); + loadFromStream(cfg_file); + } +} + +void ConfigManager::loadFromStream(SeekableReadStream &stream) { + String domain; + String comment; + int lineno = 0; + + _appDomain.clear(); + _gameDomains.clear(); + _transientDomain.clear(); + _domainSaveOrder.clear(); + + // TODO: Detect if a domain occurs multiple times (or likewise, if + // a key occurs multiple times inside one domain). + + while (!stream.eos() && !stream.ioFailed()) { + lineno++; + + // Read a line + String line; + while (line.lastChar() != '\n') { + char buf[256]; + if (!stream.readLine_NEW(buf, 256)) + break; + line += buf; + } + + if (line.size() == 0) { + // Do nothing + } else if (line[0] == '#') { + // Accumulate comments here. Once we encounter either the start + // of a new domain, or a key-value-pair, we associate the value + // of the 'comment' variable with that entity. + comment += line; + } else if (line[0] == '[') { + // It's a new domain which begins here. + const char *p = line.c_str() + 1; + // Get the domain name, and check whether it's valid (that + // is, verify that it only consists of alphanumerics, + // dashes and underscores). + while (*p && (isalnum(*p) || *p == '-' || *p == '_')) + p++; + + if (*p == '\0') + error("Config file buggy: missing ] in line %d", lineno); + else if (*p != ']') + error("Config file buggy: Invalid character '%c' occured in section name in line %d", *p, lineno); + + domain = String(line.c_str() + 1, p); + + // Store domain comment + if (domain == kApplicationDomain) { + _appDomain.setDomainComment(comment); + } else { + _gameDomains[domain].setDomainComment(comment); } + comment.clear(); - if (line.size() == 0) { - // Do nothing - } else if (line[0] == '#') { - // Accumulate comments here. Once we encounter either the start - // of a new domain, or a key-value-pair, we associate the value - // of the 'comment' variable with that entity. - comment += line; - } else if (line[0] == '[') { - // It's a new domain which begins here. - const char *p = line.c_str() + 1; - // Get the domain name, and check whether it's valid (that - // is, verify that it only consists of alphanumerics, - // dashes and underscores). - while (*p && (isalnum(*p) || *p == '-' || *p == '_')) - p++; - - switch (*p) { - case '\0': - error("Config file buggy: missing ] in line %d", lineno); - break; - case ']': - domain = String(line.c_str() + 1, p - (line.c_str() + 1)); - //domain = String(line.c_str() + 1, p); // TODO: Pending Common::String changes - break; - default: - error("Config file buggy: Invalid character '%c' occured in domain name in line %d", *p, lineno); - } - - // Store domain comment - if (domain == kApplicationDomain) { - _appDomain.setDomainComment(comment); - } else { - _gameDomains[domain].setDomainComment(comment); - } - comment.clear(); - - _domainSaveOrder.push_back(domain); + _domainSaveOrder.push_back(domain); + } else { + // This line should be a line with a 'key=value' pair, or an empty one. + + // Skip leading whitespaces + const char *t = line.c_str(); + while (isspace(*t)) + t++; + + // Skip empty lines / lines with only whitespace + if (*t == 0) + continue; + + // If no domain has been set, this config file is invalid! + if (domain.empty()) { + error("Config file buggy: Key/value pair found outside a domain in line %d", lineno); + } + + // Split string at '=' into 'key' and 'value'. First, find the "=" delimeter. + const char *p = strchr(t, '='); + if (!p) + error("Config file buggy: Junk found in line line %d: '%s'", lineno, t); + + // Extract the key/value pair + String key(t, p); + String value(p + 1); + + // Trim of spaces + key.trim(); + value.trim(); + + // Finally, store the key/value pair in the active domain + set(key, value, domain); + + // Store comment + if (domain == kApplicationDomain) { + _appDomain.setKVComment(key, comment); } else { - // This line should be a line with a 'key=value' pair, or an empty one. - - // Skip leading whitespaces - const char *t = line.c_str(); - while (isspace(*t)) - t++; - - // Skip empty lines / lines with only whitespace - if (*t == 0) - continue; - - // If no domain has been set, this config file is invalid! - if (domain.empty()) { - error("Config file buggy: Key/value pair found outside a domain in line %d", lineno); - } - - // Split string at '=' into 'key' and 'value'. First, find the "=" delimeter. - const char *p = strchr(t, '='); - if (!p) - error("Config file buggy: Junk found in line line %d: '%s'", lineno, t); - - // Trim spaces before the '=' to obtain the key - const char *p2 = p; - while (p2 > t && isspace(*(p2-1))) - p2--; - String key(t, p2 - t); - - // Skip spaces after the '=' - t = p + 1; - while (isspace(*t)) - t++; - - // Trim trailing spaces - p2 = t + strlen(t); - while (p2 > t && isspace(*(p2-1))) - p2--; - - String value(t, p2 - t); - - // Finally, store the key/value pair in the active domain - set(key, value, domain); - - // Store comment - if (domain == kApplicationDomain) { - _appDomain.setKVComment(key, comment); - } else { - _gameDomains[domain].setKVComment(key, comment); - } - comment.clear(); + _gameDomains[domain].setKVComment(key, comment); } + comment.clear(); } } } void ConfigManager::flushToDisk() { #ifndef __DC__ - DumpFile cfg_file; + WriteStream *stream; - if (!cfg_file.open(_filename)) { - warning("Unable to write configuration file: %s", _filename.c_str()); + if (_filename.empty()) { + // Write to the default config file + stream = g_system->openConfigFileForWriting(); + if (!stream) // If writing to the config file is not possible, do nothing + return; } else { - // First write the domains in _domainSaveOrder, in that order. - // Note: It's possible for _domainSaveOrder to list domains which - // are not present anymore. - StringList::const_iterator i; - for (i = _domainSaveOrder.begin(); i != _domainSaveOrder.end(); ++i) { - if (kApplicationDomain == *i) { - writeDomain(cfg_file, *i, _appDomain); - } else if (_gameDomains.contains(*i)) { - writeDomain(cfg_file, *i, _gameDomains[*i]); - } + DumpFile *dump = new DumpFile(); + assert(dump); + + if (!dump->open(_filename)) { + warning("Unable to write configuration file: %s", _filename.c_str()); + delete dump; + return; + } + + stream = dump; + } + + // First write the domains in _domainSaveOrder, in that order. + // Note: It's possible for _domainSaveOrder to list domains which + // are not present anymore. + StringList::const_iterator i; + for (i = _domainSaveOrder.begin(); i != _domainSaveOrder.end(); ++i) { + if (kApplicationDomain == *i) { + writeDomain(*stream, *i, _appDomain); + } else if (_gameDomains.contains(*i)) { + writeDomain(*stream, *i, _gameDomains[*i]); } + } - DomainMap::const_iterator d; + DomainMap::const_iterator d; - // Now write the domains which haven't been written yet - if (find(_domainSaveOrder.begin(), _domainSaveOrder.end(), kApplicationDomain) == _domainSaveOrder.end()) - writeDomain(cfg_file, kApplicationDomain, _appDomain); - for (d = _gameDomains.begin(); d != _gameDomains.end(); ++d) { - if (find(_domainSaveOrder.begin(), _domainSaveOrder.end(), d->_key) == _domainSaveOrder.end()) - writeDomain(cfg_file, d->_key, d->_value); - } + // Now write the domains which haven't been written yet + if (find(_domainSaveOrder.begin(), _domainSaveOrder.end(), kApplicationDomain) == _domainSaveOrder.end()) + writeDomain(*stream, kApplicationDomain, _appDomain); + for (d = _gameDomains.begin(); d != _gameDomains.end(); ++d) { + if (find(_domainSaveOrder.begin(), _domainSaveOrder.end(), d->_key) == _domainSaveOrder.end()) + writeDomain(*stream, d->_key, d->_value); } + + delete stream; + #endif // !__DC__ } @@ -324,6 +241,12 @@ void ConfigManager::writeDomain(WriteStream &stream, const String &name, const D if (domain.empty()) return; // Don't bother writing empty domains. + // WORKAROUND: Fix for bug #1972625 "ALL: On-the-fly targets are + // written to the config file": Do not save domains that came from + // the command line + if (domain.contains("id_came_from_command_line")) + return; + String comment; // Write domain comment (if any) diff --git a/common/config-manager.h b/common/config-manager.h index bebb59b539..9e5b88a073 100644 --- a/common/config-manager.h +++ b/common/config-manager.h @@ -36,7 +36,7 @@ namespace Common { class WriteStream; - +class SeekableReadStream; /** * The (singleton) configuration manager, used to query & set configuration @@ -144,19 +144,11 @@ public: bool hasGameDomain(const String &domName) const; const DomainMap & getGameDomains() const { return _gameDomains; } -/* - TODO: Callback/change notification system - typedef void (*ConfigCallback)(const ConstString &key, void *refCon); - - void registerCallback(ConfigCallback cfgc, void *refCon, const ConstString &key = String::emptyString) - void unregisterCallback(ConfigCallback cfgc, const ConstString &key = String::emptyString) -*/ - private: friend class Singleton<SingletonBaseType>; ConfigManager(); - void loadFile(const String &filename); + void loadFromStream(SeekableReadStream &stream); void writeDomain(WriteStream &stream, const String &name, const Domain &domain); Domain _transientDomain; diff --git a/common/file.cpp b/common/file.cpp index 5b465b5e01..fb837b9499 100644 --- a/common/file.cpp +++ b/common/file.cpp @@ -494,6 +494,28 @@ bool DumpFile::open(const String &filename) { return _handle != NULL; } +bool DumpFile::open(const FilesystemNode &node) { + assert(!_handle); + + if (node.isDirectory()) { + warning("File::open: Trying to open a FilesystemNode which is a directory"); + return false; + } /*else if (!node.isReadable() && mode == kFileReadMode) { + warning("File::open: Trying to open an unreadable FilesystemNode object for reading"); + return false; + } else if (!node.isWritable() && mode == kFileWriteMode) { + warning("File::open: Trying to open an unwritable FilesystemNode object for writing"); + return false; + }*/ + + _handle = fopen(node.getPath().c_str(), "wb"); + + if (_handle == NULL) + debug(2, "File %s not found", node.getName().c_str()); + + return _handle != NULL; +} + void DumpFile::close() { if (_handle) fclose((FILE *)_handle); @@ -528,5 +550,12 @@ uint32 DumpFile::write(const void *ptr, uint32 len) { return (uint32)fwrite(ptr, 1, len, (FILE *)_handle); } +void DumpFile::flush() { + assert(_handle); + // TODO: Should check the return value of fflush, and if it is non-zero, + // check errno and set an error flag. + fflush((FILE *)_handle); +} + } // End of namespace Common diff --git a/common/file.h b/common/file.h index 3c2520b07c..3adeb6ff36 100644 --- a/common/file.h +++ b/common/file.h @@ -125,7 +125,7 @@ public: virtual ~DumpFile(); virtual bool open(const String &filename); - //virtual bool open(const FilesystemNode &node); + virtual bool open(const FilesystemNode &node); virtual void close(); @@ -148,7 +148,9 @@ public: */ virtual bool eof() const; - uint32 write(const void *dataPtr, uint32 dataSize); + virtual uint32 write(const void *dataPtr, uint32 dataSize); + + virtual void flush(); }; diff --git a/common/fs.cpp b/common/fs.cpp index 7d803dacd4..3f585c6038 100644 --- a/common/fs.cpp +++ b/common/fs.cpp @@ -23,10 +23,13 @@ */ #include "common/util.h" +#include "common/file.h" #include "common/system.h" #include "backends/fs/abstract-fs.h" #include "backends/fs/fs-factory.h" +//namespace Common { + FilesystemNode::FilesystemNode() { } @@ -170,3 +173,41 @@ bool FilesystemNode::lookupFile(FSList &results, const Common::String &p, bool h return !results.empty(); } + +Common::SeekableReadStream *FilesystemNode::openForReading() { + if (_realNode == 0) + return 0; +#if 0 + return _realNode->openForReading(); +#else + // FIXME: Until we support openForReading in AbstractFilesystemNode, + // we just use Common::File. + Common::File *confFile = new Common::File(); + assert(confFile); + if (!confFile->open(*this)) { + delete confFile; + confFile = 0; + } + return confFile; +#endif +} + +Common::WriteStream *FilesystemNode::openForWriting() { + if (_realNode == 0) + return 0; +#if 0 + return _realNode->openForWriting(); +#else + // FIXME: Until we support openForWriting in AbstractFilesystemNode, + // we just use Common::DumpFile. + Common::DumpFile *confFile = new Common::DumpFile(); + assert(confFile); + if (!confFile->open(*this)) { + delete confFile; + confFile = 0; + } + return confFile; +#endif +} + +//} // End of namespace Common diff --git a/common/fs.h b/common/fs.h index ed7355cc00..972e0d86af 100644 --- a/common/fs.h +++ b/common/fs.h @@ -29,10 +29,18 @@ #include "common/ptr.h" #include "common/str.h" +class AbstractFilesystemNode; + +namespace Common { + class SeekableReadStream; + class WriteStream; +} + //namespace Common { class FilesystemNode; -class AbstractFilesystemNode; +//class SeekableReadStream; +//class WriteStream; /** * List of multiple file system nodes. E.g. the contents of a given directory. @@ -49,22 +57,6 @@ class FSList : public Common::Array<FilesystemNode> {}; * To this end, we abstract away from paths; implementations can be based on * paths (and it's left to them whether / or \ or : is the path separator :-); * but it is also possible to use inodes or vrefs (MacOS 9) or anything else. - * - * NOTE: Backends still have to provide a way to extract a path from a FSIntern - * - * You may ask now: "isn't this cheating? Why do we go through all this when we use - * a path in the end anyway?!?". - * Well, for once as long as we don't provide our own file open/read/write API, we - * still have to use fopen(). Since all our targets already support fopen(), it should - * be possible to get a fopen() compatible string for any file system node. - * - * Secondly, with this abstraction layer, we still avoid a lot of complications based on - * differences in FS roots, different path separators, or even systems with no real - * paths (MacOS 9 doesn't even have the notion of a "current directory"). - * And if we ever want to support devices with no FS in the classical sense (Palm...), - * we can build upon this. - * - * This class acts as a wrapper around the AbstractFilesystemNode class defined in backends/fs. */ class FilesystemNode { private: @@ -108,9 +100,9 @@ public: bool operator<(const FilesystemNode& node) const; /** - * Indicates whether the object referred by this path exists in the filesystem or not. + * Indicates whether the object referred by this node exists in the filesystem or not. * - * @return bool true if the path exists, false otherwise. + * @return bool true if the node exists, false otherwise. */ virtual bool exists() const; @@ -168,7 +160,7 @@ public: FilesystemNode getParent() const; /** - * Indicates whether the path refers to a directory or not. + * Indicates whether the node refers to a directory or not. * * @todo Currently we assume that a node that is not a directory * automatically is a file (ignoring things like symlinks or pipes). @@ -179,28 +171,28 @@ public: virtual bool isDirectory() const; /** - * Indicates whether the object referred by this path can be read from or not. + * Indicates whether the object referred by this node can be read from or not. * - * If the path refers to a directory, readability implies being able to read + * If the node refers to a directory, readability implies being able to read * and list the directory entries. * - * If the path refers to a file, readability implies being able to read the + * If the node refers to a file, readability implies being able to read the * contents of the file. * - * @return bool true if the object can be read, false otherwise. + * @return true if the object can be read, false otherwise. */ virtual bool isReadable() const; /** - * Indicates whether the object referred by this path can be written to or not. + * Indicates whether the object referred by this node can be written to or not. * - * If the path refers to a directory, writability implies being able to modify + * If the node refers to a directory, writability implies being able to modify * the directory entry (i.e. rename the directory, remove it or write files inside of it). * - * If the path refers to a file, writability implies being able to write data + * If the node refers to a file, writability implies being able to write data * to the file. * - * @return bool true if the object can be written to, false otherwise. + * @return true if the object can be written to, false otherwise. */ virtual bool isWritable() const; @@ -221,6 +213,25 @@ public: * @return true if matches could be found, false otherwise. */ virtual bool lookupFile(FSList &results, const Common::String &pattern, bool hidden, bool exhaustive, int depth = -1) const; + + + /** + * Creates a SeekableReadStream instance corresponding to the file + * referred by this node. This assumes that the node actually refers + * to a readable file. If this is not the case, 0 is returned. + * + * @return pointer to the stream object, 0 in case of a failure + */ + virtual Common::SeekableReadStream *openForReading(); + + /** + * Creates a WriteStream instance corresponding to the file + * referred by this node. This assumes that the node actually refers + * to a readable file. If this is not the case, 0 is returned. + * + * @return pointer to the stream object, 0 in case of a failure + */ + virtual Common::WriteStream *openForWriting(); }; //} // End of namespace Common diff --git a/common/hashmap.h b/common/hashmap.h index ab6e737d74..69f367de97 100644 --- a/common/hashmap.h +++ b/common/hashmap.h @@ -58,21 +58,19 @@ #include "common/str.h" #include "common/util.h" -// FIXME: Since this define is very system dependant, -// it should be moved to the appropriate H file instead. -// Portdefs might be a good location for example -#if !defined(__SYMBIAN32__) #define USE_HASHMAP_MEMORY_POOL -#endif - #ifdef USE_HASHMAP_MEMORY_POOL #include "common/memorypool.h" // FIXME: we sadly can't assume standard C++ to be present // on every system we support, so we should get rid of this. // The solution should be to write a simple placement new // on our own. + +// Symbian does not have <new> but the new operator +#if !defined(__SYMBIAN32__) #include <new> #endif +#endif namespace Common { diff --git a/common/savefile.h b/common/savefile.h index f30ddfc160..d44f946d48 100644 --- a/common/savefile.h +++ b/common/savefile.h @@ -39,27 +39,14 @@ namespace Common { * That typically means "save games", but also includes things like the * IQ points in Indy3. */ -class InSaveFile : public SeekableReadStream {}; +typedef SeekableReadStream InSaveFile; /** * A class which allows game engines to save game state data. * That typically means "save games", but also includes things like the * IQ points in Indy3. */ -class OutSaveFile : public WriteStream { -public: - /** - * Close this savefile, to be called right before destruction of this - * savefile. The idea is that this ways, I/O errors that occur - * during closing/flushing of the file can still be handled by the - * game engine. - * - * By default, this just flushes the stream. - */ - virtual void finalize() { - flush(); - } -}; +typedef WriteStream OutSaveFile; /** diff --git a/common/stream.h b/common/stream.h index d07579c2d1..01a946e685 100644 --- a/common/stream.h +++ b/common/stream.h @@ -78,6 +78,22 @@ public: */ virtual void flush() {} + /** + * Finalize and close this stream. To be called right before this + * stream instance is deleted. The goal here is to enable calling + * code to detect and handle I/O errors which might occur when + * closing (and this flushing, if buffered) the stream. + * + * After this method has been called, no further writes may be + * peformed on the stream. Calling ioFailed() is allowed. + * + * By default, this just flushes the stream. + */ + virtual void finalize() { + flush(); + } + + // The remaining methods all have default implementations; subclasses // need not (and should not) overload them. diff --git a/common/system.cpp b/common/system.cpp index 8d528258f4..d0548cdd2d 100644 --- a/common/system.cpp +++ b/common/system.cpp @@ -28,12 +28,9 @@ #include "common/config-manager.h" #include "common/system.h" -#include "common/timer.h" -#include "common/util.h" #include "graphics/colormasks.h" #include "gui/message.h" -#include "sound/mixer.h" OSystem *g_system = 0; @@ -121,3 +118,60 @@ void OSystem::clearScreen() { memset(screen->pixels, 0, screen->h * screen->pitch); unlockScreen(); } + + +/* +FIXME: The config file loading code below needs to be cleaned up. + Port specific variants should be pushed into the respective ports. + + Ideally, the default OSystem::openConfigFileForReading/Writing methods + should be removed completely. +*/ + +#include "common/file.h" + +#ifdef __PLAYSTATION2__ +#include "backends/platform/ps2/systemps2.h" +#endif + +#ifdef IPHONE +#include "backends/platform/iphone/osys_iphone.h" +#endif + + +#if defined(UNIX) +#define DEFAULT_CONFIG_FILE ".scummvmrc" +#else +#define DEFAULT_CONFIG_FILE "scummvm.ini" +#endif + +static Common::String getDefaultConfigFileName() { + char configFile[MAXPATHLEN]; +#if defined(PALMOS_MODE) + strcpy(configFile,"/PALM/Programs/ScummVM/" DEFAULT_CONFIG_FILE); +#elif defined(IPHONE) + strcpy(configFile, OSystem_IPHONE::getConfigPath()); +#elif defined(__PLAYSTATION2__) + ((OSystem_PS2*)g_system)->makeConfigPath(configFile); +#elif defined(__PSP__) + strcpy(configFile, "ms0:/" DEFAULT_CONFIG_FILE); +#else + strcpy(configFile, DEFAULT_CONFIG_FILE); +#endif + + return configFile; +} + +Common::SeekableReadStream *OSystem::openConfigFileForReading() { + FilesystemNode file(getDefaultConfigFileName()); + return file.openForReading(); +} + +Common::WriteStream *OSystem::openConfigFileForWriting() { +#ifdef __DC__ + return 0; +#else + FilesystemNode file(getDefaultConfigFileName()); + return file.openForWriting(); +#endif +} diff --git a/common/system.h b/common/system.h index b895a5cfba..501d0802fd 100644 --- a/common/system.h +++ b/common/system.h @@ -44,6 +44,8 @@ namespace Common { class EventManager; class SaveFileManager; class TimerManager; + class SeekableReadStream; + class WriteStream; } class FilesystemFactory; @@ -900,10 +902,25 @@ public: /** * Returns the FilesystemFactory object, depending on the current architecture. * - * @return FilesystemFactory* The specific factory for the current architecture. + * @return the FSNode factory for the current architecture */ virtual FilesystemFactory *getFilesystemFactory() = 0; + /** + * Open the default config file for reading, by returning a suitable + * ReadStream instance. It is the callers responsiblity to delete + * the stream after use. + */ + virtual Common::SeekableReadStream *openConfigFileForReading(); + + /** + * Open the default config file for writing, by returning a suitable + * WriteStream instance. It is the callers responsiblity to delete + * the stream after use. + * + * May return 0 to indicate that writing to config file is not possible. + */ + virtual Common::WriteStream *openConfigFileForWriting(); /** * Return String which is used for backend-specific addition to theme diff --git a/common/unarj.cpp b/common/unarj.cpp index da88c11fc9..9a7766a41f 100644 --- a/common/unarj.cpp +++ b/common/unarj.cpp @@ -75,7 +75,7 @@ static uint32 GetCRC(byte *data, int len) { return CRC ^ 0xFFFFFFFF; } -ArjFile::ArjFile() { +ArjFile::ArjFile() : _uncompressedData(NULL) { InitCRC(); _isOpen = false; _fallBack = false; @@ -256,6 +256,11 @@ bool ArjFile::open(const Common::String &filename) { _compsize = hdr->compSize; _origsize = hdr->origSize; + // FIXME: This hotfix prevents Drascula from leaking memory. + // As far as sanity checks go this is not bad, but the engine should be fixed. + if (_uncompressedData) + free(_uncompressedData); + _uncompressedData = (byte *)malloc(_origsize); _outstream = new MemoryWriteStream(_uncompressedData, _origsize); |