diff options
author | Matthew Hoops | 2011-06-03 01:14:16 -0400 |
---|---|---|
committer | Matthew Hoops | 2011-06-03 01:14:16 -0400 |
commit | 224c71e483e09931ba386555ff3b436b9defe63d (patch) | |
tree | 8e6178331a7bbd3ee1be318d3fc7a7c7f478468f /common | |
parent | d4c92983920cfe3b25a22d91e12c750e591b917e (diff) | |
parent | 547fd1bdcabcba0e741eb31100ba99ff73399d24 (diff) | |
download | scummvm-rg350-224c71e483e09931ba386555ff3b436b9defe63d.tar.gz scummvm-rg350-224c71e483e09931ba386555ff3b436b9defe63d.tar.bz2 scummvm-rg350-224c71e483e09931ba386555ff3b436b9defe63d.zip |
Merge remote branch 'upstream/master' into pegasus
Diffstat (limited to 'common')
-rw-r--r-- | common/algorithm.h | 11 | ||||
-rw-r--r-- | common/error.cpp | 3 | ||||
-rw-r--r-- | common/error.h | 3 | ||||
-rw-r--r-- | common/events.h | 2 | ||||
-rw-r--r-- | common/forbidden.h | 67 | ||||
-rw-r--r-- | common/module.mk | 1 | ||||
-rw-r--r-- | common/quicktime.cpp | 814 | ||||
-rw-r--r-- | common/quicktime.h | 213 | ||||
-rw-r--r-- | common/savefile.h | 2 | ||||
-rw-r--r-- | common/scummsys.h | 259 | ||||
-rw-r--r-- | common/str.cpp | 33 | ||||
-rw-r--r-- | common/str.h | 5 | ||||
-rw-r--r-- | common/system.h | 2 | ||||
-rw-r--r-- | common/textconsole.cpp | 2 | ||||
-rw-r--r-- | common/unzip.cpp | 10 | ||||
-rw-r--r-- | common/util.cpp | 1 | ||||
-rw-r--r-- | common/util.h | 1 |
17 files changed, 1238 insertions, 191 deletions
diff --git a/common/algorithm.h b/common/algorithm.h index be810d6e9d..00c0e1c98f 100644 --- a/common/algorithm.h +++ b/common/algorithm.h @@ -234,6 +234,13 @@ void sort(T first, T last) { sort(first, last, Common::Less<typename T::ValueType>()); } +// MSVC is complaining about the minus operator being applied to an unsigned type +// We disable this warning for the affected section of code +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable: 4146) +#endif + /** * Euclid's algorithm to compute the greatest common divisor. */ @@ -256,6 +263,10 @@ T gcd(T a, T b) { return b; } +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + } // End of namespace Common #endif diff --git a/common/error.cpp b/common/error.cpp index f150f268c0..a6c52a0ce9 100644 --- a/common/error.cpp +++ b/common/error.cpp @@ -67,9 +67,6 @@ static String errorToString(ErrorCode errorCode) { case kEnginePluginNotSupportSaves: return _s("Engine plugin does not support save states"); - case kArgumentNotProcessed: - return _s("Command line argument not processed"); - case kUnknownError: default: return _s("Unknown error"); diff --git a/common/error.h b/common/error.h index c06cec4a0b..23c12b67e4 100644 --- a/common/error.h +++ b/common/error.h @@ -47,7 +47,6 @@ enum ErrorCode { kUnsupportedGameidError, ///< Engine initialization: Gameid not supported by this (Meta)Engine kUnsupportedColorMode, ///< Engine initialization: Engine does not support backend's color mode - kReadPermissionDenied, ///< Unable to read data due to missing read permission kWritePermissionDenied, ///< Unable to write data due to missing write permission @@ -63,8 +62,6 @@ enum ErrorCode { kEnginePluginNotFound, ///< Failed to find plugin to handle target kEnginePluginNotSupportSaves, ///< Failed if plugin does not support listing save states - kArgumentNotProcessed, ///< Used in command line parsing - kUnknownError ///< Catch-all error, used if no other error code matches }; diff --git a/common/events.h b/common/events.h index 11eb0c316e..371080c1b2 100644 --- a/common/events.h +++ b/common/events.h @@ -306,7 +306,7 @@ public: /** - * Initialise the event manager. + * Initialize the event manager. * @note called after graphics system has been set up */ virtual void init() {} diff --git a/common/forbidden.h b/common/forbidden.h index d769ff38be..c551110d0e 100644 --- a/common/forbidden.h +++ b/common/forbidden.h @@ -125,6 +125,27 @@ #endif +#ifndef FORBIDDEN_SYMBOL_EXCEPTION_getc +#undef getc +#define getc(a) FORBIDDEN_SYMBOL_REPLACEMENT +#endif + +#ifndef FORBIDDEN_SYMBOL_EXCEPTION_getchar +#undef getchar +#define getchar() FORBIDDEN_SYMBOL_REPLACEMENT +#endif + +#ifndef FORBIDDEN_SYMBOL_EXCEPTION_putc +#undef putc +#define putc(a,b) FORBIDDEN_SYMBOL_REPLACEMENT +#endif + +#ifndef FORBIDDEN_SYMBOL_EXCEPTION_putchar +#undef putchar +#define putchar(a) FORBIDDEN_SYMBOL_REPLACEMENT +#endif + + #ifndef FORBIDDEN_SYMBOL_EXCEPTION_setjmp #undef setjmp #define setjmp(a) FORBIDDEN_SYMBOL_REPLACEMENT @@ -140,6 +161,31 @@ #define system(a) FORBIDDEN_SYMBOL_REPLACEMENT #endif +#ifndef FORBIDDEN_SYMBOL_EXCEPTION_exit +#undef exit +#define exit(a) FORBIDDEN_SYMBOL_REPLACEMENT +#endif + +#ifndef FORBIDDEN_SYMBOL_EXCEPTION_getenv +#undef getenv +#define getenv(a) FORBIDDEN_SYMBOL_REPLACEMENT +#endif + +#ifndef FORBIDDEN_SYMBOL_EXCEPTION_putenv +#undef putenv +#define putenv(a) FORBIDDEN_SYMBOL_REPLACEMENT +#endif + +#ifndef FORBIDDEN_SYMBOL_EXCEPTION_setenv +#undef setenv +#define setenv(a,b,c) FORBIDDEN_SYMBOL_REPLACEMENT +#endif + +#ifndef FORBIDDEN_SYMBOL_EXCEPTION_unsetenv +#undef unsetenv +#define unsetenv(a) FORBIDDEN_SYMBOL_REPLACEMENT +#endif + // // Disable various symbols from time.h @@ -281,6 +327,27 @@ #endif +#ifndef FORBIDDEN_SYMBOL_EXCEPTION_stricmp +#undef stricmp +#define stricmp(a,b) FORBIDDEN_SYMBOL_REPLACEMENT +#endif + +#ifndef FORBIDDEN_SYMBOL_EXCEPTION_strnicmp +#undef strnicmp +#define strnicmp(a,b,c) FORBIDDEN_SYMBOL_REPLACEMENT +#endif + +#ifndef FORBIDDEN_SYMBOL_EXCEPTION_strcasecmp +#undef strcasecmp +#define strcasecmp(a,b) FORBIDDEN_SYMBOL_REPLACEMENT +#endif + +#ifndef FORBIDDEN_SYMBOL_EXCEPTION_strncasecmp +#undef strncasecmp +#define strncasecmp(a,b,c) FORBIDDEN_SYMBOL_REPLACEMENT +#endif + + /* * We also would like to disable the following symbols; * however, these are also frequently used in regular code, diff --git a/common/module.mk b/common/module.mk index a57de6a4b8..5f6a529595 100644 --- a/common/module.mk +++ b/common/module.mk @@ -17,6 +17,7 @@ MODULE_OBJS := \ memorypool.o \ md5.o \ mutex.o \ + quicktime.o \ random.o \ rational.o \ str.o \ diff --git a/common/quicktime.cpp b/common/quicktime.cpp new file mode 100644 index 0000000000..57534b301a --- /dev/null +++ b/common/quicktime.cpp @@ -0,0 +1,814 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +// +// Heavily based on ffmpeg code. +// +// Copyright (c) 2001 Fabrice Bellard. +// First version by Francois Revol revol@free.fr +// Seek function by Gael Chardon gael.dev@4now.net +// + +#include "common/debug.h" +#include "common/endian.h" +#include "common/macresman.h" +#include "common/memstream.h" +#include "common/quicktime.h" +#include "common/textconsole.h" +#include "common/util.h" +#include "common/zlib.h" + +namespace Common { + +//////////////////////////////////////////// +// QuickTimeParser +//////////////////////////////////////////// + +QuickTimeParser::QuickTimeParser() { + _beginOffset = 0; + _fd = 0; + _scaleFactorX = 1; + _scaleFactorY = 1; + _resFork = new Common::MacResManager(); + _disposeFileHandle = DisposeAfterUse::YES; + + initParseTable(); +} + +QuickTimeParser::~QuickTimeParser() { + close(); + delete _resFork; +} + +bool QuickTimeParser::parseFile(const Common::String &filename) { + if (!_resFork->open(filename) || !_resFork->hasDataFork()) + return false; + + _foundMOOV = false; + _disposeFileHandle = DisposeAfterUse::YES; + + Atom atom = { 0, 0, 0xffffffff }; + + if (_resFork->hasResFork()) { + // Search for a 'moov' resource + Common::MacResIDArray idArray = _resFork->getResIDArray(MKTAG('m', 'o', 'o', 'v')); + + if (!idArray.empty()) + _fd = _resFork->getResource(MKTAG('m', 'o', 'o', 'v'), idArray[0]); + + if (_fd) { + atom.size = _fd->size(); + if (readDefault(atom) < 0 || !_foundMOOV) + return false; + } + delete _fd; + + atom.type = 0; + atom.offset = 0; + atom.size = 0xffffffff; + } + + _fd = _resFork->getDataFork(); + + if (readDefault(atom) < 0 || !_foundMOOV) + return false; + + init(); + return true; +} + +bool QuickTimeParser::parseStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeFileHandle) { + _fd = stream; + _foundMOOV = false; + _disposeFileHandle = disposeFileHandle; + + Atom atom = { 0, 0, 0xffffffff }; + + if (readDefault(atom) < 0 || !_foundMOOV) { + close(); + return false; + } + + init(); + return true; +} + +void QuickTimeParser::init() { + // Remove unknown/unhandled tracks + for (uint32 i = 0; i < _tracks.size(); i++) { + if (_tracks[i]->codecType == CODEC_TYPE_MOV_OTHER) { + delete _tracks[i]; + _tracks.remove_at(i); + i--; + } + } + + // Adjust time scale + for (uint32 i = 0; i < _tracks.size(); i++) + if (!_tracks[i]->timeScale) + _tracks[i]->timeScale = _timeScale; +} + +void QuickTimeParser::initParseTable() { + static const ParseTable p[] = { + { &QuickTimeParser::readDefault, MKTAG('d', 'i', 'n', 'f') }, + { &QuickTimeParser::readLeaf, MKTAG('d', 'r', 'e', 'f') }, + { &QuickTimeParser::readDefault, MKTAG('e', 'd', 't', 's') }, + { &QuickTimeParser::readELST, MKTAG('e', 'l', 's', 't') }, + { &QuickTimeParser::readHDLR, MKTAG('h', 'd', 'l', 'r') }, + { &QuickTimeParser::readDefault, MKTAG('m', 'd', 'a', 't') }, + { &QuickTimeParser::readMDHD, MKTAG('m', 'd', 'h', 'd') }, + { &QuickTimeParser::readDefault, MKTAG('m', 'd', 'i', 'a') }, + { &QuickTimeParser::readDefault, MKTAG('m', 'i', 'n', 'f') }, + { &QuickTimeParser::readMOOV, MKTAG('m', 'o', 'o', 'v') }, + { &QuickTimeParser::readMVHD, MKTAG('m', 'v', 'h', 'd') }, + { &QuickTimeParser::readLeaf, MKTAG('s', 'm', 'h', 'd') }, + { &QuickTimeParser::readDefault, MKTAG('s', 't', 'b', 'l') }, + { &QuickTimeParser::readSTCO, MKTAG('s', 't', 'c', 'o') }, + { &QuickTimeParser::readSTSC, MKTAG('s', 't', 's', 'c') }, + { &QuickTimeParser::readSTSD, MKTAG('s', 't', 's', 'd') }, + { &QuickTimeParser::readSTSS, MKTAG('s', 't', 's', 's') }, + { &QuickTimeParser::readSTSZ, MKTAG('s', 't', 's', 'z') }, + { &QuickTimeParser::readSTTS, MKTAG('s', 't', 't', 's') }, + { &QuickTimeParser::readTKHD, MKTAG('t', 'k', 'h', 'd') }, + { &QuickTimeParser::readTRAK, MKTAG('t', 'r', 'a', 'k') }, + { &QuickTimeParser::readLeaf, MKTAG('u', 'd', 't', 'a') }, + { &QuickTimeParser::readLeaf, MKTAG('v', 'm', 'h', 'd') }, + { &QuickTimeParser::readCMOV, MKTAG('c', 'm', 'o', 'v') }, + { &QuickTimeParser::readWAVE, MKTAG('w', 'a', 'v', 'e') }, + { &QuickTimeParser::readESDS, MKTAG('e', 's', 'd', 's') }, + { 0, 0 } + }; + + _parseTable = p; +} + +int QuickTimeParser::readDefault(Atom atom) { + uint32 total_size = 0; + Atom a; + int err = 0; + + a.offset = atom.offset; + + while(((total_size + 8) < atom.size) && !_fd->eos() && _fd->pos() < _fd->size() && !err) { + a.size = atom.size; + a.type = 0; + + if (atom.size >= 8) { + a.size = _fd->readUint32BE(); + a.type = _fd->readUint32BE(); + + // Some QuickTime videos with resource forks have mdat chunks + // that are of size 0. Adjust it so it's the correct size. + if (a.type == MKTAG('m', 'd', 'a', 't') && a.size == 0) + a.size = _fd->size(); + } + + total_size += 8; + a.offset += 8; + debug(4, "type: %08x %.4s sz: %x %x %x", a.type, tag2str(a.type), a.size, atom.size, total_size); + + if (a.size == 1) { // 64 bit extended size + warning("64 bit extended size is not supported in QuickTime"); + return -1; + } + + if (a.size == 0) { + a.size = atom.size - total_size; + if (a.size <= 8) + break; + } + + uint32 i = 0; + + for (; _parseTable[i].type != 0 && _parseTable[i].type != a.type; i++) + ; // Empty + + if (a.size < 8) + break; + + a.size -= 8; + + if (_parseTable[i].type == 0) { // skip leaf atoms data + debug(0, ">>> Skipped [%s]", tag2str(a.type)); + + _fd->seek(a.size, SEEK_CUR); + } else { + uint32 start_pos = _fd->pos(); + err = (this->*_parseTable[i].func)(a); + + uint32 left = a.size - _fd->pos() + start_pos; + + if (left > 0) // skip garbage at atom end + _fd->seek(left, SEEK_CUR); + } + + a.offset += a.size; + total_size += a.size; + } + + if (!err && total_size < atom.size) + _fd->seek(atom.size - total_size, SEEK_SET); + + return err; +} + +int QuickTimeParser::readLeaf(Atom atom) { + if (atom.size > 1) + _fd->seek(atom.size, SEEK_SET); + + return 0; +} + +int QuickTimeParser::readMOOV(Atom atom) { + if (readDefault(atom) < 0) + return -1; + + // We parsed the 'moov' atom, so we don't need anything else + _foundMOOV = true; + return 1; +} + +int QuickTimeParser::readCMOV(Atom atom) { +#ifdef USE_ZLIB + // Read in the dcom atom + _fd->readUint32BE(); + if (_fd->readUint32BE() != MKTAG('d', 'c', 'o', 'm')) + return -1; + if (_fd->readUint32BE() != MKTAG('z', 'l', 'i', 'b')) { + warning("Unknown cmov compression type"); + return -1; + } + + // Read in the cmvd atom + uint32 compressedSize = _fd->readUint32BE() - 12; + if (_fd->readUint32BE() != MKTAG('c', 'm', 'v', 'd')) + return -1; + uint32 uncompressedSize = _fd->readUint32BE(); + + // Read in data + byte *compressedData = (byte *)malloc(compressedSize); + _fd->read(compressedData, compressedSize); + + // Create uncompressed stream + byte *uncompressedData = (byte *)malloc(uncompressedSize); + + // Uncompress the data + unsigned long dstLen = uncompressedSize; + if (!Common::uncompress(uncompressedData, &dstLen, compressedData, compressedSize)) { + warning ("Could not uncompress cmov chunk"); + free(compressedData); + free(uncompressedData); + return -1; + } + + // Load data into a new MemoryReadStream and assign _fd to be that + Common::SeekableReadStream *oldStream = _fd; + _fd = new Common::MemoryReadStream(uncompressedData, uncompressedSize, DisposeAfterUse::YES); + + // Read the contents of the uncompressed data + Atom a = { MKTAG('m', 'o', 'o', 'v'), 0, uncompressedSize }; + int err = readDefault(a); + + // Assign the file handle back to the original handle + free(compressedData); + delete _fd; + _fd = oldStream; + + return err; +#else + warning ("zlib not found, cannot read QuickTime cmov atom"); + return -1; +#endif +} + +int QuickTimeParser::readMVHD(Atom atom) { + byte version = _fd->readByte(); // version + _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags + + if (version == 1) { + warning("QuickTime version 1"); + _fd->readUint32BE(); _fd->readUint32BE(); + _fd->readUint32BE(); _fd->readUint32BE(); + } else { + _fd->readUint32BE(); // creation time + _fd->readUint32BE(); // modification time + } + + _timeScale = _fd->readUint32BE(); // time scale + debug(0, "time scale = %i\n", _timeScale); + + // duration + _duration = (version == 1) ? (_fd->readUint32BE(), _fd->readUint32BE()) : _fd->readUint32BE(); + _fd->readUint32BE(); // preferred scale + + _fd->readUint16BE(); // preferred volume + + _fd->seek(10, SEEK_CUR); // reserved + + // We only need two values from the movie display matrix. Most of the values are just + // skipped. xMod and yMod are 16:16 fixed point numbers, the last part of the 3x3 matrix + // is 2:30. + uint32 xMod = _fd->readUint32BE(); + _fd->skip(12); + uint32 yMod = _fd->readUint32BE(); + _fd->skip(16); + + _scaleFactorX = Common::Rational(0x10000, xMod); + _scaleFactorY = Common::Rational(0x10000, yMod); + + _scaleFactorX.debugPrint(1, "readMVHD(): scaleFactorX ="); + _scaleFactorY.debugPrint(1, "readMVHD(): scaleFactorY ="); + + _fd->readUint32BE(); // preview time + _fd->readUint32BE(); // preview duration + _fd->readUint32BE(); // poster time + _fd->readUint32BE(); // selection time + _fd->readUint32BE(); // selection duration + _fd->readUint32BE(); // current time + _fd->readUint32BE(); // next track ID + + return 0; +} + +int QuickTimeParser::readTRAK(Atom atom) { + Track *track = new Track(); + + if (!track) + return -1; + + track->codecType = CODEC_TYPE_MOV_OTHER; + track->startTime = 0; // XXX: check + _tracks.push_back(track); + + return readDefault(atom); +} + +int QuickTimeParser::readTKHD(Atom atom) { + Track *track = _tracks.back(); + byte version = _fd->readByte(); + + _fd->readByte(); _fd->readByte(); + _fd->readByte(); // flags + // + //MOV_TRACK_ENABLED 0x0001 + //MOV_TRACK_IN_MOVIE 0x0002 + //MOV_TRACK_IN_PREVIEW 0x0004 + //MOV_TRACK_IN_POSTER 0x0008 + // + + if (version == 1) { + _fd->readUint32BE(); _fd->readUint32BE(); + _fd->readUint32BE(); _fd->readUint32BE(); + } else { + _fd->readUint32BE(); // creation time + _fd->readUint32BE(); // modification time + } + + /* track->id = */_fd->readUint32BE(); // track id (NOT 0 !) + _fd->readUint32BE(); // reserved + //track->startTime = 0; // check + (version == 1) ? (_fd->readUint32BE(), _fd->readUint32BE()) : _fd->readUint32BE(); // highlevel (considering edits) duration in movie timebase + _fd->readUint32BE(); // reserved + _fd->readUint32BE(); // reserved + + _fd->readUint16BE(); // layer + _fd->readUint16BE(); // alternate group + _fd->readUint16BE(); // volume + _fd->readUint16BE(); // reserved + + // We only need the two values from the displacement matrix for a track. + // See readMVHD() for more information. + uint32 xMod = _fd->readUint32BE(); + _fd->skip(12); + uint32 yMod = _fd->readUint32BE(); + _fd->skip(16); + + track->scaleFactorX = Common::Rational(0x10000, xMod); + track->scaleFactorY = Common::Rational(0x10000, yMod); + + track->scaleFactorX.debugPrint(1, "readTKHD(): scaleFactorX ="); + track->scaleFactorY.debugPrint(1, "readTKHD(): scaleFactorY ="); + + // these are fixed-point, 16:16 + // uint32 tkWidth = _fd->readUint32BE() >> 16; // track width + // uint32 tkHeight = _fd->readUint32BE() >> 16; // track height + + return 0; +} + +// edit list atom +int QuickTimeParser::readELST(Atom atom) { + Track *track = _tracks.back(); + + _fd->readByte(); // version + _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags + + track->editCount = _fd->readUint32BE(); + track->editList = new EditListEntry[track->editCount]; + + debug(2, "Track %d edit list count: %d", _tracks.size() - 1, track->editCount); + + for (uint32 i = 0; i < track->editCount; i++){ + track->editList[i].trackDuration = _fd->readUint32BE(); + track->editList[i].mediaTime = _fd->readSint32BE(); + track->editList[i].mediaRate = Common::Rational(_fd->readUint32BE(), 0x10000); + debugN(3, "\tDuration = %d, Media Time = %d, ", track->editList[i].trackDuration, track->editList[i].mediaTime); + track->editList[i].mediaRate.debugPrint(3, "Media Rate ="); + } + + if (track->editCount != 1) + warning("Multiple edit list entries. Things may go awry"); + + return 0; +} + +int QuickTimeParser::readHDLR(Atom atom) { + Track *track = _tracks.back(); + + _fd->readByte(); // version + _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags + + // component type + uint32 ctype = _fd->readUint32BE(); + uint32 type = _fd->readUint32BE(); // component subtype + + debug(0, "ctype= %s (0x%08lx)", tag2str(ctype), (long)ctype); + debug(0, "stype= %s", tag2str(type)); + + if (ctype == MKTAG('m', 'h', 'l', 'r')) // MOV + debug(0, "MOV detected"); + else if (ctype == 0) + debug(0, "MPEG-4 detected"); + + if (type == MKTAG('v', 'i', 'd', 'e')) + track->codecType = CODEC_TYPE_VIDEO; + else if (type == MKTAG('s', 'o', 'u', 'n')) + track->codecType = CODEC_TYPE_AUDIO; + + _fd->readUint32BE(); // component manufacture + _fd->readUint32BE(); // component flags + _fd->readUint32BE(); // component flags mask + + if (atom.size <= 24) + return 0; // nothing left to read + + // .mov: PASCAL string + byte len = _fd->readByte(); + _fd->seek(len, SEEK_CUR); + + _fd->seek(atom.size - (_fd->pos() - atom.offset), SEEK_CUR); + + return 0; +} + +int QuickTimeParser::readMDHD(Atom atom) { + Track *track = _tracks.back(); + byte version = _fd->readByte(); + + if (version > 1) + return 1; // unsupported + + _fd->readByte(); _fd->readByte(); + _fd->readByte(); // flags + + if (version == 1) { + _fd->readUint32BE(); _fd->readUint32BE(); + _fd->readUint32BE(); _fd->readUint32BE(); + } else { + _fd->readUint32BE(); // creation time + _fd->readUint32BE(); // modification time + } + + track->timeScale = _fd->readUint32BE(); + track->duration = (version == 1) ? (_fd->readUint32BE(), _fd->readUint32BE()) : _fd->readUint32BE(); // duration + + _fd->readUint16BE(); // language + _fd->readUint16BE(); // quality + + return 0; +} + +int QuickTimeParser::readSTSD(Atom atom) { + Track *track = _tracks.back(); + + _fd->readByte(); // version + _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags + + uint32 entryCount = _fd->readUint32BE(); + track->sampleDescs.resize(entryCount); + + for (uint32 i = 0; i < entryCount; i++) { // Parsing Sample description table + Atom a = { 0, 0, 0 }; + uint32 start_pos = _fd->pos(); + int size = _fd->readUint32BE(); // size + uint32 format = _fd->readUint32BE(); // data format + + _fd->readUint32BE(); // reserved + _fd->readUint16BE(); // reserved + _fd->readUint16BE(); // index + + track->sampleDescs[i] = readSampleDesc(track, format); + + debug(0, "size=%d 4CC= %s codec_type=%d", size, tag2str(format), track->codecType); + + if (!track->sampleDescs[i]) { + // other codec type, just skip (rtp, mp4s, tmcd ...) + _fd->seek(size - (_fd->pos() - start_pos), SEEK_CUR); + } + + // this will read extra atoms at the end (wave, alac, damr, avcC, SMI ...) + a.size = size - (_fd->pos() - start_pos); + if (a.size > 8) + readDefault(a); + else if (a.size > 0) + _fd->seek(a.size, SEEK_CUR); + } + + return 0; +} + +int QuickTimeParser::readSTSC(Atom atom) { + Track *track = _tracks.back(); + + _fd->readByte(); // version + _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags + + track->sampleToChunkCount = _fd->readUint32BE(); + + debug(0, "track[%i].stsc.entries = %i", _tracks.size() - 1, track->sampleToChunkCount); + + track->sampleToChunk = new SampleToChunkEntry[track->sampleToChunkCount]; + + if (!track->sampleToChunk) + return -1; + + for (uint32 i = 0; i < track->sampleToChunkCount; i++) { + track->sampleToChunk[i].first = _fd->readUint32BE() - 1; + track->sampleToChunk[i].count = _fd->readUint32BE(); + track->sampleToChunk[i].id = _fd->readUint32BE(); + //warning("Sample to Chunk[%d]: First = %d, Count = %d", i, track->sampleToChunk[i].first, track->sampleToChunk[i].count); + } + + return 0; +} + +int QuickTimeParser::readSTSS(Atom atom) { + Track *track = _tracks.back(); + + _fd->readByte(); // version + _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags + + track->keyframeCount = _fd->readUint32BE(); + + debug(0, "keyframeCount = %d", track->keyframeCount); + + track->keyframes = new uint32[track->keyframeCount]; + + if (!track->keyframes) + return -1; + + for (uint32 i = 0; i < track->keyframeCount; i++) { + track->keyframes[i] = _fd->readUint32BE() - 1; // Adjust here, the frames are based on 1 + debug(6, "keyframes[%d] = %d", i, track->keyframes[i]); + + } + return 0; +} + +int QuickTimeParser::readSTSZ(Atom atom) { + Track *track = _tracks.back(); + + _fd->readByte(); // version + _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags + + track->sampleSize = _fd->readUint32BE(); + track->sampleCount = _fd->readUint32BE(); + + debug(5, "sampleSize = %d sampleCount = %d", track->sampleSize, track->sampleCount); + + if (track->sampleSize) + return 0; // there isn't any table following + + track->sampleSizes = new uint32[track->sampleCount]; + + if (!track->sampleSizes) + return -1; + + for(uint32 i = 0; i < track->sampleCount; i++) { + track->sampleSizes[i] = _fd->readUint32BE(); + debug(6, "sampleSizes[%d] = %d", i, track->sampleSizes[i]); + } + + return 0; +} + +int QuickTimeParser::readSTTS(Atom atom) { + Track *track = _tracks.back(); + uint32 totalSampleCount = 0; + + _fd->readByte(); // version + _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags + + track->timeToSampleCount = _fd->readUint32BE(); + track->timeToSample = new TimeToSampleEntry[track->timeToSampleCount]; + + debug(0, "track[%d].stts.entries = %d", _tracks.size() - 1, track->timeToSampleCount); + + for (int32 i = 0; i < track->timeToSampleCount; i++) { + track->timeToSample[i].count = _fd->readUint32BE(); + track->timeToSample[i].duration = _fd->readUint32BE(); + + debug(1, "\tCount = %d, Duration = %d", track->timeToSample[i].count, track->timeToSample[i].duration); + + totalSampleCount += track->timeToSample[i].count; + } + + track->frameCount = totalSampleCount; + return 0; +} + +int QuickTimeParser::readSTCO(Atom atom) { + Track *track = _tracks.back(); + + _fd->readByte(); // version + _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags + + track->chunkCount = _fd->readUint32BE(); + track->chunkOffsets = new uint32[track->chunkCount]; + + if (!track->chunkOffsets) + return -1; + + for (uint32 i = 0; i < track->chunkCount; i++) { + // WORKAROUND/HACK: The offsets in Riven videos (ones inside the Mohawk archives themselves) + // have offsets relative to the archive and not the video. This is quite nasty. We subtract + // the initial offset of the stream to get the correct value inside of the stream. + track->chunkOffsets[i] = _fd->readUint32BE() - _beginOffset; + } + + return 0; +} + +int QuickTimeParser::readWAVE(Atom atom) { + if (_tracks.empty()) + return 0; + + Track *track = _tracks.back(); + + if (atom.size > (1 << 30)) + return -1; + + if (track->sampleDescs[0]->getCodecTag() == MKTAG('Q', 'D', 'M', '2')) // Read extra data for QDM2 + track->extraData = _fd->readStream(atom.size - 8); + else if (atom.size > 8) + return readDefault(atom); + else + _fd->skip(atom.size); + + return 0; +} + +enum { + kMP4IODescTag = 2, + kMP4ESDescTag = 3, + kMP4DecConfigDescTag = 4, + kMP4DecSpecificDescTag = 5 +}; + +static int readMP4DescLength(Common::SeekableReadStream *stream) { + int length = 0; + int count = 4; + + while (count--) { + byte c = stream->readByte(); + length = (length << 7) | (c & 0x7f); + + if (!(c & 0x80)) + break; + } + + return length; +} + +static void readMP4Desc(Common::SeekableReadStream *stream, byte &tag, int &length) { + tag = stream->readByte(); + length = readMP4DescLength(stream); +} + +int QuickTimeParser::readESDS(Atom atom) { + if (_tracks.empty()) + return 0; + + Track *track = _tracks.back(); + + _fd->readUint32BE(); // version + flags + + byte tag; + int length; + + readMP4Desc(_fd, tag, length); + _fd->readUint16BE(); // id + if (tag == kMP4ESDescTag) + _fd->readByte(); // priority + + // Check if we've got the Config MPEG-4 header + readMP4Desc(_fd, tag, length); + if (tag != kMP4DecConfigDescTag) + return 0; + + track->objectTypeMP4 = _fd->readByte(); + _fd->readByte(); // stream type + _fd->readUint16BE(); _fd->readByte(); // buffer size + _fd->readUint32BE(); // max bitrate + _fd->readUint32BE(); // avg bitrate + + // Check if we've got the Specific MPEG-4 header + readMP4Desc(_fd, tag, length); + if (tag != kMP4DecSpecificDescTag) + return 0; + + track->extraData = _fd->readStream(length); + + debug(0, "MPEG-4 object type = %02x", track->objectTypeMP4); + return 0; +} + +void QuickTimeParser::close() { + for (uint32 i = 0; i < _tracks.size(); i++) + delete _tracks[i]; + + _tracks.clear(); + + if (_disposeFileHandle == DisposeAfterUse::YES) + delete _fd; + + _fd = 0; +} + +QuickTimeParser::SampleDesc::SampleDesc(Track *parentTrack, uint32 codecTag) { + _parentTrack = parentTrack; + _codecTag = codecTag; +} + +QuickTimeParser::Track::Track() { + chunkCount = 0; + chunkOffsets = 0; + timeToSampleCount = 0; + timeToSample = 0; + sampleToChunkCount = 0; + sampleToChunk = 0; + sampleSize = 0; + sampleCount = 0; + sampleSizes = 0; + keyframeCount = 0; + keyframes = 0; + timeScale = 0; + width = 0; + height = 0; + codecType = CODEC_TYPE_MOV_OTHER; + editCount = 0; + editList = 0; + extraData = 0; + frameCount = 0; + duration = 0; + startTime = 0; + objectTypeMP4 = 0; +} + +QuickTimeParser::Track::~Track() { + delete[] chunkOffsets; + delete[] timeToSample; + delete[] sampleToChunk; + delete[] sampleSizes; + delete[] keyframes; + delete[] editList; + delete extraData; + + for (uint32 i = 0; i < sampleDescs.size(); i++) + delete sampleDescs[i]; +} + +} // End of namespace Video diff --git a/common/quicktime.h b/common/quicktime.h new file mode 100644 index 0000000000..cb2bed1202 --- /dev/null +++ b/common/quicktime.h @@ -0,0 +1,213 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +// +// Heavily based on ffmpeg code. +// +// Copyright (c) 2001 Fabrice Bellard. +// First version by Francois Revol revol@free.fr +// Seek function by Gael Chardon gael.dev@4now.net +// + +#ifndef COMMON_QUICKTIME_H +#define COMMON_QUICKTIME_H + +#include "common/array.h" +#include "common/scummsys.h" +#include "common/stream.h" +#include "common/rational.h" + +namespace Common { + class MacResManager; + +/** + * Parser for QuickTime/MPEG-4 files. + * + * File parser used in engines: + * - groovie + * - mohawk + * - sci + */ +class QuickTimeParser { +public: + QuickTimeParser(); + virtual ~QuickTimeParser(); + + /** + * Load a QuickTime file + * @param filename the filename to load + */ + bool parseFile(const Common::String &filename); + + /** + * Load a QuickTime file from a SeekableReadStream + * @param stream the stream to load + * @param disposeFileHandle whether to delete the stream after use + */ + bool parseStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeFileHandle = DisposeAfterUse::YES); + + /** + * Close a QuickTime file + */ + void close(); + + /** + * Set the beginning offset of the video so we can modify the offsets in the stco + * atom of videos inside the Mohawk archives + * @param the beginning offset of the video + */ + void setChunkBeginOffset(uint32 offset) { _beginOffset = offset; } + + bool isOpen() const { return _fd != 0; } + +protected: + // This is the file handle from which data is read from. It can be the actual file handle or a decompressed stream. + Common::SeekableReadStream *_fd; + + DisposeAfterUse::Flag _disposeFileHandle; + + struct Atom { + uint32 type; + uint32 offset; + uint32 size; + }; + + struct ParseTable { + int (QuickTimeParser::*func)(Atom atom); + uint32 type; + }; + + struct TimeToSampleEntry { + int count; + int duration; + }; + + struct SampleToChunkEntry { + uint32 first; + uint32 count; + uint32 id; + }; + + struct EditListEntry { + uint32 trackDuration; + int32 mediaTime; + Common::Rational mediaRate; + }; + + struct Track; + + class SampleDesc { + public: + SampleDesc(Track *parentTrack, uint32 codecTag); + virtual ~SampleDesc() {} + + uint32 getCodecTag() const { return _codecTag; } + + protected: + Track *_parentTrack; + uint32 _codecTag; + }; + + enum CodecType { + CODEC_TYPE_MOV_OTHER, + CODEC_TYPE_VIDEO, + CODEC_TYPE_AUDIO + }; + + struct Track { + Track(); + ~Track(); + + uint32 chunkCount; + uint32 *chunkOffsets; + int timeToSampleCount; + TimeToSampleEntry *timeToSample; + uint32 sampleToChunkCount; + SampleToChunkEntry *sampleToChunk; + uint32 sampleSize; + uint32 sampleCount; + uint32 *sampleSizes; + uint32 keyframeCount; + uint32 *keyframes; + int32 timeScale; + + uint16 width; + uint16 height; + CodecType codecType; + + Common::Array<SampleDesc *> sampleDescs; + + uint32 editCount; + EditListEntry *editList; + + Common::SeekableReadStream *extraData; + + uint32 frameCount; + uint32 duration; + uint32 startTime; + Common::Rational scaleFactorX; + Common::Rational scaleFactorY; + + byte objectTypeMP4; + }; + + virtual SampleDesc *readSampleDesc(Track *track, uint32 format) = 0; + + const ParseTable *_parseTable; + bool _foundMOOV; + uint32 _timeScale; + uint32 _duration; + Common::Rational _scaleFactorX; + Common::Rational _scaleFactorY; + Common::Array<Track *> _tracks; + uint32 _beginOffset; + Common::MacResManager *_resFork; + + void initParseTable(); + void init(); + + int readDefault(Atom atom); + int readLeaf(Atom atom); + int readELST(Atom atom); + int readHDLR(Atom atom); + int readMDHD(Atom atom); + int readMOOV(Atom atom); + int readMVHD(Atom atom); + int readTKHD(Atom atom); + int readTRAK(Atom atom); + int readSTCO(Atom atom); + int readSTSC(Atom atom); + int readSTSD(Atom atom); + int readSTSS(Atom atom); + int readSTSZ(Atom atom); + int readSTTS(Atom atom); + int readCMOV(Atom atom); + int readWAVE(Atom atom); + int readESDS(Atom atom); +}; + +} // End of namespace Common + +#endif diff --git a/common/savefile.h b/common/savefile.h index 40f316267f..03a7b52add 100644 --- a/common/savefile.h +++ b/common/savefile.h @@ -142,7 +142,7 @@ public: /** * Request a list of available savegames with a given DOS-style pattern, - * also known as "glob" in the UNIX world. Refer to the Common::matchString() + * also known as "glob" in the POSIX world. Refer to the Common::matchString() * function to learn about the precise pattern format. * @param pattern Pattern to match. Wildcards like * or ? are available. * @return list of strings for all present file names. diff --git a/common/scummsys.h b/common/scummsys.h index 2420349245..a425befecf 100644 --- a/common/scummsys.h +++ b/common/scummsys.h @@ -40,10 +40,42 @@ #if defined(WIN32) #ifdef _MSC_VER - // vsnprintf is already defined in Visual Studio 2008 - #if (_MSC_VER < 1500) - #define vsnprintf _vsnprintf - #endif + + // FIXME: The placement of the workaround functions for MSVC below + // require us to include stdio.h and stdarg.h for MSVC here. This + // is not exactly nice... + // We should think of a better way of doing this. + #include <stdio.h> + #include <stdarg.h> + + // MSVC's vsnprintf is either non-existant (2003) or bugged since it + // does not always include a terminating NULL (2005+). To work around + // that we fix up the _vsnprintf included. Note that the return value + // will still not match C99's specs! + inline int vsnprintf_msvc(char *str, size_t size, const char *format, va_list args) { + // We do not pass size - 1 here, to ensure we would get the same + // return value as when we would use _vsnprintf directly, since + // for example Common::String::format relies on this. + int retValue = _vsnprintf(str, size, format, args); + str[size - 1] = 0; + return retValue; + } + + #define vsnprintf vsnprintf_msvc + + // Visual Studio does not include snprintf in its standard C library. + // Instead it includes a function called _snprintf with somewhat + // similar semantics. The minor difference is that the return value in + // case the formatted string exceeds the buffer size is different. + // A much more dangerous one is that _snprintf does not always include + // a terminating null (Whoops!). Instead we map to our fixed vsnprintf. + inline int snprintf(char *str, size_t size, const char *format, ...) { + va_list args; + va_start(args, format); + int len = vsnprintf(str, size, format, args); + va_end(args); + return len; + } #endif #if !defined(_WIN32_WCE) @@ -107,21 +139,6 @@ #include "config.h" #endif -// -// Define scumm_stricmp and scumm_strnicmp -// -#if defined(_WIN32_WCE) || defined(_MSC_VER) - #define scumm_stricmp stricmp - #define scumm_strnicmp _strnicmp - #define snprintf _snprintf -#elif defined(__MINGW32__) || defined(__GP32__) || defined(__DS__) - #define scumm_stricmp stricmp - #define scumm_strnicmp strnicmp -#else - #define scumm_stricmp strcasecmp - #define scumm_strnicmp strncasecmp -#endif - // In the following we configure various targets, in particular those // which can't use our "configure" tool and hence don't use config.h. @@ -151,88 +168,50 @@ // #define SCUMMVM_USE_PRAGMA_PACK +// +// Determine the host endianess and whether memory alignment is required. +// +#if !defined(HAVE_CONFIG_H) -#if defined(HAVE_CONFIG_H) - // All settings should have been set in config.h - -#elif defined(__SYMBIAN32__) - - #define SCUMM_LITTLE_ENDIAN - #define SCUMM_NEED_ALIGNMENT + #if defined(__DC__) || \ + defined(__DS__) || \ + defined(__GP32__) || \ + defined(IPHONE) || \ + defined(__PLAYSTATION2__) || \ + defined(__PSP__) || \ + defined(__SYMBIAN32__) -#elif defined(_WIN32_WCE) + #define SCUMM_LITTLE_ENDIAN + #define SCUMM_NEED_ALIGNMENT - #define SCUMM_LITTLE_ENDIAN + #elif defined(_WIN32_WCE) || defined(_MSC_VER) || defined(__MINGW32__) -#elif defined(_MSC_VER) + #define SCUMM_LITTLE_ENDIAN - #define SCUMM_LITTLE_ENDIAN + #elif defined(__amigaos4__) || defined(__N64__) || defined(__WII__) -#elif defined(__MINGW32__) + #define SCUMM_BIG_ENDIAN + #define SCUMM_NEED_ALIGNMENT - #define SCUMM_LITTLE_ENDIAN + #elif defined(SDL_BACKEND) + // On SDL based ports, we try to use SDL_BYTEORDER to determine the + // endianess. We explicitly do this as the *last* thing we try, so that + // platform specific settings have precedence. + #include <SDL_endian.h> -#elif defined(SDL_BACKEND) - /* need this for the SDL_BYTEORDER define */ - #include <SDL_byteorder.h> + #if SDL_BYTEORDER == SDL_LIL_ENDIAN + #define SCUMM_LITTLE_ENDIAN + #elif SDL_BYTEORDER == SDL_BIG_ENDIAN + #define SCUMM_BIG_ENDIAN + #else + #error Neither SDL_BIG_ENDIAN nor SDL_LIL_ENDIAN is set. + #endif - #if SDL_BYTEORDER == SDL_LIL_ENDIAN - #define SCUMM_LITTLE_ENDIAN - #elif SDL_BYTEORDER == SDL_BIG_ENDIAN - #define SCUMM_BIG_ENDIAN #else - #error Neither SDL_BIG_ENDIAN nor SDL_LIL_ENDIAN is set. - #endif - -#elif defined(__DC__) - - #define SCUMM_LITTLE_ENDIAN - #define SCUMM_NEED_ALIGNMENT - -#elif defined(__GP32__) - - #define SCUMM_LITTLE_ENDIAN - #define SCUMM_NEED_ALIGNMENT - -#elif defined(__PLAYSTATION2__) - - #define SCUMM_LITTLE_ENDIAN - #define SCUMM_NEED_ALIGNMENT - -#elif defined(__N64__) - - #define SCUMM_BIG_ENDIAN - #define SCUMM_NEED_ALIGNMENT - -#elif defined(__PSP__) - - #define SCUMM_LITTLE_ENDIAN - #define SCUMM_NEED_ALIGNMENT - -#elif defined(__amigaos4__) - - #define SCUMM_BIG_ENDIAN - #define SCUMM_NEED_ALIGNMENT - -#elif defined(__DS__) - - #define SCUMM_NEED_ALIGNMENT - #define SCUMM_LITTLE_ENDIAN - -#elif defined(__WII__) - - #define SCUMM_BIG_ENDIAN - #define SCUMM_NEED_ALIGNMENT - -#elif defined(IPHONE) - - #define SCUMM_LITTLE_ENDIAN - #define SCUMM_NEED_ALIGNMENT + #error No system type defined, host endianess unknown. -#else - #error No system type defined - + #endif #endif @@ -240,17 +219,7 @@ // Some more system specific settings. // TODO/FIXME: All of these should be moved to backend specific files (such as portdefs.h) // -#if defined(__SYMBIAN32__) - - #define SMALL_SCREEN_DEVICE - -#elif defined(_WIN32_WCE) - - #if _WIN32_WCE < 300 - #define SMALL_SCREEN_DEVICE - #endif - -#elif defined(DINGUX) +#if defined(DINGUX) // Very BAD hack following, used to avoid triggering an assert in uClibc dingux library // "toupper" when pressing keyboard function keys. @@ -309,7 +278,7 @@ #if defined(_MSC_VER) #define NORETURN_PRE __declspec(noreturn) #else - #define NORETURN_PRE + #define NORETURN_PRE #endif #endif @@ -317,7 +286,7 @@ #if defined(__GNUC__) || defined(__INTEL_COMPILER) #define NORETURN_POST __attribute__((__noreturn__)) #else - #define NORETURN_POST + #define NORETURN_POST #endif #endif @@ -335,87 +304,25 @@ // -// Typedef our system types +// Typedef our system types unless they have already been defined by config.h, +// or SCUMMVM_DONT_DEFINE_TYPES is set. // -#if !defined(HAVE_CONFIG_H) - - #if defined(__SYMBIAN32__) - - // Enable Symbians own datatypes - // This is done for two reasons - // a) uint is already defined by Symbians libc component - // b) Symbian is using its "own" datatyping, and the Scummvm port - // should follow this to ensure the best compability possible. - typedef unsigned char byte; - - typedef unsigned char uint8; - typedef signed char int8; - - typedef unsigned short int uint16; - typedef signed short int int16; - - typedef unsigned long int uint32; - typedef signed long int int32; - - #elif defined(__GP32__) - - // Override typenames. uint is already defined by system header files. - typedef unsigned char byte; - - typedef unsigned char uint8; - typedef signed char int8; - - typedef unsigned short int uint16; - typedef signed short int int16; - - typedef unsigned long int uint32; - typedef signed long int int32; - - #elif defined(__N64__) - - typedef unsigned char byte; - - typedef unsigned char uint8; - typedef signed char int8; - - typedef unsigned short int uint16; - typedef signed short int int16; - - typedef unsigned int uint32; - typedef signed int int32; - - #elif defined(__DS__) - - // Do nothing, the SDK defines all types we need in nds/ndstypes.h, - // which we include in our portsdef.h - - #else - - typedef unsigned char byte; - typedef unsigned char uint8; - typedef signed char int8; - typedef unsigned short uint16; - typedef signed short int16; - typedef unsigned int uint32; - typedef signed int int32; - typedef unsigned int uint; - - #endif - +#if !defined(HAVE_CONFIG_H) && !defined(SCUMMVM_DONT_DEFINE_TYPES) + typedef unsigned char byte; + typedef unsigned char uint8; + typedef signed char int8; + typedef unsigned short uint16; + typedef signed short int16; + typedef unsigned int uint32; + typedef signed int int32; + typedef unsigned int uint; #endif - // // Overlay color type (FIXME: shouldn't be declared here) // -#if defined(NEWGUI_256) - // 256 color only on PalmOS - typedef byte OverlayColor; -#else - // 15/16 bit color mode everywhere else... - typedef uint16 OverlayColor; -#endif +typedef uint16 OverlayColor; #include "common/forbidden.h" diff --git a/common/str.cpp b/common/str.cpp index 08a6cb6822..740e7b6a06 100644 --- a/common/str.cpp +++ b/common/str.cpp @@ -833,3 +833,36 @@ size_t strlcat(char *dst, const char *src, size_t size) { } } // End of namespace Common + +// Portable implementation of stricmp / strcasecmp / strcmpi. +// TODO: Rename this to Common::strcasecmp +int scumm_stricmp(const char *s1, const char *s2) { + byte l1, l2; + do { + // Don't use ++ inside tolower, in case the macro uses its + // arguments more than once. + l1 = (byte)*s1++; + l1 = tolower(l1); + l2 = (byte)*s2++; + l2 = tolower(l2); + } while (l1 == l2 && l1 != 0); + return l1 - l2; +} + +// Portable implementation of strnicmp / strncasecmp / strncmpi. +// TODO: Rename this to Common::strncasecmp +int scumm_strnicmp(const char *s1, const char *s2, uint n) { + byte l1, l2; + do { + if (n-- == 0) + return 0; // no difference found so far -> signal equality + + // Don't use ++ inside tolower, in case the macro uses its + // arguments more than once. + l1 = (byte)*s1++; + l1 = tolower(l1); + l2 = (byte)*s2++; + l2 = tolower(l2); + } while (l1 == l2 && l1 != 0); + return l1 - l2; +} diff --git a/common/str.h b/common/str.h index b76e4f8448..7b97dfe945 100644 --- a/common/str.h +++ b/common/str.h @@ -38,7 +38,7 @@ namespace Common { * a certain length do we allocate a buffer on the heap. * * The presence of \0 characters in the string will cause undefined - * behaviour in some operations. + * behavior in some operations. */ class String { protected: @@ -378,4 +378,7 @@ size_t strlcat(char *dst, const char *src, size_t size); } // End of namespace Common +extern int scumm_stricmp(const char *s1, const char *s2); +extern int scumm_strnicmp(const char *s1, const char *s2, uint n); + #endif diff --git a/common/system.h b/common/system.h index e02779fe47..b584739b77 100644 --- a/common/system.h +++ b/common/system.h @@ -1031,7 +1031,7 @@ public: }; -/** The global OSystem instance. Initialised in main(). */ +/** The global OSystem instance. Initialized in main(). */ extern OSystem *g_system; #endif diff --git a/common/textconsole.cpp b/common/textconsole.cpp index 0bd233d206..f2325ac9ad 100644 --- a/common/textconsole.cpp +++ b/common/textconsole.cpp @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#define FORBIDDEN_SYMBOL_EXCEPTION_exit + #include "common/textconsole.h" #include "common/system.h" #include "common/str.h" diff --git a/common/unzip.cpp b/common/unzip.cpp index f0590dcbfd..91f352f40a 100644 --- a/common/unzip.cpp +++ b/common/unzip.cpp @@ -349,7 +349,7 @@ typedef struct { z_stream stream; /* zLib stream structure for inflate */ uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ - uLong stream_initialised; /* flag set if stream structure is initialised*/ + uLong stream_initialized; /* flag set if stream structure is initialized*/ uLong offset_local_extrafield;/* offset of the local extra field */ uInt size_local_extrafield;/* size of the local extra field */ @@ -1073,7 +1073,7 @@ int unzOpenCurrentFile (unzFile file) { return UNZ_INTERNALERROR; } - pfile_in_zip_read_info->stream_initialised=0; + pfile_in_zip_read_info->stream_initialized=0; if ((s->cur_file_info.compression_method!=0) && (s->cur_file_info.compression_method!=Z_DEFLATED)) @@ -1096,7 +1096,7 @@ int unzOpenCurrentFile (unzFile file) { err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); if (err == Z_OK) - pfile_in_zip_read_info->stream_initialised = 1; + pfile_in_zip_read_info->stream_initialized = 1; /* windowBits is passed < 0 to tell that there is no zlib header. * Note that in this case inflate *requires* an extra "dummy" byte * after the compressed stream in order to complete decompression and @@ -1365,7 +1365,7 @@ int unzCloseCurrentFile(unzFile file) { if (pfile_in_zip_read_info->crc32_data != pfile_in_zip_read_info->crc32_wait) err=UNZ_CRCERROR; } - if (pfile_in_zip_read_info->stream_initialised) + if (pfile_in_zip_read_info->stream_initialized) inflateEnd(&pfile_in_zip_read_info->stream); #endif @@ -1373,7 +1373,7 @@ int unzCloseCurrentFile(unzFile file) { free(pfile_in_zip_read_info->read_buffer); pfile_in_zip_read_info->read_buffer = NULL; - pfile_in_zip_read_info->stream_initialised = 0; + pfile_in_zip_read_info->stream_initialized = 0; free(pfile_in_zip_read_info); s->pfile_in_zip_read=NULL; diff --git a/common/util.cpp b/common/util.cpp index eed7009f90..a7ec1a9de7 100644 --- a/common/util.cpp +++ b/common/util.cpp @@ -211,6 +211,7 @@ const PlatformDescription g_platforms[] = { { "windows", "win", "win", "Windows", kPlatformWindows }, { "playstation", "psx", "psx", "Sony PlayStation", kPlatformPSX }, { "cdi", "cdi", "cdi", "Philips CD-i", kPlatformCDi }, + { "ios", "ios", "ios", "Apple iOS", kPlatformIOS }, { 0, 0, 0, "Default", kPlatformUnknown } }; diff --git a/common/util.h b/common/util.h index 5d965c4d31..5837c8beab 100644 --- a/common/util.h +++ b/common/util.h @@ -172,6 +172,7 @@ enum Platform { kPlatformWii, kPlatformPSX, kPlatformCDi, + kPlatformIOS, kPlatformUnknown = -1 }; |