[Scummvm-git-logs] scummvm master -> 2185c50632b1a68717d501198c2aba032f175d0b
bluegr
bluegr at gmail.com
Sun Jan 19 19:38:59 UTC 2020
This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
07df6cc254 SCI: Add built-in resource patcher
3180528adf SCI: Fix compilation with C90 and older language versions
2185c50632 SCI32: Adapt the PQ4CD dual patch with our new view. Fixes bug #9690
Commit: 07df6cc254717d9bd0e1f3e15d5eeaece4ee2ee1
https://github.com/scummvm/scummvm/commit/07df6cc254717d9bd0e1f3e15d5eeaece4ee2ee1
Author: Colin Snover (github.com at zetafleet.com)
Date: 2020-01-19T21:37:20+02:00
Commit Message:
SCI: Add built-in resource patcher
The resource patcher can be used to patch non-script resources
like views, maps, sounds, etc. It is more primitive than the script
patcher in that it does not use signatures for safe and automatic
patch relocation, but it does at least allow existing resources to
be grown if needed.
Refs Trac#9788. Refs Trac#9690.
Changed paths:
A engines/sci/resource_patcher.cpp
A engines/sci/resource_patcher.h
engines/sci/engine/script_patches.cpp
engines/sci/graphics/celobj32.cpp
engines/sci/module.mk
engines/sci/resource.cpp
engines/sci/resource.h
engines/sci/resource_intern.h
engines/sci/sci.cpp
engines/sci/sci.h
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index eb41410..9bf95e7 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -18801,7 +18801,7 @@ void ScriptPatcher::processScript(uint16 scriptNr, SciSpan<byte> scriptData) {
foundOffset = findSignature(curEntry, curRuntimeEntry, scriptData);
if (foundOffset != -1) {
// found, so apply the patch
- debugC(kDebugLevelScriptPatcher, "Script-Patcher: '%s' on script %d offset %d", curEntry->description, scriptNr, foundOffset);
+ debugC(kDebugLevelPatcher, "Script-Patcher: '%s' on script %d offset %d", curEntry->description, scriptNr, foundOffset);
applyPatch(curEntry, scriptData, foundOffset);
}
applyCount--;
diff --git a/engines/sci/graphics/celobj32.cpp b/engines/sci/graphics/celobj32.cpp
index f62712d..efb8baa 100644
--- a/engines/sci/graphics/celobj32.cpp
+++ b/engines/sci/graphics/celobj32.cpp
@@ -1026,19 +1026,7 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
error("Cel is less than 0 on loop 0");
}
- // HACK: Phantasmagoria view 64001 contains a bad palette that overwrites
- // parts of the palette used by the background picture in room 6400, causing
- // the black shadows to become tan, and many of the other background colors
- // to end up a little bit off. View 64001 renders fine using the existing
- // palette created by the background image, so here we just ignore the
- // embedded palette entirely.
- if (g_sci->getGameId() == GID_PHANTASMAGORIA &&
- _info.type == kCelTypeView && _info.resourceId == 64001) {
-
- _hunkPaletteOffset = 0;
- } else {
- _hunkPaletteOffset = data.getUint32SEAt(8);
- }
+ _hunkPaletteOffset = data.getUint32SEAt(8);
_celHeaderOffset = loopHeader.getUint32SEAt(12) + (data[13] * _info.celNo);
const SciSpan<const byte> celHeader = data.subspan(_celHeaderOffset);
diff --git a/engines/sci/module.mk b/engines/sci/module.mk
index 6cf0cad..174bd8d 100644
--- a/engines/sci/module.mk
+++ b/engines/sci/module.mk
@@ -7,6 +7,7 @@ MODULE_OBJS := \
event.o \
resource.o \
resource_audio.o \
+ resource_patcher.o \
sci.o \
util.o \
engine/features.o \
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index a716a12..3e1f520 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -35,6 +35,7 @@
#include "sci/parser/vocabulary.h"
#include "sci/resource.h"
#include "sci/resource_intern.h"
+#include "sci/resource_patcher.h"
#include "sci/util.h"
namespace Sci {
@@ -419,6 +420,7 @@ void ResourceManager::disposeVolumeFileStream(Common::SeekableReadStream *fileSt
void ResourceManager::loadResource(Resource *res) {
res->_source->loadResource(this, res);
+ _patcher->applyPatch(*res);
}
@@ -978,6 +980,9 @@ void ResourceManager::init() {
#ifdef ENABLE_SCI32
_currentDiscNo = 1;
#endif
+ _patcher = new ResourcePatcher(g_sci->getGameId(), g_sci->getLanguage());
+ addSource(_patcher);
+
// FIXME: put this in an Init() function, so that we can error out if detection fails completely
_mapVersion = detectMapVersion();
diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index 119d860..5268e7a 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -145,6 +145,7 @@ enum ResVersion {
class ResourceManager;
class ResourceSource;
+class ResourcePatcher;
class ResourceId {
static inline ResourceType fixupType(ResourceType type) {
@@ -243,6 +244,7 @@ struct ResourceIdHash : public Common::UnaryFunction<ResourceId, uint> {
/** Class for storing resources in memory */
class Resource : public SciSpan<const byte> {
friend class ResourceManager;
+ friend class ResourcePatcher;
// FIXME: These 'friend' declarations are meant to be a temporary hack to
// ease transition to the ResourceSource class system.
@@ -323,6 +325,7 @@ class ResourceManager {
friend class ExtAudioMapResourceSource;
friend class WaveResourceSource;
friend class MacResourceForkResourceSource;
+ friend class ResourcePatcher;
#ifdef ENABLE_SCI32
friend class ChunkResourceSource;
#endif
@@ -624,6 +627,9 @@ protected:
void detectSciVersion();
private:
+ // For better or worse, because the patcher is added as a ResourceSource,
+ // its destruction is managed by freeResourceSources.
+ ResourcePatcher *_patcher;
bool _hasBadResources;
};
diff --git a/engines/sci/resource_intern.h b/engines/sci/resource_intern.h
index ea3e056..4eaca67 100644
--- a/engines/sci/resource_intern.h
+++ b/engines/sci/resource_intern.h
@@ -41,7 +41,8 @@ enum ResSourceType {
kSourceExtAudioMap, ///< SCI1 audio resource maps
kSourceWave, ///< External WAVE files, patched in as sound resources
kSourceMacResourceFork, ///< Mac SCI1.1 and later resource forks
- kSourceChunk ///< Script chunk resources (*.chk)
+ kSourceChunk, ///< Script chunk resources (*.chk)
+ kSourceScummVM ///< Built-in resource patcher
};
diff --git a/engines/sci/resource_patcher.cpp b/engines/sci/resource_patcher.cpp
new file mode 100644
index 0000000..528d89e
--- /dev/null
+++ b/engines/sci/resource_patcher.cpp
@@ -0,0 +1,626 @@
+/* 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.
+ *
+ */
+
+#include "common/scummsys.h"
+#include "common/textconsole.h"
+#include "sci/sci.h"
+#include "sci/resource.h"
+#include "sci/resource_patcher.h"
+
+namespace Sci {
+
+// Start of internal resource patcher macros. Please do not use these directly
+// in resource patches.
+#define _NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
+#ifdef SCUMM_LITTLE_ENDIAN
+#define _PACKINT32(n) (((uint32)n) & 0xFF), (((uint32)n) >> 8 & 0xFF), (((uint32)n) >> 16 & 0xFF), (((uint32)n) >> 24 & 0xFF)
+#else
+#define _PACKINT32(n) (((uint32)n) >> 24 & 0xFF), (((uint32)n) >> 16 & 0xFF), (((uint32)n) >> 8 & 0xFF), (((uint32)n) & 0xFF)
+#endif
+#define _BYTEOP(op, ...) op, _PACKINT32(_NUMARGS(__VA_ARGS__)), __VA_ARGS__
+#define _NUMBEROP(op, type, value) op, sizeof(type), _PACKINT32(value)
+#define _FILLOP(op, numBytes, value) op, _PACKINT32(numBytes), value
+// End of internal resource patcher macros
+
+/**
+ * Advances the current position by `numBytes` bytes without changing any data.
+ */
+#define SKIP(numBytes) kSkipBytes, _PACKINT32(numBytes)
+
+/**
+ * Replaces data at the current position.
+ */
+#define REPLACE(...) _BYTEOP(kReplaceBytes, __VA_ARGS__)
+
+/**
+ * Inserts new data at the current position.
+ */
+#define INSERT(...) _BYTEOP(kInsertBytes, __VA_ARGS__)
+
+/**
+ * Replaces a number of the given type at the current position with the given
+ * value.
+ */
+#define REPLACE_NUMBER(type, value) _NUMBEROP(kReplaceNumber, type, value)
+
+/**
+ * Adjusts a number of the given type at the current position by the given
+ * delta.
+ */
+#define ADJUST_NUMBER(type, delta) _NUMBEROP(kAdjustNumber, type, delta)
+
+/**
+ * Inserts a number of the given type at the current position with the given
+ * value.
+ */
+#define INSERT_NUMBER(type, value) _NUMBEROP(kInsertNumber, type, value)
+
+/**
+ * Replaces N bytes at the current position with the given value.
+ */
+#define REPLACE_FILL(value, numBytes) _FILLOP(kReplaceFill, numBytes, value)
+
+/**
+ * Inserts N bytes at the current position with the given value.
+ */
+#define INSERT_FILL(value, numBytes) _FILLOP(kInsertFill, numBytes, value)
+
+/**
+ * A required marker indicating that the end of the patch data has been reached
+ * and no new patch operations will occur.
+ */
+#define END kEndOfPatch
+
+#pragma mark -
+#pragma mark Phantasmagoria
+
+// Phantasmagoria view 64001 contains a bad palette that overwrites parts of the
+// palette used by the background picture in room 6400, causing the black
+// shadows to become tan, and many of the other background colors to end up a
+// little bit off. View 64001 renders fine using the existing palette created by
+// the background image, so just disable the embedded palette.
+static const byte phant1View64001Palette[] = {
+ SKIP(8),
+ REPLACE_NUMBER(uint32, 0),
+ END
+};
+
+#pragma mark -
+#pragma mark Police Quest 4
+
+// Police Quest 4 can support speech+subtitles mode but it includes no view that
+// can be used to show that this mode is active in the UI, so we have to add our
+// own.
+static const byte pq4EnhancedAudioToggleView[] = {
+ INSERT_NUMBER(uint16, 16), // header size
+ INSERT_NUMBER(uint8, 1), // loop count
+ INSERT(0x00, 0x01), // unused
+ INSERT_NUMBER(uint8, 0), // resolution flag
+ INSERT_NUMBER(uint16, 0), // unused
+ INSERT_NUMBER(uint32, 70), // palette offset
+ INSERT_NUMBER(uint8, 16), // loop header size
+ INSERT_NUMBER(uint8, 36), // cel header size
+ INSERT_NUMBER(uint16, 640), // x-resolution
+ INSERT_NUMBER(uint16, 480), // y-resolution
+ INSERT_NUMBER(int8, -1), // alternate loop header
+ INSERT_NUMBER(uint8, 0), // mirror flag
+ INSERT_NUMBER(uint8, 1), // cel count
+ INSERT_NUMBER(int32, -1), // unused
+ INSERT_NUMBER(uint8, 0), // unused
+ INSERT_NUMBER(uint32, 0), // unused
+ INSERT_NUMBER(uint32, 34), // cel header offset
+ INSERT_NUMBER(uint16, 85), // width
+ INSERT_NUMBER(uint16, 23), // height
+ INSERT_NUMBER(int16, 42), // x-origin
+ INSERT_NUMBER(int16, 22), // y-origin
+ INSERT_NUMBER(uint8, 255), // transparent color
+ INSERT_NUMBER(uint8, 0), // compression type (none)
+ INSERT_NUMBER(uint16, 0), // transparency/remap flags
+ INSERT_NUMBER(uint32, 0), // unused
+ INSERT_NUMBER(uint32, 0), // unused
+ INSERT_NUMBER(uint32, 0), // unused
+ INSERT_NUMBER(uint32, 0x46b), // data offset
+ INSERT_NUMBER(uint32, 0), // unused (for compressed data)
+ INSERT_NUMBER(uint32, 0), // unused (for compressed data)
+
+ // palette data
+ INSERT_NUMBER(uint8, 14), // magic number
+ INSERT_FILL(0x00, 9), // garbage
+ INSERT_NUMBER(uint8, 1), // number of palettes
+ INSERT_NUMBER(uint16, 0), // garbage
+ INSERT_NUMBER(uint8, 22), // first palette offset
+ INSERT_FILL(0x00, 11), // garbage
+ INSERT_NUMBER(uint8, 0), // start color
+ INSERT_FILL(0x00, 3), // garbage
+ INSERT_NUMBER(uint16, 256), // number of colors
+ INSERT_NUMBER(uint8, 1), // used
+ INSERT_NUMBER(uint8, 0), // shared used
+ INSERT_NUMBER(uint32, 0), // version
+ INSERT( // color data
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x1B, 0x1B, 0x1B, 0x01, 0x2B,
+ 0x2F, 0x2B, 0x01, 0x33, 0x33, 0x33, 0x01, 0x37, 0x3B, 0x37,
+ 0x01, 0x47, 0x47, 0x47, 0x01, 0x4B, 0x4B, 0x4B, 0x01, 0x53,
+ 0x57, 0x53, 0x01, 0x63, 0x67, 0x63, 0x01, 0x6B, 0x6B, 0x6B,
+ 0x01, 0x6F, 0x77, 0x6F, 0x01, 0x7B, 0x7F, 0x7B, 0x01, 0x93,
+ 0x9B, 0x93, 0x01, 0xAF, 0xB3, 0xAB, 0x01, 0x0F, 0x17, 0x3F,
+ 0x01, 0x1F, 0x27, 0x57, 0x01, 0x2B, 0x43, 0x6F, 0x01, 0x5B,
+ 0x87, 0xA7, 0x01, 0x63, 0x3B, 0x1B, 0x01, 0x97, 0x63, 0x3F,
+ 0x01, 0xCB, 0x7B, 0x4B, 0x01, 0xE3, 0xA3, 0x63, 0x01, 0x00,
+ 0xAF, 0x27, 0x01, 0x00, 0x87, 0x27, 0x01, 0x00, 0x5F, 0x23,
+ 0x01, 0x8B, 0x6B, 0x53, 0x01, 0xAB, 0x87, 0x67, 0x01, 0xC7,
+ 0xA3, 0x73, 0x01, 0xEF, 0xDB, 0x9B, 0x01, 0x57, 0x2B, 0x1F,
+ 0x01, 0x7F, 0x27, 0x1F, 0x01, 0x8F, 0x3F, 0x33, 0x01, 0xBB,
+ 0x3F, 0x33, 0x01, 0xCB, 0x4F, 0x33, 0x01, 0x07, 0x07, 0xCB,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF,
+ 0xFF, 0xFF
+ ),
+ INSERT_FILL(0x00, 872), // unused color entries
+
+ // pixel data
+ INSERT(
+ 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x07, 0x05, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x04, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04,
+ 0x05, 0x04, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x05, 0x04, 0x04, 0x05, 0x04, 0x04, 0x00, 0x04,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x04, 0x05, 0x04, 0x04,
+ 0x05, 0x04, 0x04, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x05, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05,
+ 0x04, 0x04, 0x05, 0x04, 0x04, 0x05, 0x04, 0x04, 0x00, 0x04,
+ 0x04, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x04, 0x00,
+ 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x04, 0x04,
+ 0x05, 0x04, 0x04, 0x00, 0x04, 0x04, 0x00, 0x00, 0x04, 0x04,
+ 0x04, 0x04, 0x16, 0x16, 0x04, 0x04, 0x16, 0x16, 0x16, 0x04,
+ 0x04, 0x16, 0x16, 0x16, 0x04, 0x16, 0x16, 0x16, 0x04, 0x04,
+ 0x16, 0x16, 0x04, 0x04, 0x16, 0x04, 0x04, 0x16, 0x04, 0x04,
+ 0x04, 0x05, 0x05, 0x04, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x16, 0x16, 0x16, 0x04, 0x16, 0x16, 0x16,
+ 0x04, 0x16, 0x04, 0x04, 0x04, 0x16, 0x04, 0x16, 0x16, 0x16,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05,
+ 0x04, 0x04, 0x05, 0x04, 0x04, 0x05, 0x04, 0x04, 0x00, 0x04,
+ 0x04, 0x00, 0x00, 0x04, 0x04, 0x04, 0x16, 0x04, 0x04, 0x16,
+ 0x04, 0x16, 0x04, 0x04, 0x16, 0x04, 0x16, 0x04, 0x04, 0x04,
+ 0x16, 0x04, 0x04, 0x04, 0x16, 0x04, 0x04, 0x16, 0x04, 0x16,
+ 0x04, 0x04, 0x16, 0x04, 0x04, 0x04, 0x05, 0x05, 0x04, 0x00,
+ 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x16,
+ 0x04, 0x04, 0x16, 0x04, 0x04, 0x04, 0x04, 0x16, 0x04, 0x16,
+ 0x04, 0x04, 0x04, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x04, 0x04,
+ 0x05, 0x04, 0x04, 0x00, 0x04, 0x04, 0x00, 0x00, 0x04, 0x04,
+ 0x04, 0x16, 0x04, 0x04, 0x04, 0x04, 0x16, 0x04, 0x04, 0x16,
+ 0x04, 0x16, 0x04, 0x04, 0x04, 0x16, 0x04, 0x04, 0x04, 0x16,
+ 0x04, 0x04, 0x04, 0x04, 0x16, 0x04, 0x04, 0x16, 0x04, 0x04,
+ 0x04, 0x05, 0x05, 0x04, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x16, 0x04, 0x04, 0x16, 0x04, 0x04,
+ 0x04, 0x04, 0x16, 0x04, 0x16, 0x04, 0x04, 0x04, 0x16, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05,
+ 0x04, 0x04, 0x05, 0x04, 0x04, 0x05, 0x04, 0x04, 0x00, 0x04,
+ 0x04, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x16, 0x04, 0x04,
+ 0x04, 0x16, 0x16, 0x16, 0x04, 0x04, 0x16, 0x16, 0x16, 0x04,
+ 0x16, 0x16, 0x16, 0x04, 0x16, 0x04, 0x04, 0x04, 0x04, 0x16,
+ 0x16, 0x16, 0x16, 0x04, 0x04, 0x04, 0x05, 0x05, 0x04, 0x00,
+ 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x16,
+ 0x04, 0x04, 0x16, 0x16, 0x16, 0x04, 0x04, 0x04, 0x16, 0x04,
+ 0x04, 0x04, 0x04, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x04, 0x04,
+ 0x05, 0x04, 0x04, 0x00, 0x04, 0x04, 0x00, 0x00, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x16, 0x04, 0x04, 0x16, 0x04, 0x04, 0x04,
+ 0x04, 0x16, 0x04, 0x04, 0x04, 0x16, 0x04, 0x04, 0x04, 0x16,
+ 0x04, 0x04, 0x04, 0x04, 0x16, 0x04, 0x04, 0x16, 0x04, 0x04,
+ 0x04, 0x05, 0x05, 0x04, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x16, 0x04, 0x04, 0x16, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x16, 0x04, 0x04, 0x04, 0x04, 0x16, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05,
+ 0x04, 0x04, 0x05, 0x04, 0x04, 0x05, 0x04, 0x04, 0x00, 0x04,
+ 0x04, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x16,
+ 0x04, 0x16, 0x04, 0x04, 0x04, 0x04, 0x16, 0x04, 0x04, 0x04,
+ 0x16, 0x04, 0x04, 0x04, 0x16, 0x04, 0x04, 0x04, 0x04, 0x16,
+ 0x04, 0x04, 0x16, 0x04, 0x04, 0x04, 0x05, 0x05, 0x04, 0x00,
+ 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x16,
+ 0x04, 0x04, 0x16, 0x04, 0x04, 0x04, 0x04, 0x16, 0x04, 0x16,
+ 0x04, 0x04, 0x04, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x04, 0x04,
+ 0x05, 0x04, 0x04, 0x00, 0x04, 0x04, 0x00, 0x00, 0x04, 0x04,
+ 0x04, 0x16, 0x04, 0x04, 0x16, 0x04, 0x16, 0x04, 0x04, 0x04,
+ 0x04, 0x16, 0x04, 0x04, 0x04, 0x16, 0x04, 0x04, 0x04, 0x16,
+ 0x04, 0x04, 0x16, 0x04, 0x16, 0x04, 0x04, 0x16, 0x04, 0x04,
+ 0x04, 0x05, 0x05, 0x04, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x16, 0x04, 0x04, 0x16, 0x04, 0x04,
+ 0x04, 0x04, 0x16, 0x04, 0x16, 0x04, 0x04, 0x04, 0x16, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05,
+ 0x04, 0x04, 0x05, 0x04, 0x04, 0x05, 0x04, 0x04, 0x00, 0x04,
+ 0x04, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x16, 0x16, 0x04,
+ 0x04, 0x16, 0x04, 0x04, 0x04, 0x04, 0x16, 0x16, 0x16, 0x04,
+ 0x16, 0x16, 0x16, 0x04, 0x04, 0x16, 0x16, 0x04, 0x04, 0x16,
+ 0x04, 0x04, 0x16, 0x04, 0x04, 0x04, 0x05, 0x05, 0x04, 0x00,
+ 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x16,
+ 0x04, 0x04, 0x16, 0x16, 0x16, 0x04, 0x16, 0x04, 0x04, 0x04,
+ 0x16, 0x04, 0x04, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x04, 0x04,
+ 0x05, 0x04, 0x04, 0x00, 0x04, 0x04, 0x00, 0x00, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x05, 0x05, 0x04, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05,
+ 0x04, 0x04, 0x05, 0x04, 0x04, 0x05, 0x04, 0x04, 0x00, 0x04,
+ 0x04, 0x00, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x07, 0x05, 0x04, 0x00,
+ 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x07, 0x05, 0x04, 0x04, 0x05, 0x04, 0x04,
+ 0x05, 0x04, 0x04, 0x00, 0x04, 0x04, 0x07, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x07, 0x04, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x07,
+ 0x04, 0x04, 0x05, 0x04, 0x04, 0x05, 0x04, 0x04, 0x00, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x04, 0x04,
+ 0x05, 0x04, 0x04, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x07, 0x04, 0x04, 0x05, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04
+ ),
+ END
+};
+
+#pragma mark -
+#pragma mark Patch table
+
+static const GameResourcePatch resourcePatches[] = {
+ { GID_PHANTASMAGORIA, Common::UNK_LANG, ResourceId(kResourceTypeView, 64001), phant1View64001Palette, false },
+ { GID_PQ4, Common::EN_ANY, ResourceId(kResourceTypeView, 20982), pq4EnhancedAudioToggleView, true }
+};
+
+#pragma mark -
+#pragma mark ResourcePatcher
+
+ResourcePatcher::ResourcePatcher(const SciGameId gameId, const Common::Language gameLanguage) :
+ ResourceSource(kSourceScummVM, "-scummvm-") {
+ for (int i = 0; i < ARRAYSIZE(resourcePatches); ++i) {
+ const GameResourcePatch &patch = resourcePatches[i];
+ if (patch.gameId == gameId &&
+ (patch.gameLanguage == Common::UNK_LANG || patch.gameLanguage == gameLanguage)) {
+ _patches.push_back(patch);
+ }
+ }
+}
+
+bool ResourcePatcher::applyPatch(Resource &resource) const {
+ PatchList::const_iterator it;
+ for (it = _patches.begin(); it != _patches.end(); ++it) {
+ if (it->resourceId == resource._id) {
+ debugC(kDebugLevelPatcher, "Applying resource patch to %s", resource._id.toString().c_str());
+ patchResource(resource, *it);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void ResourcePatcher::scanSource(ResourceManager *resMan) {
+ PatchList::const_iterator it;
+ for (it = _patches.begin(); it != _patches.end(); ++it) {
+ if (it->isNewResource && !resMan->testResource(it->resourceId)) {
+ // Unlike other resources, ResourcePatcher does not have any files
+ // to open to retrieve its resources, so the resource has to get
+ // created and added manually instead of going through
+ // `ResourceManager::addResource` or else the file validation will
+ // blow up.
+ Resource *res = new Resource(resMan, it->resourceId);
+ res->_status = kResStatusNoMalloc;
+ res->_source = this;
+ res->_headerSize = 0;
+ res->_fileOffset = 0;
+ res->_size = 0;
+ resMan->_resMap.setVal(it->resourceId, res);
+ }
+ }
+}
+
+void ResourcePatcher::patchResource(Resource &resource, const GameResourcePatch &patch) const {
+ const byte *oldData;
+ const byte *source = resource.data();
+ byte *target;
+
+ // New resources that came from ResourcePatcher need to get allocated or
+ // else they will keep getting patched over themselves
+ if (resource._source == this) {
+ if (resource._status != kResStatusNoMalloc) {
+ return;
+ }
+
+ resource._status = kResStatusAllocated;
+ }
+
+ const PatchSizes size = calculatePatchSizes(patch.patchData);
+ if (size.expected > resource.size()) {
+ warning("Unable to apply patch %s: patch expects at least %u bytes but resource is only %u bytes", patch.resourceId.toString().c_str(), size.expected, resource.size());
+ return;
+ }
+
+ if (size.delta != 0) {
+ // In the future it should be possible to have a negative size delta for
+ // resources that need to be truncated, but for now just keep it
+ // positive until there's a need for truncation
+ assert(size.delta > 0);
+
+ const int32 newSize = resource.size() + size.delta;
+ assert(newSize > 0);
+
+ target = new byte[newSize];
+ assert(target);
+
+ oldData = resource._data;
+ resource._data = target;
+ resource._size = newSize;
+ } else {
+ target = const_cast<byte *>(source);
+ oldData = nullptr;
+ }
+
+ const byte *patchData = patch.patchData;
+ ResourcePatchOp op;
+ while ((op = static_cast<ResourcePatchOp>(*patchData++)) != kEndOfPatch) {
+ switch (op) {
+ case kSkipBytes: {
+ const int32 skipSize = readBlockSize(patchData);
+ if (target != source) {
+ memcpy(target, source, skipSize);
+ }
+ source += skipSize;
+ target += skipSize;
+ break;
+ }
+ case kReplaceBytes:
+ case kInsertBytes: {
+ const int32 blockSize = readBlockSize(patchData);
+ memcpy(target, patchData, blockSize);
+ patchData += blockSize;
+ if (op == kReplaceBytes) {
+ source += blockSize;
+ }
+ target += blockSize;
+ break;
+ }
+ case kReplaceNumber:
+ case kAdjustNumber:
+ case kInsertNumber: {
+ const uint8 width = *patchData++;
+ assert(width == 1 || width == 2 || width == 4);
+
+ int32 value = *reinterpret_cast<const int32 *>(patchData);
+ switch (width) {
+ case 1:
+ if (op == kAdjustNumber) {
+ value += static_cast<int8>(*source);
+ }
+ assert(value >= -128 && value <= 255);
+ *target = value;
+ break;
+ case 2:
+ if (op == kAdjustNumber) {
+ value += static_cast<int16>(READ_SCI11ENDIAN_UINT16(source));
+ }
+ assert(value >= -32768 && value <= 65535);
+ WRITE_SCI11ENDIAN_UINT16(target, value);
+ break;
+ case 4:
+ if (op == kAdjustNumber) {
+ value += static_cast<int32>(READ_SCI11ENDIAN_UINT32(source));
+ }
+ WRITE_SCI11ENDIAN_UINT32(target, value);
+ break;
+ }
+
+ patchData += sizeof(int32);
+ if (op != kInsertNumber) {
+ source += width;
+ }
+ target += width;
+ break;
+ }
+ case kReplaceFill:
+ case kInsertFill: {
+ const int32 blockSize = readBlockSize(patchData);
+ const byte value = *patchData++;
+ memset(target, value, blockSize);
+ if (op != kInsertFill) {
+ source += blockSize;
+ }
+ target += blockSize;
+ break;
+ }
+ default:
+ error("Invalid control code %02x in patch data", op);
+ }
+ }
+
+ if (target != source) {
+ memcpy(target, source, resource._size - (target - resource._data));
+ }
+
+ delete[] oldData;
+}
+
+ResourcePatcher::PatchSizes ResourcePatcher::calculatePatchSizes(const byte *patchData) const {
+ int32 deltaSize = 0;
+ uint32 dataSize = 0;
+
+ ResourcePatchOp op;
+ while ((op = static_cast<ResourcePatchOp>(*patchData++)) != kEndOfPatch) {
+ switch (op) {
+ case kSkipBytes:
+ case kReplaceBytes:
+ case kInsertBytes: {
+ const int32 blockSize = readBlockSize(patchData);
+
+ if (op == kReplaceBytes || op == kInsertBytes) {
+ patchData += blockSize;
+ }
+
+ if (op == kInsertBytes) {
+ deltaSize += blockSize;
+ } else {
+ dataSize += blockSize;
+ }
+
+ break;
+ }
+ case kReplaceNumber:
+ case kAdjustNumber:
+ case kInsertNumber: {
+ const uint8 width = *patchData++;
+ assert(width == 1 || width == 2 || width == 4);
+
+ if (op == kInsertNumber) {
+ deltaSize += width;
+ } else {
+ dataSize += width;
+ }
+
+ patchData += /* value */ sizeof(int32);
+ break;
+ }
+ case kReplaceFill:
+ case kInsertFill: {
+ const int32 blockSize = readBlockSize(patchData);
+ /* value */ ++patchData;
+
+ if (op == kInsertFill) {
+ deltaSize += blockSize;
+ } else {
+ dataSize += blockSize;
+ }
+
+ break;
+ }
+ default:
+ error("Invalid control code %02x in patch data", op);
+ }
+ }
+
+ return { dataSize, deltaSize };
+}
+
+int32 ResourcePatcher::readBlockSize(const byte * &patchData) const {
+ const int32 blockSize = *reinterpret_cast<const int32 *>(patchData);
+ assert(blockSize >= 1);
+ patchData += sizeof(int32);
+ return blockSize;
+}
+} // End of namespace Sci
diff --git a/engines/sci/resource_patcher.h b/engines/sci/resource_patcher.h
new file mode 100644
index 0000000..860e4a6
--- /dev/null
+++ b/engines/sci/resource_patcher.h
@@ -0,0 +1,146 @@
+/* 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.
+ *
+ */
+
+#ifndef SCI_RESOURCE_PATCHER_H
+#define SCI_RESOURCE_PATCHER_H
+
+#include "common/language.h"
+#include "sci/sci.h"
+#include "sci/resource.h"
+#include "sci/resource_intern.h"
+
+namespace Sci {
+
+enum ResourcePatchOp {
+ // Using high bytes to make it less likely that accidental raw data will be
+ // treated like an operator instead of an error
+ kSkipBytes = 0xF0,
+ kReplaceBytes,
+ kInsertBytes,
+ kReplaceNumber,
+ kAdjustNumber,
+ kInsertNumber,
+ kReplaceFill,
+ kInsertFill,
+ kEndOfPatch
+};
+
+struct GameResourcePatch {
+ /**
+ * The game to patch.
+ */
+ SciGameId gameId;
+
+ /**
+ * The language to patch. Use `Common::UNK_LANG` to apply the patch to all
+ * languages.
+ */
+ Common::Language gameLanguage;
+
+ /**
+ * The resource ID to patch.
+ */
+ ResourceId resourceId;
+
+ /**
+ * Patch instructions to apply to the resource.
+ */
+ const byte *patchData;
+
+ /**
+ * Set to true if the patch resource is actually a new resource, rather than
+ * a patch for an existing resource.
+ */
+ bool isNewResource;
+};
+
+/**
+ * A basic class for generating patched resource data at runtime.
+ */
+class ResourcePatcher : public ResourceSource {
+public:
+ ResourcePatcher(const SciGameId gameId, const Common::Language gameLanguage);
+
+ virtual ~ResourcePatcher() {}
+
+ /**
+ * Finds and applies a patch to the given resource.
+ *
+ * @returns true if a patch was applied.
+ */
+ bool applyPatch(Resource &resource) const;
+
+ /**
+ * Adds new resources from the patch table to the resource manager. This
+ * is needed since otherwise tests for these resources via `kResCheck`
+ * would fail, and so they would never actually be loaded.
+ */
+ virtual void scanSource(ResourceManager *resMan) override;
+
+ /**
+ * Load a resource. Since resources using this source are patched explicitly
+ * after they get loaded by any other resource source, this method does
+ * nothing.
+ */
+ virtual void loadResource(ResourceManager *resMan, Resource *res) override {}
+
+private:
+ struct PatchSizes {
+ /**
+ * The minimum number of bytes required in the source data.
+ */
+ uint32 expected;
+
+ /**
+ * The difference in size between the original data and the patched
+ * data.
+ */
+ int32 delta;
+ };
+
+ typedef Common::Array<GameResourcePatch> PatchList;
+
+ /**
+ * The list of patches that should apply to the currently loaded game.
+ */
+ PatchList _patches;
+
+ /**
+ * Patches the given Resource using patch data from the given
+ * GameResourcePatch.
+ */
+ void patchResource(Resource &resource, const GameResourcePatch &patch) const;
+
+ /**
+ * Calculates expected and extra data sizes from the patch data.
+ */
+ PatchSizes calculatePatchSizes(const byte *patchData) const;
+
+ /**
+ * Reads an block size from the patch data, validates it, and advances the
+ * patch data pointer.
+ */
+ int32 readBlockSize(const byte * &patchData) const;
+};
+} // End of namespace Sci
+
+#endif
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index f44bed6..70e4129 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -129,7 +129,7 @@ SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc, SciGameId gam
DebugMan.addDebugChannel(kDebugLevelDclInflate, "DCL", "DCL inflate debugging");
DebugMan.addDebugChannel(kDebugLevelVM, "VM", "VM debugging");
DebugMan.addDebugChannel(kDebugLevelScripts, "Scripts", "Notifies when scripts are unloaded");
- DebugMan.addDebugChannel(kDebugLevelScriptPatcher, "ScriptPatcher", "Notifies when scripts are patched");
+ DebugMan.addDebugChannel(kDebugLevelPatcher, "Patcher", "Notifies when scripts or resources are patched");
DebugMan.addDebugChannel(kDebugLevelWorkarounds, "Workarounds", "Notifies when workarounds are triggered");
DebugMan.addDebugChannel(kDebugLevelVideo, "Video", "Video (SEQ, VMD, RBT) debugging");
DebugMan.addDebugChannel(kDebugLevelGame, "Game", "Debug calls from game scripts");
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index 8dd73ef..0c680fb 100644
--- a/engines/sci/sci.h
+++ b/engines/sci/sci.h
@@ -128,7 +128,7 @@ enum kDebugLevels {
kDebugLevelResMan = 1 << 19,
kDebugLevelOnStartup = 1 << 20,
kDebugLevelDebugMode = 1 << 21,
- kDebugLevelScriptPatcher = 1 << 22,
+ kDebugLevelPatcher = 1 << 22,
kDebugLevelWorkarounds = 1 << 23,
kDebugLevelVideo = 1 << 24,
kDebugLevelGame = 1 << 25
Commit: 3180528adf7a1777d991caa96fd1e0150c3278e0
https://github.com/scummvm/scummvm/commit/3180528adf7a1777d991caa96fd1e0150c3278e0
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2020-01-19T21:37:21+02:00
Commit Message:
SCI: Fix compilation with C90 and older language versions
Change the resource patcher's _NUMARGS macro to use a typedef
Changed paths:
engines/sci/resource_patcher.cpp
diff --git a/engines/sci/resource_patcher.cpp b/engines/sci/resource_patcher.cpp
index 528d89e..f869284 100644
--- a/engines/sci/resource_patcher.cpp
+++ b/engines/sci/resource_patcher.cpp
@@ -30,7 +30,8 @@ namespace Sci {
// Start of internal resource patcher macros. Please do not use these directly
// in resource patches.
-#define _NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
+using int_c_array = int[];
+#define _NUMARGS(...) (sizeof(int_c_array{__VA_ARGS__})/sizeof(int))
#ifdef SCUMM_LITTLE_ENDIAN
#define _PACKINT32(n) (((uint32)n) & 0xFF), (((uint32)n) >> 8 & 0xFF), (((uint32)n) >> 16 & 0xFF), (((uint32)n) >> 24 & 0xFF)
#else
Commit: 2185c50632b1a68717d501198c2aba032f175d0b
https://github.com/scummvm/scummvm/commit/2185c50632b1a68717d501198c2aba032f175d0b
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2020-01-19T21:37:21+02:00
Commit Message:
SCI32: Adapt the PQ4CD dual patch with our new view. Fixes bug #9690
Changed paths:
engines/sci/engine/script_patches.cpp
engines/sci/resource_patcher.cpp
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index 9bf95e7..94176c1 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -9120,36 +9120,45 @@ static const uint16 pq4CdSpeechAndSubtitlesSignature[] = {
SIG_END
};
+// Note: global 0x5a may contain the following values:
+// 1: subtitles
+// 2: speech
+// 3: both
static const uint16 pq4CdSpeechAndSubtitlesPatch[] = {
// iconText::init
0x76, // push0
0x41, 0x02, PATCH_UINT16(0x00), // call [our new subroutine which sets view+loop+cel], 0
0x33, 0x40, // jmp [to original init, super GCItem call]
// new code for setting view+loop+cel
- 0x34, PATCH_UINT16(0x2aeb), // ldi 10987
- 0x65, 0x78, // aTop mainView - always set this view, because it's used by 2 states
+ //
0x89, 0x5a, // lsg global[$5a]
0x35, 0x03, // ldi 3
0x1a, // eq?
- 0x31, 0x04, // bnt [skip over follow up code]
- // speech+subtitles mode
- 0x78, // push1
- 0x69, 0x7a, // sTop mainLoop
- 0x48, // ret
- 0x89, 0x5a, // lsg global[$5a]
- 0x35, 0x01, // ldi 1
- 0x12, // and
- 0x31, 0x04, // bnt [skip over follow up code]
- // subtitles mode
+ 0x31, 0x05, // bnt [skip over the view modification code]
+ //
+ // Mode 3: speech+subtitles
+ 0x34, PATCH_UINT16(0x2aec), // ldi 10988 (our new injected view, speech + subtitles)
+ 0x33, 0x03, // jmp [skip over the view modification code]
+ // Mode 1: subtitles
+ 0x34, PATCH_UINT16(0x2aeb), // ldi 10987 (subtitles view)
+ //
+ // common code for speech+subtitles / subtitles mode
+ 0x65, 0x78, // aTop mainView
0x76, // push0
0x69, 0x7a, // sTop mainLoop
- 0x48, // ret
- // speech mode
- 0x34, PATCH_UINT16(0x2ae6), // ldi 10982
+ //
+ 0x89, 0x5a, // lsg global[$5a]
+ 0x35, 0x02, // ldi 2
+ 0x1a, // eq?
+ 0x31, 0x09, // bnt [skip over follow up code]
+ //
+ // Mode 2: speech
+ 0x34, PATCH_UINT16(0x2ae6), // ldi 10982 (speech view)
0x65, 0x78, // aTop mainView
0x35, 0x0f, // ldi 15
0x65, 0x7a, // aTop mainLoop
0x48, // ret
+ //
PATCH_ADDTOOFFSET(+38), // skip to iconText::select
// iconText::select
diff --git a/engines/sci/resource_patcher.cpp b/engines/sci/resource_patcher.cpp
index f869284..2745fc1 100644
--- a/engines/sci/resource_patcher.cpp
+++ b/engines/sci/resource_patcher.cpp
@@ -383,7 +383,7 @@ static const byte pq4EnhancedAudioToggleView[] = {
static const GameResourcePatch resourcePatches[] = {
{ GID_PHANTASMAGORIA, Common::UNK_LANG, ResourceId(kResourceTypeView, 64001), phant1View64001Palette, false },
- { GID_PQ4, Common::EN_ANY, ResourceId(kResourceTypeView, 20982), pq4EnhancedAudioToggleView, true }
+ { GID_PQ4, Common::EN_ANY, ResourceId(kResourceTypeView, 10988), pq4EnhancedAudioToggleView, true }
};
#pragma mark -
More information about the Scummvm-git-logs
mailing list