aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
authorColin Snover2016-12-31 20:39:57 -0600
committerColin Snover2017-03-27 19:42:31 -0500
commit31daa956d62b39429cb6638ed3fb549ac488833a (patch)
treefa831adefae05d82209b3f565055f7b761ca8691 /engines/sci
parent1298762b7665dc1b7aeedf0271eadfb284309ef1 (diff)
downloadscummvm-rg350-31daa956d62b39429cb6638ed3fb549ac488833a.tar.gz
scummvm-rg350-31daa956d62b39429cb6638ed3fb549ac488833a.tar.bz2
scummvm-rg350-31daa956d62b39429cb6638ed3fb549ac488833a.zip
SCI: Implement bounds-checked reads of game resources
Diffstat (limited to 'engines/sci')
-rw-r--r--engines/sci/console.cpp81
-rw-r--r--engines/sci/detection.cpp16
-rw-r--r--engines/sci/engine/features.cpp2
-rw-r--r--engines/sci/engine/kernel.cpp24
-rw-r--r--engines/sci/engine/kernel.h4
-rw-r--r--engines/sci/engine/kparse.cpp6
-rw-r--r--engines/sci/engine/kvideo.cpp14
-rw-r--r--engines/sci/engine/message.cpp74
-rw-r--r--engines/sci/engine/object.cpp65
-rw-r--r--engines/sci/engine/object.h73
-rw-r--r--engines/sci/engine/savegame.cpp27
-rw-r--r--engines/sci/engine/script.cpp533
-rw-r--r--engines/sci/engine/script.h49
-rw-r--r--engines/sci/engine/script_patches.cpp34
-rw-r--r--engines/sci/engine/script_patches.h10
-rw-r--r--engines/sci/engine/scriptdebug.cpp140
-rw-r--r--engines/sci/engine/seg_manager.cpp8
-rw-r--r--engines/sci/engine/workarounds.cpp2
-rw-r--r--engines/sci/graphics/animate.cpp2
-rw-r--r--engines/sci/graphics/celobj32.cpp164
-rw-r--r--engines/sci/graphics/celobj32.h11
-rw-r--r--engines/sci/graphics/compare.cpp2
-rw-r--r--engines/sci/graphics/cursor.cpp63
-rw-r--r--engines/sci/graphics/cursor.h12
-rw-r--r--engines/sci/graphics/cursor32.cpp2
-rw-r--r--engines/sci/graphics/font.cpp50
-rw-r--r--engines/sci/graphics/font.h15
-rw-r--r--engines/sci/graphics/maciconbar.cpp4
-rw-r--r--engines/sci/graphics/palette.cpp30
-rw-r--r--engines/sci/graphics/palette.h5
-rw-r--r--engines/sci/graphics/palette32.cpp30
-rw-r--r--engines/sci/graphics/palette32.h8
-rw-r--r--engines/sci/graphics/picture.cpp226
-rw-r--r--engines/sci/graphics/picture.h26
-rw-r--r--engines/sci/graphics/portrait.cpp118
-rw-r--r--engines/sci/graphics/portrait.h19
-rw-r--r--engines/sci/graphics/ports.cpp12
-rw-r--r--engines/sci/graphics/ports.h4
-rw-r--r--engines/sci/graphics/screen.cpp37
-rw-r--r--engines/sci/graphics/screen.h13
-rw-r--r--engines/sci/graphics/screen_item32.cpp10
-rw-r--r--engines/sci/graphics/view.cpp268
-rw-r--r--engines/sci/graphics/view.h24
-rw-r--r--engines/sci/parser/vocabulary.cpp92
-rw-r--r--engines/sci/parser/vocabulary.h3
-rw-r--r--engines/sci/resource.cpp257
-rw-r--r--engines/sci/resource.h19
-rw-r--r--engines/sci/resource_audio.cpp181
-rw-r--r--engines/sci/sci.cpp6
-rw-r--r--engines/sci/sound/audio.cpp32
-rw-r--r--engines/sci/sound/drivers/adlib.cpp61
-rw-r--r--engines/sci/sound/drivers/amigamac.cpp2
-rw-r--r--engines/sci/sound/drivers/cms.cpp20
-rw-r--r--engines/sci/sound/drivers/fb01.cpp39
-rw-r--r--engines/sci/sound/drivers/fmtowns.cpp20
-rw-r--r--engines/sci/sound/drivers/midi.cpp248
-rw-r--r--engines/sci/sound/midiparser_sci.cpp14
-rw-r--r--engines/sci/sound/music.cpp8
-rw-r--r--engines/sci/sound/sync.cpp8
-rw-r--r--engines/sci/util.cpp2
-rw-r--r--engines/sci/util.h257
61 files changed, 1888 insertions, 1698 deletions
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index ae8ab14d84..eed0be1a82 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -526,16 +526,16 @@ bool Console::cmdOpcodes(int argc, const char **argv) {
return true;
}
- int count = READ_LE_UINT16(r->data);
+ int count = r->getUint16LEAt(0);
debugPrintf("Opcode names in numeric order [index: type name]:\n");
for (int i = 0; i < count; i++) {
- int offset = READ_LE_UINT16(r->data + 2 + i * 2);
- int len = READ_LE_UINT16(r->data + offset) - 2;
- int type = READ_LE_UINT16(r->data + offset + 2);
+ int offset = r->getUint16LEAt(2 + i * 2);
+ int len = r->getUint16LEAt(offset) - 2;
+ int type = r->getUint16LEAt(offset + 2);
// QFG3 has empty opcodes
- Common::String name = len > 0 ? Common::String((const char *)r->data + offset + 4, len) : "Dummy";
+ Common::String name = len > 0 ? r->getStringAt(offset + 4, len) : "Dummy";
debugPrintf("%03x: %03x %20s | ", i, type, name.c_str());
if ((i % 3) == 2)
debugPrintf("\n");
@@ -816,7 +816,7 @@ bool Console::cmdHexDump(int argc, const char **argv) {
else {
Resource *resource = _engine->getResMan()->findResource(ResourceId(res, resNum), 0);
if (resource) {
- Common::hexdump(resource->data, resource->size, 16, 0);
+ Common::hexdump(resource->getUnsafeDataAt(0), resource->size(), 16, 0);
debugPrintf("Resource %s.%03d has been dumped to standard output\n", argv[1], resNum);
} else {
debugPrintf("Resource %s.%03d not found\n", argv[1], resNum);
@@ -954,7 +954,7 @@ bool Console::cmdResourceInfo(int argc, const char **argv) {
else {
Resource *resource = _engine->getResMan()->findResource(ResourceId(res, resNum), 0);
if (resource) {
- debugPrintf("Resource size: %d\n", resource->size);
+ debugPrintf("Resource size: %lu\n", resource->size());
debugPrintf("Resource location: %s\n", resource->getResourceLocation().c_str());
} else {
debugPrintf("Resource %s.%03d not found\n", argv[1], resNum);
@@ -1015,8 +1015,8 @@ bool Console::cmdHexgrep(int argc, const char **argv) {
uint32 comppos = 0;
int output_script_name = 0;
- while (seeker < script->size) {
- if (script->data[seeker] == byteString[comppos]) {
+ while (seeker < script->size()) {
+ if (script->getUint8At(seeker) == byteString[comppos]) {
if (comppos == 0)
seekerold = seeker;
@@ -1066,13 +1066,13 @@ bool Console::cmdVerifyScripts(int argc, const char **argv) {
if (!heap)
debugPrintf("Error: script %d doesn't have a corresponding heap\n", itr->getNumber());
- if (script && heap && (script->size + heap->size > 65535))
- debugPrintf("Error: script and heap %d together are larger than 64KB (%d bytes)\n",
- itr->getNumber(), script->size + heap->size);
+ if (script && heap && (script->size() + heap->size() > 65535))
+ debugPrintf("Error: script and heap %d together are larger than 64KB (%lu bytes)\n",
+ itr->getNumber(), script->size() + heap->size());
} else { // SCI3
- if (script && script->size > 65535)
- debugPrintf("Error: script %d is larger than 64KB (%d bytes)\n",
- itr->getNumber(), script->size);
+ if (script && script->size() > 65535)
+ debugPrintf("Error: script %d is larger than 64KB (%lu bytes)\n",
+ itr->getNumber(), script->size());
}
}
@@ -1566,7 +1566,7 @@ bool Console::cmdSaid(int argc, const char **argv) {
spec[len++] = 0xFF;
debugN("Matching '%s' against:", string);
- _engine->getVocabulary()->debugDecipherSaidBlock(spec);
+ _engine->getVocabulary()->debugDecipherSaidBlock(SciSpan<const byte>(spec, len));
debugN("\n");
ResultWordListList words;
@@ -2113,9 +2113,10 @@ bool Console::segmentInfo(int nr) {
case SEG_TYPE_SCRIPT: {
Script *scr = (Script *)mobj;
debugPrintf("script.%03d locked by %d, bufsize=%d (%x)\n", scr->getScriptNumber(), scr->getLockers(), (uint)scr->getBufSize(), (uint)scr->getBufSize());
- if (scr->getExportTable())
- debugPrintf(" Exports: %4d at %d\n", scr->getExportsNr(), (int)(((const byte *)scr->getExportTable()) - ((const byte *)scr->getBuf())));
- else
+ if (scr->getExportsNr()) {
+ const uint location = scr->getExportsOffset();
+ debugPrintf(" Exports: %4d at %d\n", scr->getExportsNr(), location);
+ } else
debugPrintf(" Exports: none\n");
debugPrintf(" Synonyms: %4d\n", scr->getSynonymsNr());
@@ -3171,7 +3172,7 @@ void Console::printOffsets(int scriptNr, uint16 showType) {
saidPtr = curScriptData + arrayIterator->offset;
debugPrintf(" %03d:%04x:\n", arrayIterator->id, arrayIterator->offset);
debugN(" %03d:%04x: ", arrayIterator->id, arrayIterator->offset);
- vocab->debugDecipherSaidBlock(saidPtr);
+ vocab->debugDecipherSaidBlock(SciSpan<const byte>(saidPtr, (arrayIterator + 1)->offset - arrayIterator->offset));
debugN("\n");
break;
default:
@@ -3512,7 +3513,7 @@ void Console::printKernelCallsFound(int kernelFuncNum, bool showFoundScripts) {
byte opcode;
uint16 maxJmpOffset = 0;
- while (true) {
+ for (;;) {
offset += readPMachineInstruction(script->getBuf(offset), extOpcode, opparams);
opcode = extOpcode >> 1;
@@ -3946,7 +3947,7 @@ bool Console::cmdSfx01Header(int argc, const char **argv) {
return true;
}
- Resource *song = _engine->getResMan()->findResource(ResourceId(kResourceTypeSound, atoi(argv[1])), 0);
+ Resource *song = _engine->getResMan()->findResource(ResourceId(kResourceTypeSound, atoi(argv[1])), false);
if (!song) {
debugPrintf("Doesn't exist\n");
@@ -3957,36 +3958,36 @@ bool Console::cmdSfx01Header(int argc, const char **argv) {
debugPrintf("SCI01 song track mappings:\n");
- if (*song->data == 0xf0) // SCI1 priority spec
+ if (song->getUint8At(0) == 0xf0) // SCI1 priority spec
offset = 8;
- if (song->size <= 0)
+ if (song->size() <= 0)
return 1;
- while (song->data[offset] != 0xff) {
- byte device_id = song->data[offset];
+ while (song->getUint8At(offset) != 0xff) {
+ byte device_id = song->getUint8At(offset);
debugPrintf("* Device %02x:\n", device_id);
offset++;
- if (offset + 1 >= song->size)
+ if (offset + 1 >= song->size())
return 1;
- while (song->data[offset] != 0xff) {
+ while (song->getUint8At(offset) != 0xff) {
int track_offset;
int end;
byte header1, header2;
- if (offset + 7 >= song->size)
+ if (offset + 7 >= song->size())
return 1;
offset += 2;
- track_offset = READ_LE_UINT16(song->data + offset);
- header1 = song->data[track_offset];
- header2 = song->data[track_offset+1];
+ track_offset = song->getUint16LEAt(offset);
+ header1 = song->getUint8At(track_offset);
+ header2 = song->getUint8At(track_offset + 1);
track_offset += 2;
- end = READ_LE_UINT16(song->data + offset + 2);
+ end = song->getUint16LEAt(offset + 2);
debugPrintf(" - %04x -- %04x", track_offset, track_offset + end);
if (track_offset == 0xfe)
@@ -4002,7 +4003,7 @@ bool Console::cmdSfx01Header(int argc, const char **argv) {
return true;
}
-static int _parse_ticks(byte *data, int *offset_p, int size) {
+static int _parse_ticks(const byte *data, int *offset_p, int size) {
int ticks = 0;
int tempticks;
int offset = 0;
@@ -4019,7 +4020,7 @@ static int _parse_ticks(byte *data, int *offset_p, int size) {
}
// Specialised for SCI01 tracks (this affects the way cumulative cues are treated)
-static void midi_hexdump(byte *data, int size, int notational_offset) {
+static void midi_hexdump(const byte *data, int size, int notational_offset) {
int offset = 0;
int prev = 0;
const int MIDI_cmdlen[16] = {0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0};
@@ -4120,7 +4121,7 @@ bool Console::cmdSfx01Track(int argc, const char **argv) {
return true;
}
- midi_hexdump(song->data + offset, song->size, offset);
+ midi_hexdump(song->getUnsafeDataAt(offset), song->size() - offset, offset);
return true;
}
@@ -4141,9 +4142,9 @@ bool Console::cmdMapVocab994(int argc, const char **argv) {
return true;
}
- Resource *resource = _engine->_resMan->findResource(ResourceId(kResourceTypeVocab, 994), 0);
+ Resource *resource = _engine->_resMan->findResource(ResourceId(kResourceTypeVocab, 994), false);
const Object *obj = s->_segMan->getObject(reg);
- uint16 *data = (uint16 *) resource->data;
+ SciSpan<const uint16> data = resource->subspan<const uint16>(0);
uint32 first = atoi(argv[2]);
uint32 last = atoi(argv[3]);
Common::Array<bool> markers;
@@ -4152,8 +4153,8 @@ bool Console::cmdMapVocab994(int argc, const char **argv) {
if (!obj->isClass() && getSciVersion() != SCI_VERSION_3)
obj = s->_segMan->getObject(obj->getSuperClassSelector());
- first = MIN(first, (uint32) (resource->size / 2 - 2));
- last = MIN(last, (uint32) (resource->size / 2 - 2));
+ first = MIN<uint32>(first, resource->size() / 2 - 2);
+ last = MIN<uint32>(last, resource->size() / 2 - 2);
for (uint32 i = first; i <= last; ++i) {
uint16 ofs = data[i];
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index 5270398899..13b3326c08 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -648,18 +648,18 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
// As far as we know, these games store the messages of each language in separate
// resources, and it's not possible to detect that easily
// Also look for "%J" which is used in japanese games
- Resource *text = resMan.findResource(ResourceId(kResourceTypeText, 0), 0);
+ Resource *text = resMan.findResource(ResourceId(kResourceTypeText, 0), false);
uint seeker = 0;
if (text) {
- while (seeker < text->size) {
- if (text->data[seeker] == '#') {
- if (seeker + 1 < text->size)
- s_fallbackDesc.language = charToScummVMLanguage(text->data[seeker + 1]);
+ while (seeker < text->size()) {
+ if (text->getUint8At(seeker) == '#') {
+ if (seeker + 1 < text->size())
+ s_fallbackDesc.language = charToScummVMLanguage(text->getUint8At(seeker + 1));
break;
}
- if (text->data[seeker] == '%') {
- if ((seeker + 1 < text->size) && (text->data[seeker + 1] == 'J')) {
- s_fallbackDesc.language = charToScummVMLanguage(text->data[seeker + 1]);
+ if (text->getUint8At(seeker) == '%') {
+ if ((seeker + 1 < text->size()) && (text->getUint8At(seeker + 1) == 'J')) {
+ s_fallbackDesc.language = charToScummVMLanguage(text->getUint8At(seeker + 1));
break;
}
}
diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp
index e37a1651ef..40d380195d 100644
--- a/engines/sci/engine/features.cpp
+++ b/engines/sci/engine/features.cpp
@@ -448,7 +448,7 @@ SciVersion GameFeatures::detectMessageFunctionType() {
// Only v2 Message resources use the kGetMessage kernel function.
// v3-v5 use the kMessage kernel function.
- if (READ_SCI11ENDIAN_UINT32(res->data) / 1000 == 2)
+ if (res->getUint32SEAt(0) / 1000 == 2)
_messageFunctionType = SCI_VERSION_1_LATE;
else
_messageFunctionType = SCI_VERSION_1_1;
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index c7732c6b15..d029923d96 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -149,13 +149,13 @@ void Kernel::loadSelectorNames() {
return;
}
- int count = (isBE ? READ_BE_UINT16(r->data) : READ_LE_UINT16(r->data)) + 1; // Counter is slightly off
+ int count = (isBE ? r->getUint16BEAt(0) : r->getUint16LEAt(0)) + 1; // Counter is slightly off
for (int i = 0; i < count; i++) {
- int offset = isBE ? READ_BE_UINT16(r->data + 2 + i * 2) : READ_LE_UINT16(r->data + 2 + i * 2);
- int len = isBE ? READ_BE_UINT16(r->data + offset) : READ_LE_UINT16(r->data + offset);
+ int offset = isBE ? r->getUint16BEAt(2 + i * 2) : r->getUint16LEAt(2 + i * 2);
+ int len = isBE ? r->getUint16BEAt(offset) : r->getUint16LEAt(offset);
- Common::String tmp((const char *)r->data + offset + 2, len);
+ Common::String tmp = r->getStringAt(offset + 2, len);
_selectorNames.push_back(tmp);
//debug("%s", tmp.c_str());
@@ -940,33 +940,27 @@ void Kernel::loadKernelNames(GameFeatures *features) {
}
Common::String Kernel::lookupText(reg_t address, int index) {
- char *seeker;
- Resource *textres;
-
if (address.getSegment())
return _segMan->getString(address);
- int textlen;
- int _index = index;
- textres = _resMan->findResource(ResourceId(kResourceTypeText, address.getOffset()), 0);
+ Resource *textres = _resMan->findResource(ResourceId(kResourceTypeText, address.getOffset()), false);
if (!textres) {
error("text.%03d not found", address.getOffset());
- return NULL; /* Will probably segfault */
}
- textlen = textres->size;
- seeker = (char *) textres->data;
+ int textlen = textres->size();
+ const char *seeker = (const char *)textres->getUnsafeDataAt(0);
+ int _index = index;
while (index--)
- while ((textlen--) && (*seeker++))
+ while (textlen-- && *seeker++)
;
if (textlen)
return seeker;
error("Index %d out of bounds in text.%03d", _index, address.getOffset());
- return NULL;
}
// TODO: script_adjust_opcode_formats should probably be part of the
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index 335fec06ad..51f4b5dbcb 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -171,8 +171,8 @@ public:
// Script dissection/dumping functions
void dissectScript(int scriptNumber, Vocabulary *vocab);
- void dumpScriptObject(char *data, int seeker, int objsize);
- void dumpScriptClass(char *data, int seeker, int objsize);
+ void dumpScriptObject(const SciSpan<const byte> &script, SciSpan<const byte> object);
+ void dumpScriptClass(const SciSpan<const byte> &script, SciSpan<const byte> clazz);
SelectorCache _selectorCache; /**< Shortcut list for important selectors. */
typedef Common::Array<KernelFunction> KernelFunctionArray;
diff --git a/engines/sci/engine/kparse.cpp b/engines/sci/engine/kparse.cpp
index f85f33e3e8..d3bf2d72e9 100644
--- a/engines/sci/engine/kparse.cpp
+++ b/engines/sci/engine/kparse.cpp
@@ -188,7 +188,7 @@ reg_t kSetSynonyms(EngineState *s, int argc, reg_t *argv) {
numSynonyms = s->_segMan->getScript(seg)->getSynonymsNr();
if (numSynonyms) {
- const byte *synonyms = s->_segMan->getScript(seg)->getSynonyms();
+ const SciSpan<const byte> &synonyms = s->_segMan->getScript(seg)->getSynonyms();
if (synonyms) {
debugC(kDebugLevelParser, "Setting %d synonyms for script.%d",
@@ -202,8 +202,8 @@ reg_t kSetSynonyms(EngineState *s, int argc, reg_t *argv) {
} else
for (int i = 0; i < numSynonyms; i++) {
synonym_t tmp;
- tmp.replaceant = READ_LE_UINT16(synonyms + i * 4);
- tmp.replacement = READ_LE_UINT16(synonyms + i * 4 + 2);
+ tmp.replaceant = synonyms.getUint16LEAt(i * 4);
+ tmp.replacement = synonyms.getUint16LEAt(i * 4 + 2);
voc->addSynonym(tmp);
}
} else
diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp
index 11378d7647..3d689f2b42 100644
--- a/engines/sci/engine/kvideo.cpp
+++ b/engines/sci/engine/kvideo.cpp
@@ -27,8 +27,10 @@
#include "sci/graphics/cursor.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/screen.h"
+#include "sci/util.h"
#include "common/events.h"
#include "common/keyboard.h"
+#include "common/span.h"
#include "common/str.h"
#include "common/system.h"
#include "common/textconsole.h"
@@ -53,19 +55,21 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) {
videoDecoder->start();
- byte *scaleBuffer = 0;
+ Common::SpanOwner<SciSpan<byte> > scaleBuffer;
byte bytesPerPixel = videoDecoder->getPixelFormat().bytesPerPixel;
uint16 width = videoDecoder->getWidth();
uint16 height = videoDecoder->getHeight();
uint16 pitch = videoDecoder->getWidth() * bytesPerPixel;
uint16 screenWidth = g_sci->_gfxScreen->getDisplayWidth();
uint16 screenHeight = g_sci->_gfxScreen->getDisplayHeight();
+ uint32 numPixels;
if (screenWidth == 640 && width <= 320 && height <= 240) {
width *= 2;
height *= 2;
pitch *= 2;
- scaleBuffer = new byte[width * height * bytesPerPixel];
+ numPixels = width * height * bytesPerPixel;
+ scaleBuffer->allocate(numPixels, videoState.fileName + " scale buffer");
}
uint16 x = (screenWidth - width) / 2;
@@ -84,9 +88,10 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) {
if (frame) {
if (scaleBuffer) {
+ const SciSpan<const byte> input((const byte *)frame->getPixels(), frame->w * frame->h * bytesPerPixel);
// TODO: Probably should do aspect ratio correction in KQ6
- g_sci->_gfxScreen->scale2x((const byte *)frame->getPixels(), scaleBuffer, videoDecoder->getWidth(), videoDecoder->getHeight(), bytesPerPixel);
- g_system->copyRectToScreen(scaleBuffer, pitch, x, y, width, height);
+ g_sci->_gfxScreen->scale2x(input, *scaleBuffer, videoDecoder->getWidth(), videoDecoder->getHeight(), bytesPerPixel);
+ g_system->copyRectToScreen(scaleBuffer->getUnsafeDataAt(0, pitch * height), pitch, x, y, width, height);
} else {
g_system->copyRectToScreen(frame->getPixels(), frame->pitch, x, y, width, height);
}
@@ -111,7 +116,6 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) {
g_system->delayMillis(10);
}
- delete[] scaleBuffer;
delete videoDecoder;
}
diff --git a/engines/sci/engine/message.cpp b/engines/sci/engine/message.cpp
index 5e07ead5d7..c30ad3aee4 100644
--- a/engines/sci/engine/message.cpp
+++ b/engines/sci/engine/message.cpp
@@ -39,13 +39,13 @@ struct MessageRecord {
class MessageReader {
public:
bool init() {
- if (_headerSize > _size)
+ if (_headerSize > _data.size())
return false;
// Read message count from last word in header
- _messageCount = READ_SCI11ENDIAN_UINT16(_data + _headerSize - 2);
+ _messageCount = _data.getUint16SEAt(_headerSize - 2);
- if (_messageCount * _recordSize + _headerSize > _size)
+ if (_messageCount * _recordSize + _headerSize > _data.size())
return false;
return true;
@@ -56,11 +56,10 @@ public:
virtual ~MessageReader() { }
protected:
- MessageReader(const byte *data, uint size, uint headerSize, uint recordSize)
- : _data(data), _size(size), _headerSize(headerSize), _recordSize(recordSize), _messageCount(0) { }
+ MessageReader(const SciSpan<const byte> &data, uint headerSize, uint recordSize)
+ : _data(data), _headerSize(headerSize), _recordSize(recordSize), _messageCount(0) { }
- const byte *_data;
- const uint _size;
+ const SciSpan<const byte> _data;
const uint _headerSize;
const uint _recordSize;
uint _messageCount;
@@ -68,22 +67,22 @@ protected:
class MessageReaderV2 : public MessageReader {
public:
- MessageReaderV2(byte *data, uint size) : MessageReader(data, size, 6, 4) { }
+ MessageReaderV2(const SciSpan<const byte> &data) : MessageReader(data, 6, 4) { }
bool findRecord(const MessageTuple &tuple, MessageRecord &record) {
- const byte *recordPtr = _data + _headerSize;
+ SciSpan<const byte> recordPtr = _data.subspan(_headerSize);
for (uint i = 0; i < _messageCount; i++) {
if ((recordPtr[0] == tuple.noun) && (recordPtr[1] == tuple.verb)) {
record.tuple = tuple;
record.refTuple = MessageTuple();
record.talker = 0;
- const uint16 stringOffset = READ_LE_UINT16(recordPtr + 2);
- const uint32 maxSize = _size - stringOffset;
- record.string = (const char *)_data + stringOffset;
+ const uint16 stringOffset = recordPtr.getUint16LEAt(2);
+ const uint32 maxSize = _data.size() - stringOffset;
+ record.string = (const char *)_data.getUnsafeDataAt(stringOffset, maxSize);
record.length = Common::strnlen(record.string, maxSize);
if (record.length == maxSize) {
- warning("Message %s appears truncated at %ld", tuple.toString().c_str(), recordPtr - _data);
+ warning("Message %s from %s appears truncated at %ld", tuple.toString().c_str(), _data.name().c_str(), recordPtr - _data);
}
return true;
}
@@ -96,23 +95,22 @@ public:
class MessageReaderV3 : public MessageReader {
public:
- MessageReaderV3(byte *data, uint size) : MessageReader(data, size, 8, 10) { }
+ MessageReaderV3(const SciSpan<const byte> &data) : MessageReader(data, 8, 10) { }
bool findRecord(const MessageTuple &tuple, MessageRecord &record) {
- const byte *recordPtr = _data + _headerSize;
-
+ SciSpan<const byte> recordPtr = _data.subspan(_headerSize);
for (uint i = 0; i < _messageCount; i++) {
if ((recordPtr[0] == tuple.noun) && (recordPtr[1] == tuple.verb)
&& (recordPtr[2] == tuple.cond) && (recordPtr[3] == tuple.seq)) {
record.tuple = tuple;
record.refTuple = MessageTuple();
record.talker = recordPtr[4];
- const uint16 stringOffset = READ_LE_UINT16(recordPtr + 5);
- const uint32 maxSize = _size - stringOffset;
- record.string = (const char *)_data + stringOffset;
+ const uint16 stringOffset = recordPtr.getUint16LEAt(5);
+ const uint32 maxSize = _data.size() - stringOffset;
+ record.string = (const char *)_data.getUnsafeDataAt(stringOffset, maxSize);
record.length = Common::strnlen(record.string, maxSize);
if (record.length == maxSize) {
- warning("Message %s appears truncated at %ld", tuple.toString().c_str(), recordPtr - _data);
+ warning("Message %s from %s appears truncated at %ld", tuple.toString().c_str(), _data.name().c_str(), recordPtr - _data);
}
return true;
}
@@ -125,23 +123,22 @@ public:
class MessageReaderV4 : public MessageReader {
public:
- MessageReaderV4(byte *data, uint size) : MessageReader(data, size, 10, 11) { }
+ MessageReaderV4(const SciSpan<const byte> &data) : MessageReader(data, 10, 11) { }
bool findRecord(const MessageTuple &tuple, MessageRecord &record) {
- const byte *recordPtr = _data + _headerSize;
-
+ SciSpan<const byte> recordPtr = _data.subspan(_headerSize);
for (uint i = 0; i < _messageCount; i++) {
if ((recordPtr[0] == tuple.noun) && (recordPtr[1] == tuple.verb)
&& (recordPtr[2] == tuple.cond) && (recordPtr[3] == tuple.seq)) {
record.tuple = tuple;
record.refTuple = MessageTuple(recordPtr[7], recordPtr[8], recordPtr[9]);
record.talker = recordPtr[4];
- const uint16 stringOffset = READ_SCI11ENDIAN_UINT16(recordPtr + 5);
- const uint32 maxSize = _size - stringOffset;
- record.string = (const char *)_data + stringOffset;
+ const uint16 stringOffset = recordPtr.getUint16SEAt(5);
+ const uint32 maxSize = _data.size() - stringOffset;
+ record.string = (const char *)_data.getUnsafeDataAt(stringOffset, maxSize);
record.length = Common::strnlen(record.string, maxSize);
if (record.length == maxSize) {
- warning("Message %s appears truncated at %ld", tuple.toString().c_str(), recordPtr - _data);
+ warning("Message %s from %s appears truncated at %ld", tuple.toString().c_str(), _data.name().c_str(), recordPtr - _data);
}
return true;
}
@@ -157,23 +154,22 @@ public:
// the talker and the string...
class MessageReaderV4_MacSCI32 : public MessageReader {
public:
- MessageReaderV4_MacSCI32(byte *data, uint size) : MessageReader(data, size, 10, 12) { }
+ MessageReaderV4_MacSCI32(const SciSpan<const byte> &data) : MessageReader(data, 10, 12) { }
bool findRecord(const MessageTuple &tuple, MessageRecord &record) {
- const byte *recordPtr = _data + _headerSize;
-
+ SciSpan<const byte> recordPtr = _data.subspan(_headerSize);
for (uint i = 0; i < _messageCount; i++) {
if ((recordPtr[0] == tuple.noun) && (recordPtr[1] == tuple.verb)
&& (recordPtr[2] == tuple.cond) && (recordPtr[3] == tuple.seq)) {
record.tuple = tuple;
record.refTuple = MessageTuple(recordPtr[8], recordPtr[9], recordPtr[10]);
record.talker = recordPtr[4];
- const uint16 stringOffset = READ_BE_UINT16(recordPtr + 6);
- const uint32 maxSize = _size - stringOffset;
- record.string = (const char *)_data + stringOffset;
+ const uint16 stringOffset = recordPtr.getUint16BEAt(6);
+ const uint32 maxSize = _data.size() - stringOffset;
+ record.string = (const char *)_data.getUnsafeDataAt(stringOffset, maxSize);
record.length = Common::strnlen(record.string, maxSize);
if (record.length == maxSize) {
- warning("Message %s appears truncated at %ld", tuple.toString().c_str(), recordPtr - _data);
+ warning("Message %s from %s appears truncated at %ld", tuple.toString().c_str(), _data.name().c_str(), recordPtr - _data);
}
return true;
}
@@ -194,24 +190,24 @@ bool MessageState::getRecord(CursorStack &stack, bool recurse, MessageRecord &re
}
MessageReader *reader;
- int version = READ_SCI11ENDIAN_UINT32(res->data) / 1000;
+ int version = res->getUint32SEAt(0) / 1000;
switch (version) {
case 2:
- reader = new MessageReaderV2(res->data, res->size);
+ reader = new MessageReaderV2(*res);
break;
case 3:
- reader = new MessageReaderV3(res->data, res->size);
+ reader = new MessageReaderV3(*res);
break;
case 4:
#ifdef ENABLE_SCI32
case 5: // v5 seems to be compatible with v4
// SCI32 Mac is different than SCI32 DOS/Win here
if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1_EARLY)
- reader = new MessageReaderV4_MacSCI32(res->data, res->size);
+ reader = new MessageReaderV4_MacSCI32(*res);
else
#endif
- reader = new MessageReaderV4(res->data, res->size);
+ reader = new MessageReaderV4(*res);
break;
default:
error("Message: unsupported resource version %d", version);
diff --git a/engines/sci/engine/object.cpp b/engines/sci/engine/object.cpp
index 0566d6955f..2a6c96664b 100644
--- a/engines/sci/engine/object.cpp
+++ b/engines/sci/engine/object.cpp
@@ -51,24 +51,25 @@ static bool relocateBlock(Common::Array<reg_t> &block, int block_location, Segme
return true;
}
-void Object::init(byte *buf, reg_t obj_pos, bool initVariables) {
- byte *data = buf + obj_pos.getOffset();
+void Object::init(const SciSpan<const byte> &buf, reg_t obj_pos, bool initVariables) {
+ const SciSpan<const byte> data = buf.subspan(obj_pos.getOffset());
_baseObj = data;
_pos = obj_pos;
if (getSciVersion() <= SCI_VERSION_1_LATE) {
- _variables.resize(READ_LE_UINT16(data + kOffsetSelectorCounter));
- _baseVars = (const uint16 *)(_baseObj + _variables.size() * 2);
- _methodCount = READ_LE_UINT16(data + READ_LE_UINT16(data + kOffsetFunctionArea) - 2);
+ const SciSpan<const byte> header = buf.subspan(obj_pos.getOffset() - kOffsetHeaderSize);
+ _variables.resize(header.getUint16LEAt(kOffsetHeaderSelectorCounter));
+ _baseVars = _baseObj.subspan<const uint16>(_variables.size() * sizeof(uint16));
+ _methodCount = data.getUint16LEAt(header.getUint16LEAt(kOffsetHeaderFunctionArea) - 2);
for (int i = 0; i < _methodCount * 2 + 2; ++i) {
- _baseMethod.push_back(READ_SCI11ENDIAN_UINT16(data + READ_LE_UINT16(data + kOffsetFunctionArea) + i * 2));
+ _baseMethod.push_back(data.getUint16SEAt(header.getUint16LEAt(kOffsetHeaderFunctionArea) + i * 2));
}
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
- _variables.resize(READ_SCI11ENDIAN_UINT16(data + 2));
- _baseVars = (const uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 4));
- _methodCount = READ_SCI11ENDIAN_UINT16(buf + READ_SCI11ENDIAN_UINT16(data + 6));
+ _variables.resize(data.getUint16SEAt(2));
+ _baseVars = buf.subspan<const uint16>(data.getUint16SEAt(4), _variables.size() * sizeof(uint16));
+ _methodCount = buf.getUint16SEAt(data.getUint16SEAt(6));
for (int i = 0; i < _methodCount * 2 + 3; ++i) {
- _baseMethod.push_back(READ_SCI11ENDIAN_UINT16(buf + READ_SCI11ENDIAN_UINT16(data + 6) + i * 2));
+ _baseMethod.push_back(buf.getUint16SEAt(data.getUint16SEAt(6) + i * 2));
}
} else if (getSciVersion() == SCI_VERSION_3) {
initSelectorsSci3(buf);
@@ -77,9 +78,9 @@ void Object::init(byte *buf, reg_t obj_pos, bool initVariables) {
if (initVariables) {
if (getSciVersion() <= SCI_VERSION_2_1_LATE) {
for (uint i = 0; i < _variables.size(); i++)
- _variables[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(data + (i * 2)));
+ _variables[i] = make_reg(0, data.getUint16SEAt(i * 2));
} else {
- _infoSelectorSci3 = make_reg(0, READ_SCI11ENDIAN_UINT16(_baseObj + 10));
+ _infoSelectorSci3 = make_reg(0, _baseObj.getUint16SEAt(10));
}
}
}
@@ -89,20 +90,20 @@ const Object *Object::getClass(SegManager *segMan) const {
}
int Object::locateVarSelector(SegManager *segMan, Selector slc) const {
- const byte *buf = 0;
+ SciSpan<const byte> buf;
uint varnum = 0;
if (getSciVersion() <= SCI_VERSION_2_1_LATE) {
const Object *obj = getClass(segMan);
varnum = getSciVersion() <= SCI_VERSION_1_LATE ? getVarCount() : obj->getVariable(1).toUint16();
- buf = (const byte *)obj->_baseVars;
+ buf = obj->_baseVars.subspan<const byte>(0);
} else if (getSciVersion() == SCI_VERSION_3) {
varnum = _variables.size();
- buf = (const byte *)_baseVars;
+ buf = _baseVars.subspan<const byte>(0);
}
for (uint i = 0; i < varnum; i++)
- if (READ_SCI11ENDIAN_UINT16(buf + (i << 1)) == slc) // Found it?
+ if (buf.getUint16SEAt(i << 1) == slc) // Found it?
return i; // report success
return -1; // Failed
@@ -136,14 +137,14 @@ int Object::propertyOffsetToId(SegManager *segMan, int propertyOffset) const {
}
if (getSciVersion() < SCI_VERSION_1_1) {
- const byte *selectoroffset = ((const byte *)(_baseObj)) + kOffsetSelectorSegment + selectors * 2;
- return READ_SCI11ENDIAN_UINT16(selectoroffset + propertyOffset);
+ const SciSpan<const byte> selectoroffset = _baseObj.subspan(kOffsetSelectorSegment + selectors * 2);
+ return selectoroffset.getUint16SEAt(propertyOffset);
} else {
const Object *obj = this;
if (!isClass())
obj = segMan->getObject(getSuperClassSelector());
- return READ_SCI11ENDIAN_UINT16((const byte *)obj->_baseVars + propertyOffset);
+ return obj->_baseVars.subspan<const byte>(0).getUint16SEAt(propertyOffset);
}
}
@@ -246,9 +247,9 @@ bool Object::initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClas
const int EXTRA_GROUPS = 3;
-void Object::initSelectorsSci3(const byte *buf) {
- const byte *groupInfo = _baseObj + 16;
- const byte *selectorBase = groupInfo + EXTRA_GROUPS * 32 * 2;
+void Object::initSelectorsSci3(const SciSpan<const byte> &buf) {
+ const SciSpan<const byte> groupInfo = _baseObj.subspan(16);
+ const SciSpan<const byte> selectorBase = groupInfo.subspan(EXTRA_GROUPS * 32 * 2);
int groups = g_sci->getKernel()->getSelectorNamesSize()/32;
int methods, properties;
@@ -266,16 +267,16 @@ void Object::initSelectorsSci3(const byte *buf) {
// there are, so we count them first.
for (int groupNr = 0; groupNr < groups; ++groupNr) {
byte groupLocation = groupInfo[groupNr];
- const byte *seeker = selectorBase + groupLocation * 32 * 2;
+ const SciSpan<const byte> seeker = selectorBase.subspan(groupLocation * 32 * 2);
if (groupLocation != 0) {
// This object actually has selectors belonging to this group
- int typeMask = READ_SCI11ENDIAN_UINT32(seeker);
+ int typeMask = seeker.getUint32SEAt(0);
_mustSetViewVisible[groupNr] = (typeMask & 1);
for (int bit = 2; bit < 32; ++bit) {
- int value = READ_SCI11ENDIAN_UINT16(seeker + bit * 2);
+ int value = seeker.getUint16SEAt(bit * 2);
if (typeMask & (1 << bit)) { // Property
++properties;
} else if (value != 0xffff) { // Method
@@ -300,15 +301,15 @@ void Object::initSelectorsSci3(const byte *buf) {
// and method pointers
for (int groupNr = 0; groupNr < groups; ++groupNr) {
byte groupLocation = groupInfo[groupNr];
- const byte *seeker = selectorBase + groupLocation * 32 * 2;
+ const SciSpan<const byte> seeker = selectorBase.subspan(groupLocation * 32 * 2);
if (groupLocation != 0) {
// This object actually has selectors belonging to this group
- int typeMask = READ_SCI11ENDIAN_UINT32(seeker);
+ int typeMask = seeker.getUint32SEAt(0);
int groupBaseId = groupNr * 32;
for (int bit = 2; bit < 32; ++bit) {
- int value = READ_SCI11ENDIAN_UINT16(seeker + bit * 2);
+ int value = seeker.getUint16SEAt(bit * 2);
if (typeMask & (1 << bit)) { // Property
// FIXME: We really shouldn't be doing endianness
@@ -325,7 +326,7 @@ void Object::initSelectorsSci3(const byte *buf) {
++propertyCounter;
} else if (value != 0xffff) { // Method
_baseMethod.push_back(groupBaseId + bit);
- _baseMethod.push_back(value + READ_SCI11ENDIAN_UINT32(buf));
+ _baseMethod.push_back(value + buf.getUint32SEAt(0));
// methodOffsets[methodCounter] = (seeker + bit * 2) - buf;
++methodCounter;
} else {
@@ -336,10 +337,10 @@ void Object::initSelectorsSci3(const byte *buf) {
}
}
- _speciesSelectorSci3 = make_reg(0, READ_SCI11ENDIAN_UINT16(_baseObj + 4));
- _superClassPosSci3 = make_reg(0, READ_SCI11ENDIAN_UINT16(_baseObj + 8));
+ _speciesSelectorSci3 = make_reg(0, _baseObj.getUint16SEAt(4));
+ _superClassPosSci3 = make_reg(0, _baseObj.getUint16SEAt(8));
- _baseVars = propertyIds;
+ _baseVars = SciSpan<const uint16>(propertyIds, properties);
_methodCount = methods;
_propertyOffsetsSci3 = propertyOffsets;
//_methodOffsetsSci3 = methodOffsets;
diff --git a/engines/sci/engine/object.h b/engines/sci/engine/object.h
index 74a908a810..61f942c04a 100644
--- a/engines/sci/engine/object.h
+++ b/engines/sci/engine/object.h
@@ -59,9 +59,11 @@ enum infoSelectorFlags {
};
enum ObjectOffsets {
- kOffsetLocalVariables = -6,
- kOffsetFunctionArea = -4,
- kOffsetSelectorCounter = -2,
+ kOffsetHeaderSize = 6,
+ kOffsetHeaderLocalVariables = 0,
+ kOffsetHeaderFunctionArea = 2,
+ kOffsetHeaderSelectorCounter = 4,
+
kOffsetSelectorSegment = 0,
kOffsetInfoSelectorSci0 = 4,
kOffsetNamePointerSci0 = 6,
@@ -74,21 +76,48 @@ public:
Object() {
_offset = getSciVersion() < SCI_VERSION_1_1 ? 0 : 5;
_flags = 0;
- _baseObj = 0;
- _baseVars = 0;
+ _baseObj.clear();
+ _baseVars.clear();
_methodCount = 0;
- _propertyOffsetsSci3 = 0;
+ _propertyOffsetsSci3 = nullptr;
}
~Object() {
if (getSciVersion() == SCI_VERSION_3) {
- // FIXME: memory leak! Commented out because of reported heap
- // corruption by MSVC (e.g. in LSL7, when it starts)
- //free(_baseVars);
- //_baseVars = 0;
- //free(_propertyOffsetsSci3);
- //_propertyOffsetsSci3 = 0;
+ // TODO: This is super gross
+ free(const_cast<uint16 *>(_baseVars.data()));
+ _baseVars.clear();
+ free(_propertyOffsetsSci3);
+ _propertyOffsetsSci3 = nullptr;
+ }
+ }
+
+ Object &operator=(const Object &other) {
+ _baseObj = other._baseObj;
+ _baseMethod = other._baseMethod;
+ _variables = other._variables;
+ _methodCount = other._methodCount;
+ _flags = other._flags;
+ _offset = other._offset;
+ _pos = other._pos;
+
+ if (getSciVersion() == SCI_VERSION_3) {
+ uint16 *baseVars = (uint16 *)malloc(other._baseVars.byteSize());
+ other._baseVars.unsafeCopyDataTo(baseVars);
+ _baseVars = SciSpan<const uint16>(baseVars, other._baseVars.size());
+
+ _propertyOffsetsSci3 = (uint32 *)malloc(sizeof(uint32) * _variables.size());
+ memcpy(_propertyOffsetsSci3, other._propertyOffsetsSci3, sizeof(uint32) * _variables.size());
+
+ _superClassPosSci3 = other._superClassPosSci3;
+ _speciesSelectorSci3 = other._speciesSelectorSci3;
+ _infoSelectorSci3 = other._infoSelectorSci3;
+ _mustSetViewVisible = other._mustSetViewVisible;
+ } else {
+ _baseVars = other._baseVars;
}
+
+ return *this;
}
reg_t getSpeciesSelector() const {
@@ -181,7 +210,7 @@ public:
if (getSciVersion() < SCI_VERSION_3)
return _variables[4];
else // SCI3
- return make_reg(0, READ_SCI11ENDIAN_UINT16(_baseObj + 6));
+ return make_reg(0, _baseObj.getUint16SEAt(6));
}
void setClassScriptSelector(reg_t value) {
@@ -192,7 +221,7 @@ public:
error("setClassScriptSelector called for SCI3");
}
- Selector getVarSelector(uint16 i) const { return READ_SCI11ENDIAN_UINT16(_baseVars + i); }
+ Selector getVarSelector(uint16 i) const { return _baseVars.getUint16SEAt(i); }
reg_t getFunction(uint16 i) const {
uint16 offset = (getSciVersion() < SCI_VERSION_1_1) ? _methodCount + 1 + i : i * 2 + 2;
@@ -236,7 +265,7 @@ public:
uint getVarCount() const { return _variables.size(); }
- void init(byte *buf, reg_t obj_pos, bool initVariables = true);
+ void init(const SciSpan<const byte> &buf, reg_t obj_pos, bool initVariables = true);
reg_t getVariable(uint var) const { return _variables[var]; }
reg_t &getVariableRef(uint var) { return _variables[var]; }
@@ -247,9 +276,9 @@ public:
void saveLoadWithSerializer(Common::Serializer &ser);
void cloneFromObject(const Object *obj) {
- _baseObj = obj ? obj->_baseObj : NULL;
+ _baseObj = obj ? obj->_baseObj : SciSpan<const byte>();
_baseMethod = obj ? obj->_baseMethod : Common::Array<uint16>();
- _baseVars = obj ? obj->_baseVars : NULL;
+ _baseVars = obj ? obj->_baseVars : SciSpan<const uint16>();
}
bool relocateSci0Sci21(SegmentId segment, int location, size_t scriptSize);
@@ -260,17 +289,17 @@ public:
void initSpecies(SegManager *segMan, reg_t addr);
void initSuperClass(SegManager *segMan, reg_t addr);
bool initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass = true);
- void syncBaseObject(const byte *ptr) { _baseObj = ptr; }
+ void syncBaseObject(const SciSpan<const byte> &ptr) { _baseObj = ptr; }
bool mustSetViewVisibleSci3(int selector) const { return _mustSetViewVisible[selector/32]; }
private:
- void initSelectorsSci3(const byte *buf);
+ void initSelectorsSci3(const SciSpan<const byte> &buf);
- const byte *_baseObj; /**< base + object offset within base */
- const uint16 *_baseVars; /**< Pointer to the varselector area for this object */
+ SciSpan<const byte> _baseObj; /**< base + object offset within base */
+ SciSpan<const uint16> _baseVars; /**< Pointer to the varselector area for this object */
Common::Array<uint16> _baseMethod; /**< Pointer to the method selector area for this object */
- uint32 *_propertyOffsetsSci3; /**< This is used to enable relocation of property valuesa in SCI3 */
+ uint32 *_propertyOffsetsSci3; /**< This is used to enable relocation of property values in SCI3 */
Common::Array<reg_t> _variables;
uint16 _methodCount;
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index a3a690be59..f05fdc5cb9 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -255,7 +255,7 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) {
ObjMap objects = scr->getObjectMap();
for (ObjMap::iterator it = objects.begin(); it != objects.end(); ++it)
- it->_value.syncBaseObject(scr->getBuf(it->_value.getPos().getOffset()));
+ it->_value.syncBaseObject(SciSpan<const byte>(scr->getBuf(it->_value.getPos().getOffset()), scr->getBufSize() - it->_value.getPos().getOffset()));
}
@@ -437,37 +437,38 @@ void HunkTable::saveLoadWithSerializer(Common::Serializer &s) {
void Script::syncStringHeap(Common::Serializer &s) {
if (getSciVersion() < SCI_VERSION_1_1) {
// Sync all of the SCI_OBJ_STRINGS blocks
- byte *buf = _buf;
+ SciSpan<byte> buf = (SciSpan<byte> &)*_buf;
bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
if (oldScriptHeader)
buf += 2;
- do {
- int blockType = READ_LE_UINT16(buf);
+ for (;;) {
+ int blockType = buf.getUint16LEAt(0);
int blockSize;
if (blockType == 0)
break;
- blockSize = READ_LE_UINT16(buf + 2);
+ blockSize = buf.getUint16LEAt(2);
assert(blockSize > 0);
if (blockType == SCI_OBJ_STRINGS)
- s.syncBytes(buf, blockSize);
+ s.syncBytes(buf.getUnsafeDataAt(0, blockSize), blockSize);
buf += blockSize;
- } while (1);
+ }
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE){
// Strings in SCI1.1 come after the object instances
- byte *buf = _heapStart + 4 + READ_SCI11ENDIAN_UINT16(_heapStart + 2) * 2;
+ SciSpan<byte> buf = _heap.subspan<byte>(4 + _heap.getUint16SEAt(2) * 2);
// Skip all of the objects
- while (READ_SCI11ENDIAN_UINT16(buf) == SCRIPT_OBJECT_MAGIC_NUMBER)
- buf += READ_SCI11ENDIAN_UINT16(buf + 2) * 2;
+ while (buf.getUint16SEAt(0) == SCRIPT_OBJECT_MAGIC_NUMBER)
+ buf += buf.getUint16SEAt(2) * 2;
// Now, sync everything till the end of the buffer
- s.syncBytes(buf, _heapSize - (buf - _heapStart));
+ const int length = _heap.size() - (buf - _heap);
+ s.syncBytes(buf.getUnsafeDataAt(0, length), length);
} else if (getSciVersion() == SCI_VERSION_3) {
warning("TODO: syncStringHeap(): Implement SCI3 variant");
}
@@ -1062,7 +1063,7 @@ bool gamestate_save(EngineState *s, Common::WriteStream *fh, const Common::Strin
meta.saveTime = ((curTime.tm_hour & 0xFF) << 16) | (((curTime.tm_min) & 0xFF) << 8) | ((curTime.tm_sec) & 0xFF);
Resource *script0 = g_sci->getResMan()->findResource(ResourceId(kResourceTypeScript, 0), false);
- meta.script0Size = script0->size;
+ meta.script0Size = script0->size();
meta.gameObjectOffset = g_sci->getGameObject().getOffset();
// Checking here again
@@ -1199,7 +1200,7 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
if (meta.gameObjectOffset > 0 && meta.script0Size > 0) {
Resource *script0 = g_sci->getResMan()->findResource(ResourceId(kResourceTypeScript, 0), false);
- if (script0->size != meta.script0Size || g_sci->getGameObject().getOffset() != meta.gameObjectOffset) {
+ if (script0->size() != meta.script0Size || g_sci->getGameObject().getOffset() != meta.gameObjectOffset) {
showScummVMDialog("This saved game was created with a different version of the game, unable to load it");
s->r_acc = TRUE_REG; // signal failure
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp
index 8a973bd217..f790b411cf 100644
--- a/engines/sci/engine/script.cpp
+++ b/engines/sci/engine/script.cpp
@@ -33,8 +33,13 @@
namespace Sci {
+const char *sciObjectTypeNames[] = {
+ "terminator", "object", "code", "synonyms", "said", "strings", "class",
+ "exports", "pointers", "preload text", "local vars"
+};
+
Script::Script()
- : SegmentObj(SEG_TYPE_SCRIPT), _buf(NULL) {
+ : SegmentObj(SEG_TYPE_SCRIPT), _buf() {
freeScript();
}
@@ -45,16 +50,12 @@ Script::~Script() {
void Script::freeScript() {
_nr = 0;
- free(_buf);
- _buf = NULL;
- _bufSize = 0;
- _scriptSize = 0;
- _heapStart = NULL;
- _heapSize = 0;
-
- _exportTable = NULL;
+ _buf.clear();
+ _script.clear();
+ _heap.clear();
+ _exports.clear();
_numExports = 0;
- _synonyms = NULL;
+ _synonyms.clear();
_numSynonyms = 0;
_localsOffset = 0;
@@ -80,15 +81,16 @@ enum {
void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptPatcher) {
freeScript();
- Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
+ Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), false);
if (!script)
error("Script %d not found", script_nr);
_nr = script_nr;
- _bufSize = _scriptSize = script->size;
+ uint32 scriptSize = script->size();
+ uint32 bufSize = scriptSize;
if (getSciVersion() == SCI_VERSION_0_EARLY) {
- _bufSize += READ_LE_UINT16(script->data) * 2;
+ bufSize += script->getUint16LEAt(0) * 2;
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
// In SCI1.1 - SCI2.1, the heap was in a separate space from the script. We append
// it to the end of the script, and adjust addressing accordingly.
@@ -97,18 +99,17 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP
// worked for SCI11, SCI2 and SCI21 games. SCI3 games use a different
// script format, and theoretically they can exceed the 64KB boundary
// using relocation.
- Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
- _bufSize += heap->size;
- _heapSize = heap->size;
+ Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, script_nr), false);
+ bufSize += heap->size();
// Ensure that the start of the heap resource can be word-aligned.
- if (script->size & 2) {
- _bufSize++;
- _scriptSize++;
+ if (script->size() & 2) {
+ ++bufSize;
+ ++scriptSize;
}
// As mentioned above, the script and the heap together should not exceed 64KB
- if (script->size + heap->size > 65535)
+ if (script->size() + heap->size() > 65535)
error("Script and heap sizes combined exceed 64K. This means a fundamental "
"design bug was made regarding SCI1.1 and newer games.\n"
"Please report this error to the ScummVM team");
@@ -125,13 +126,13 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP
// RAMA: 70
//
// TODO: Remove this once such a mechanism is in place
- if (script->size > 65535)
- warning("TODO: SCI script %d is over 64KB - it's %d bytes long. This can't "
- "be fully handled at the moment", script_nr, script->size);
+ if (script->size() > 65535)
+ warning("TODO: SCI script %d is over 64KB - it's %lu bytes long. This can't "
+ "be fully handled at the moment", script_nr, script->size());
}
uint extraLocalsWorkaround = 0;
- if (g_sci->getGameId() == GID_FANMADE && _nr == 1 && script->size == 11140) {
+ if (g_sci->getGameId() == GID_FANMADE && _nr == 1 && script->size() == 11140) {
// WORKAROUND: Script 1 in Ocean Battle doesn't have enough locals to
// fit the string showing how many shots are left (a nasty script bug,
// corrupting heap memory). We add 10 more locals so that it has enough
@@ -139,60 +140,71 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP
// #3059871.
extraLocalsWorkaround = 10;
}
- _bufSize += extraLocalsWorkaround * 2;
+ bufSize += extraLocalsWorkaround * 2;
- _buf = (byte *)malloc(_bufSize);
- assert(_buf);
-
- assert(_bufSize >= script->size);
- memcpy(_buf, script->data, script->size);
+ SciSpan<byte> outBuffer = _buf->allocate(bufSize, script->name() + " buffer");
+ script->copyDataTo(outBuffer);
+ // The word-aligned script size is used here because other parts of the code
+ // currently rely on finding the start of the heap by reading the script
+ // size
+ _script = _buf->subspan(0, scriptSize, script->name());
if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
- Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, _nr), 0);
- assert(heap != 0);
-
- _heapStart = _buf + _scriptSize;
+ Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, _nr), false);
+ assert(heap);
- assert(_bufSize - _scriptSize >= heap->size);
- memcpy(_heapStart, heap->data, heap->size);
+ SciSpan<byte> outHeap = outBuffer.subspan(scriptSize, heap->size(), heap->name(), 0);
+ heap->copyDataTo(outHeap);
+ _heap = outHeap;
}
// Check scripts (+ possibly SCI 1.1 heap) for matching signatures and patch those, if found
- scriptPatcher->processScript(_nr, _buf, _bufSize);
+ scriptPatcher->processScript(_nr, outBuffer);
if (getSciVersion() <= SCI_VERSION_1_LATE) {
- _exportTable = (const uint16 *)findBlockSCI0(SCI_OBJ_EXPORTS);
- if (_exportTable) {
- _numExports = READ_SCI11ENDIAN_UINT16(_exportTable + 1);
- _exportTable += 3; // skip header plus 2 bytes (_exportTable is a uint16 pointer)
+ SciSpan<const uint16> exportTable = findBlockSCI0(SCI_OBJ_EXPORTS).subspan<const uint16>(0);
+ if (exportTable) {
+ // The export table is after the block header (4 bytes / 2 uint16s)
+ // and the number of exports (2 bytes / 1 uint16).
+ // The exports span does not need to be explicitly sized since the
+ // maximum size was already determined by findBlockSCI0
+ _exports = exportTable.subspan(3);
+ _numExports = exportTable.getUint16SEAt(2);
}
- _synonyms = findBlockSCI0(SCI_OBJ_SYNONYMS);
- if (_synonyms) {
- _numSynonyms = READ_SCI11ENDIAN_UINT16(_synonyms + 2) / 4;
- _synonyms += 4; // skip header
+
+ SciSpan<const byte> synonymTable = findBlockSCI0(SCI_OBJ_SYNONYMS);
+ if (synonymTable) {
+ // the synonyms table is after the block header (4 bytes),
+ // and each synonym entry is 4 bytes
+ _synonyms = synonymTable.subspan(4);
+ _numSynonyms = _synonyms.size() / 4;
}
- const byte* localsBlock = findBlockSCI0(SCI_OBJ_LOCALVARS);
- if (localsBlock) {
- _localsOffset = localsBlock - _buf + 4;
- _localsCount = (READ_LE_UINT16(_buf + _localsOffset - 2) - 4) >> 1; // half block size
+
+ SciSpan<const byte> localsTable = findBlockSCI0(SCI_OBJ_LOCALVARS);
+ if (localsTable) {
+ // skip header (4 bytes)
+ _localsOffset = localsTable - *_buf + 4;
+ _localsCount = (_buf->getUint16LEAt(_localsOffset - 2) - 4) >> 1; // half block size
}
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
- _numExports = READ_SCI11ENDIAN_UINT16(_buf + kSci11NumExportsOffset);
+ _numExports = _buf->getUint16SEAt(kSci11NumExportsOffset);
if (_numExports) {
- _exportTable = (const uint16 *)(_buf + kSci11ExportTableOffset);
+ _exports = _buf->subspan<const uint16>(kSci11ExportTableOffset, _numExports * sizeof(uint16));
}
- _localsOffset = _scriptSize + 4;
- _localsCount = READ_SCI11ENDIAN_UINT16(_buf + _localsOffset - 2);
+ _localsOffset = _script.size() + 4;
+ _localsCount = _buf->getUint16SEAt(_localsOffset - 2);
} else if (getSciVersion() == SCI_VERSION_3) {
- _localsCount = READ_LE_UINT16(_buf + 12);
- _exportTable = (const uint16 *)(_buf + 22);
- _numExports = READ_LE_UINT16(_buf + 20);
- // SCI3 local variables always start dword-aligned
- if (_numExports % 2)
- _localsOffset = 22 + _numExports * 2;
- else
- _localsOffset = 24 + _numExports * 2;
+ _localsCount = _buf->getUint16LEAt(12);
+ _numExports = _buf->getUint16LEAt(20);
+ if (_numExports) {
+ _exports = _buf->subspan<const uint16>(22, _numExports * sizeof(uint16));
+ // SCI3 local variables always start dword-aligned
+ if (_numExports % 2)
+ _localsOffset = 22 + _numExports * 2;
+ else
+ _localsOffset = 24 + _numExports * 2;
+ }
}
// WORKAROUND: Increase locals, if needed (check above)
@@ -203,7 +215,7 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP
// Old script block. There won't be a localvar block in this case.
// Instead, the script starts with a 16 bit int specifying the
// number of locals we need; these are then allocated and zeroed.
- _localsCount = READ_LE_UINT16(_buf);
+ _localsCount = _buf->getUint16LEAt(0);
_localsOffset = -_localsCount * 2; // Make sure it's invalid
} else {
// SCI0 late and newer
@@ -211,8 +223,8 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP
if (!_localsCount)
_localsOffset = 0;
- if (_localsOffset + _localsCount * 2 + 1 >= (int)_bufSize) {
- error("Locals extend beyond end of script: offset %04x, count %d vs size %d", _localsOffset, _localsCount, (int)_bufSize);
+ if (_localsOffset + _localsCount * 2 + 1 >= (int)_buf->size()) {
+ error("Locals extend beyond end of script: offset %04x, count %d vs size %d", _localsOffset, _localsCount, (int)_buf->size());
//_localsCount = (_bufSize - _localsOffset) >> 1;
}
}
@@ -223,11 +235,9 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP
void Script::identifyOffsets() {
offsetLookupArrayEntry arrayEntry;
- const byte *scriptDataPtr = NULL;
- const byte *stringStartPtr = NULL;
- const byte *stringDataPtr = NULL;
- uint32 scriptDataLeft = 0;
- uint32 stringDataLeft = 0;
+ SciSpan<const byte> scriptDataPtr;
+ SciSpan<const byte> stringStartPtr;
+ SciSpan<const byte> stringDataPtr;
byte stringDataByte = 0;
uint16 typeObject_id = 0;
uint16 typeString_id = 0;
@@ -244,38 +254,34 @@ void Script::identifyOffsets() {
if (getSciVersion() < SCI_VERSION_1_1) {
// SCI0 + SCI1
- scriptDataPtr = _buf;
- scriptDataLeft = _bufSize;
+ scriptDataPtr = *_buf;
// Go through all blocks
if (getSciVersion() == SCI_VERSION_0_EARLY) {
- if (scriptDataLeft < 2)
+ if (scriptDataPtr.size() < 2)
error("Script::identifyOffsets(): unexpected end of script %d", _nr);
- scriptDataPtr += 2;
- scriptDataLeft -= 2;
+ scriptDataPtr += 2;
}
- do {
- if (scriptDataLeft < 2)
+ for (;;) {
+ if (scriptDataPtr.size() < 2)
error("Script::identifyOffsets(): unexpected end of script %d", _nr);
- blockType = READ_LE_UINT16(scriptDataPtr);
- scriptDataPtr += 2;
- scriptDataLeft -= 2;
+ blockType = scriptDataPtr.getUint16LEAt(0);
+ scriptDataPtr += 2;
if (blockType == 0) // end of blocks detected
break;
- if (scriptDataLeft < 2)
+ if (scriptDataPtr.size() < 2)
error("Script::identifyOffsets(): unexpected end of script %d", _nr);
- blockSize = READ_LE_UINT16(scriptDataPtr);
+ blockSize = scriptDataPtr.getUint16LEAt(0);
if (blockSize < 4)
error("Script::identifyOffsets(): invalid block size in script %d", _nr);
- blockSize -= 4; // block size includes block-type UINT16 and block-size UINT16
- scriptDataPtr += 2;
- scriptDataLeft -= 2;
+ blockSize -= 4; // block size includes block-type UINT16 and block-size UINT16
+ scriptDataPtr += 2;
- if (scriptDataLeft < blockSize)
+ if (scriptDataPtr.size() < blockSize)
error("Script::identifyOffsets(): invalid block size in script %d", _nr);
switch (blockType) {
@@ -284,7 +290,7 @@ void Script::identifyOffsets() {
typeObject_id++;
arrayEntry.type = SCI_SCR_OFFSET_TYPE_OBJECT;
arrayEntry.id = typeObject_id;
- arrayEntry.offset = scriptDataPtr - _buf + 8; // Calculate offset inside script data (VM uses +8)
+ arrayEntry.offset = scriptDataPtr - *_buf + 8; // Calculate offset inside script data (VM uses +8)
arrayEntry.stringSize = 0;
_offsetLookupArray.push_back(arrayEntry);
_offsetLookupObjectCount++;
@@ -292,18 +298,17 @@ void Script::identifyOffsets() {
case SCI_OBJ_STRINGS:
// string block detected, we now grab all NUL terminated strings out of this block
- stringDataPtr = scriptDataPtr;
- stringDataLeft = blockSize;
+ stringDataPtr = scriptDataPtr.subspan(0, blockSize);
arrayEntry.type = SCI_SCR_OFFSET_TYPE_STRING;
- do {
- if (stringDataLeft < 1) // no more bytes left
+ for (;;) {
+ if (stringDataPtr.size() < 1) // no more bytes left
break;
stringStartPtr = stringDataPtr;
- if (stringDataLeft == 1) {
+ if (stringDataPtr.size() == 1) {
// only 1 byte left and that byte is a [00], in that case we also exit
stringDataByte = *stringStartPtr;
if (stringDataByte == 0x00)
@@ -311,46 +316,44 @@ void Script::identifyOffsets() {
}
// now look for terminating [NUL]
- do {
+ for (;;) {
stringDataByte = *stringDataPtr;
stringDataPtr++;
- stringDataLeft--;
if (!stringDataByte) // NUL found, exit this loop
break;
- if (stringDataLeft < 1) {
+ if (stringDataPtr.size() < 1) {
// no more bytes left
warning("Script::identifyOffsets(): string without terminating NUL in script %d", _nr);
break;
}
- } while (1);
+ }
if (stringDataByte)
break;
typeString_id++;
arrayEntry.id = typeString_id;
- arrayEntry.offset = stringStartPtr - _buf; // Calculate offset inside script data
+ arrayEntry.offset = stringStartPtr - *_buf; // Calculate offset inside script data
arrayEntry.stringSize = stringDataPtr - stringStartPtr;
_offsetLookupArray.push_back(arrayEntry);
_offsetLookupStringCount++;
- } while (1);
+ }
break;
case SCI_OBJ_SAID:
// said block detected, we now try to find every single said "string" inside this block
// said strings are terminated with a 0xFF, the string itself may contain words (2 bytes), where
// the second byte of a word may also be a 0xFF.
- stringDataPtr = scriptDataPtr;
- stringDataLeft = blockSize;
+ stringDataPtr = scriptDataPtr.subspan(0, blockSize);
arrayEntry.type = SCI_SCR_OFFSET_TYPE_SAID;
- do {
- if (stringDataLeft < 1) // no more bytes left
+ for (;;) {
+ if (stringDataPtr.size() < 1) // no more bytes left
break;
stringStartPtr = stringDataPtr;
- if (stringDataLeft == 1) {
+ if (stringDataPtr.size() == 1) {
// only 1 byte left and that byte is a [00], in that case we also exit
// happens in some scripts, for example Conquests of Camelot, script 997
// may have been a bug in the compiler or just an intentional filler byte
@@ -360,30 +363,28 @@ void Script::identifyOffsets() {
}
// now look for terminating 0xFF
- do {
+ for (;;) {
stringDataByte = *stringDataPtr;
stringDataPtr++;
- stringDataLeft--;
if (stringDataByte == 0xFF) // Terminator found, exit this loop
break;
- if (stringDataLeft < 1) // no more bytes left
+ if (stringDataPtr.size() < 1) // no more bytes left
error("Script::identifyOffsets(): said-string without terminator in script %d", _nr);
if (stringDataByte < 0xF0) {
// Part of a word, skip second byte
stringDataPtr++;
- stringDataLeft--;
- if (stringDataLeft < 1) // no more bytes left
+ if (stringDataPtr.size() < 1) // no more bytes left
error("Script::identifyOffsets(): said-string without terminator in script %d", _nr);
}
- } while (1);
+ }
typeSaid_id++;
arrayEntry.id = typeSaid_id;
- arrayEntry.offset = stringStartPtr - _buf; // Calculate offset inside script data
+ arrayEntry.offset = stringStartPtr - *_buf; // Calculate offset inside script data
arrayEntry.stringSize = 0;
_offsetLookupArray.push_back(arrayEntry);
_offsetLookupSaidCount++;
- } while (1);
+ }
break;
default:
@@ -391,48 +392,44 @@ void Script::identifyOffsets() {
}
scriptDataPtr += blockSize;
- scriptDataLeft -= blockSize;
- } while (1);
+ }
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
// Strings in SCI1.1 up to SCI2 come after the object instances
- scriptDataPtr = _heapStart;
- scriptDataLeft = _heapSize;
+ scriptDataPtr = _heap;
enum {
- kExportSize = 2,
- kPropertySize = 2,
- kNumMethodsSize = 2,
+ kExportSize = sizeof(uint16),
+ kPropertySize = sizeof(uint16),
+ kNumMethodsSize = sizeof(uint16),
kPropDictEntrySize = 2,
kMethDictEntrySize = 4
};
- const byte *hunkPtr = _buf + kSci11ExportTableOffset + _numExports * kExportSize;
+ SciSpan<const byte> hunkPtr = _buf->subspan(kSci11ExportTableOffset + _numExports * kExportSize);
- if (scriptDataLeft < 4)
+ if (scriptDataPtr.size() < 4)
error("Script::identifyOffsets(): unexpected end of script in script %d", _nr);
- uint16 endOfStringOffset = READ_SCI11ENDIAN_UINT16(scriptDataPtr);
- uint16 objectStartOffset = READ_SCI11ENDIAN_UINT16(scriptDataPtr + 2) * 2 + 4;
+ uint16 endOfStringOffset = scriptDataPtr.getUint16SEAt(0);
+ uint16 objectStartOffset = scriptDataPtr.getUint16SEAt(2) * 2 + 4;
- if (scriptDataLeft < objectStartOffset)
+ if (scriptDataPtr.size() < objectStartOffset)
error("Script::identifyOffsets(): object start is beyond heap size in script %d", _nr);
- if (scriptDataLeft < endOfStringOffset)
+ if (scriptDataPtr.size() < endOfStringOffset)
error("Script::identifyOffsets(): end of string is beyond heap size in script %d", _nr);
- const byte *endOfStringPtr = scriptDataPtr + endOfStringOffset;
+ SciSpan<const byte> endOfStringPtr = scriptDataPtr.subspan(endOfStringOffset);
scriptDataPtr += objectStartOffset;
- scriptDataLeft -= objectStartOffset;
// go through all objects
- do {
- if (scriptDataLeft < 2)
+ for (;;) {
+ if (scriptDataPtr.size() < 2)
error("Script::identifyOffsets(): unexpected end of script %d", _nr);
- blockType = READ_SCI11ENDIAN_UINT16(scriptDataPtr);
+ blockType = scriptDataPtr.getUint16SEAt(0);
scriptDataPtr += 2;
- scriptDataLeft -= 2;
if (blockType != SCRIPT_OBJECT_MAGIC_NUMBER)
break;
@@ -440,77 +437,73 @@ void Script::identifyOffsets() {
typeObject_id++;
arrayEntry.type = SCI_SCR_OFFSET_TYPE_OBJECT;
arrayEntry.id = typeObject_id;
- arrayEntry.offset = scriptDataPtr - _buf - 2; // the VM uses a pointer to the Magic-Number
+ arrayEntry.offset = scriptDataPtr - *_buf - 2; // the VM uses a pointer to the Magic-Number
arrayEntry.stringSize = 0;
_offsetLookupArray.push_back(arrayEntry);
_offsetLookupObjectCount++;
- if (scriptDataLeft < 2)
+ if (scriptDataPtr.size() < 2)
error("Script::identifyOffsets(): unexpected end of script in script %d", _nr);
- const uint16 numProperties = READ_SCI11ENDIAN_UINT16(scriptDataPtr);
+ const uint16 numProperties = scriptDataPtr.getUint16SEAt(0);
blockSize = numProperties * kPropertySize;
if (blockSize < 4)
error("Script::identifyOffsets(): invalid block size in script %d", _nr);
scriptDataPtr += 2;
- scriptDataLeft -= 2;
- const uint16 scriptNum = READ_SCI11ENDIAN_UINT16(scriptDataPtr + 6);
+ const uint16 scriptNum = scriptDataPtr.getUint16SEAt(6);
if (scriptNum != 0xFFFF) {
hunkPtr += numProperties * kPropDictEntrySize;
}
- const uint16 numMethods = READ_SCI11ENDIAN_UINT16(hunkPtr);
+ const uint16 numMethods = hunkPtr.getUint16SEAt(0);
hunkPtr += kNumMethodsSize + numMethods * kMethDictEntrySize;
blockSize -= 4; // blocksize contains UINT16 type and UINT16 size
- if (scriptDataLeft < blockSize)
+ if (scriptDataPtr.size() < blockSize)
error("Script::identifyOffsets(): invalid block size in script %d", _nr);
scriptDataPtr += blockSize;
- scriptDataLeft -= blockSize;
- } while (1);
+ }
- _codeOffset = hunkPtr - _buf;
+ _codeOffset = hunkPtr - *_buf;
// now scriptDataPtr points to right at the start of the strings
if (scriptDataPtr > endOfStringPtr)
error("Script::identifyOffsets(): string block / end-of-string block mismatch in script %d", _nr);
- stringDataPtr = scriptDataPtr;
- stringDataLeft = endOfStringPtr - scriptDataPtr; // Calculate byte count within string-block
+ stringDataPtr = scriptDataPtr.subspan(0, endOfStringPtr - scriptDataPtr);
arrayEntry.type = SCI_SCR_OFFSET_TYPE_STRING;
- do {
- if (stringDataLeft < 1) // no more bytes left
+ for (;;) {
+ if (stringDataPtr.size() < 1) // no more bytes left
break;
stringStartPtr = stringDataPtr;
// now look for terminating [NUL]
- do {
+ for (;;) {
stringDataByte = *stringDataPtr;
stringDataPtr++;
- stringDataLeft--;
if (!stringDataByte) // NUL found, exit this loop
break;
- if (stringDataLeft < 1) {
+ if (stringDataPtr.size() < 1) {
// no more bytes left
warning("Script::identifyOffsets(): string without terminating NUL in script %d", _nr);
break;
}
- } while (1);
+ }
if (stringDataByte)
break;
typeString_id++;
arrayEntry.id = typeString_id;
- arrayEntry.offset = stringStartPtr - _buf; // Calculate offset inside script data
+ arrayEntry.offset = stringStartPtr - *_buf; // Calculate offset inside script data
arrayEntry.stringSize = stringDataPtr - stringStartPtr;
_offsetLookupArray.push_back(arrayEntry);
_offsetLookupStringCount++;
- } while (1);
+ }
} else if (getSciVersion() == SCI_VERSION_3) {
// SCI3
@@ -518,25 +511,23 @@ void Script::identifyOffsets() {
uint32 sci3RelocationOffset = 0;
uint32 sci3BoundaryOffset = 0;
- if (_bufSize < 22)
+ if (_buf->size() < 22)
error("Script::identifyOffsets(): script %d smaller than expected SCI3-header", _nr);
- sci3StringOffset = READ_LE_UINT32(_buf + 4);
- sci3RelocationOffset = READ_LE_UINT32(_buf + 8);
+ sci3StringOffset = _buf->getUint32LEAt(4);
+ sci3RelocationOffset = _buf->getUint32LEAt(8);
- if (sci3RelocationOffset > _bufSize)
+ if (sci3RelocationOffset > _buf->size())
error("Script::identifyOffsets(): relocation offset is beyond end of script %d", _nr);
// First we get all the objects
scriptDataPtr = getSci3ObjectsPointer();
- scriptDataLeft = _bufSize - (scriptDataPtr - _buf);
- do {
- if (scriptDataLeft < 2)
+ for (;;) {
+ if (scriptDataPtr.size() < 2)
error("Script::identifyOffsets(): unexpected end of script %d", _nr);
- blockType = READ_SCI11ENDIAN_UINT16(scriptDataPtr);
- scriptDataPtr += 2;
- scriptDataLeft -= 2;
+ blockType = scriptDataPtr.getUint16SEAt(0);
+ scriptDataPtr += 2;
if (blockType != SCRIPT_OBJECT_MAGIC_NUMBER)
break;
@@ -544,48 +535,45 @@ void Script::identifyOffsets() {
typeObject_id++;
arrayEntry.type = SCI_SCR_OFFSET_TYPE_OBJECT;
arrayEntry.id = typeObject_id;
- arrayEntry.offset = scriptDataPtr - _buf - 2; // the VM uses a pointer to the Magic-Number
+ arrayEntry.offset = scriptDataPtr - *_buf - 2; // the VM uses a pointer to the Magic-Number
arrayEntry.stringSize = 0;
_offsetLookupArray.push_back(arrayEntry);
_offsetLookupObjectCount++;
- if (scriptDataLeft < 2)
+ if (scriptDataPtr.size() < 2)
error("Script::identifyOffsets(): unexpected end of script in script %d", _nr);
- blockSize = READ_SCI11ENDIAN_UINT16(scriptDataPtr);
+ blockSize = scriptDataPtr.getUint16SEAt(0);
if (blockSize < 4)
error("Script::identifyOffsets(): invalid block size in script %d", _nr);
scriptDataPtr += 2;
- scriptDataLeft -= 2;
blockSize -= 4; // blocksize contains UINT16 type and UINT16 size
- if (scriptDataLeft < blockSize)
+ if (scriptDataPtr.size() < blockSize)
error("Script::identifyOffsets(): invalid block size in script %d", _nr);
scriptDataPtr += blockSize;
- scriptDataLeft -= blockSize;
- } while (1);
+ }
// And now we get all the strings
if (sci3StringOffset > 0) {
// string offset set, we expect strings
- if (sci3StringOffset > _bufSize)
+ if (sci3StringOffset > _buf->size())
error("Script::identifyOffsets(): string offset is beyond end of script %d", _nr);
if (sci3RelocationOffset < sci3StringOffset)
error("Script::identifyOffsets(): string offset points beyond relocation offset in script %d", _nr);
- stringDataPtr = _buf + sci3StringOffset;
- stringDataLeft = sci3RelocationOffset - sci3StringOffset;
+ stringDataPtr = _buf->subspan(sci3StringOffset, sci3RelocationOffset - sci3StringOffset);
arrayEntry.type = SCI_SCR_OFFSET_TYPE_STRING;
- do {
- if (stringDataLeft < 1) // no more bytes left
+ for (;;) {
+ if (stringDataPtr.size() < 1) // no more bytes left
break;
stringStartPtr = stringDataPtr;
- if (stringDataLeft == 1) {
+ if (stringDataPtr.size() == 1) {
// only 1 byte left and that byte is a [00], in that case we also exit
stringDataByte = *stringStartPtr;
if (stringDataByte == 0x00)
@@ -593,60 +581,57 @@ void Script::identifyOffsets() {
}
// now look for terminating [NUL]
- do {
+ for (;;) {
stringDataByte = *stringDataPtr;
stringDataPtr++;
- stringDataLeft--;
if (!stringDataByte) // NUL found, exit this loop
break;
- if (stringDataLeft < 1) {
+ if (stringDataPtr.size() < 1) {
// no more bytes left
warning("Script::identifyOffsets(): string without terminating NUL in script %d", _nr);
break;
}
- } while (1);
+ }
if (stringDataByte)
break;
typeString_id++;
arrayEntry.id = typeString_id;
- arrayEntry.offset = stringStartPtr - _buf; // Calculate offset inside script data
+ arrayEntry.offset = stringStartPtr - *_buf; // Calculate offset inside script data
arrayEntry.stringSize = stringDataPtr - stringStartPtr;
_offsetLookupArray.push_back(arrayEntry);
_offsetLookupStringCount++;
// SCI3 seems to have aligned all string on DWORD boundaries
- sci3BoundaryOffset = stringDataPtr - _buf; // Calculate current offset inside script data
+ sci3BoundaryOffset = stringDataPtr - *_buf; // Calculate current offset inside script data
sci3BoundaryOffset = sci3BoundaryOffset & 3; // Check boundary offset
if (sci3BoundaryOffset) {
// lower 2 bits are set? Then we have to adjust the offset
sci3BoundaryOffset = 4 - sci3BoundaryOffset;
- if (stringDataLeft < sci3BoundaryOffset)
+ if (stringDataPtr.size() < sci3BoundaryOffset)
error("Script::identifyOffsets(): SCI3 string boundary adjustment goes beyond end of string block in script %d", _nr);
- stringDataLeft -= sci3BoundaryOffset;
stringDataPtr += sci3BoundaryOffset;
}
- } while (1);
+ }
}
- return;
}
}
-const byte *Script::getSci3ObjectsPointer() {
- const byte *ptr = 0;
+SciSpan<const byte> Script::getSci3ObjectsPointer() {
+ SciSpan<const byte> ptr;
// SCI3 local variables always start dword-aligned
if (_numExports % 2)
- ptr = _buf + 22 + _numExports * 2;
+ ptr = _buf->subspan(22 + _numExports * sizeof(uint16));
else
- ptr = _buf + 24 + _numExports * 2;
+ ptr = _buf->subspan(24 + _numExports * sizeof(uint16));
// SCI3 object structures always start dword-aligned
if (_localsCount % 2)
- ptr += 2 + _localsCount * 2;
+ ptr += 2 + _localsCount * sizeof(uint16);
else
- ptr += _localsCount * 2;
+ ptr += _localsCount * sizeof(uint16);
return ptr;
}
@@ -669,13 +654,13 @@ Object *Script::scriptObjInit(reg_t obj_pos, bool fullObjectInit) {
if (getSciVersion() < SCI_VERSION_1_1 && fullObjectInit)
obj_pos.incOffset(8); // magic offset (SCRIPT_OBJECT_MAGIC_OFFSET)
- if (obj_pos.getOffset() >= _bufSize)
+ if (obj_pos.getOffset() >= _buf->size())
error("Attempt to initialize object beyond end of script");
// Get the object at the specified position and init it. This will
// automatically "allocate" space for it in the _objects map if necessary.
Object *obj = &_objects[obj_pos.getOffset()];
- obj->init(_buf, obj_pos, fullObjectInit);
+ obj->init(*_buf, obj_pos, fullObjectInit);
return obj;
}
@@ -705,14 +690,14 @@ static bool relocateBlock(Common::Array<reg_t> &block, int block_location, Segme
}
int Script::relocateOffsetSci3(uint32 offset) const {
- int relocStart = READ_LE_UINT32(_buf + 8);
- int relocCount = READ_LE_UINT16(_buf + 18);
- const byte *seeker = _buf + relocStart;
+ int relocStart = _buf->getUint32LEAt(8);
+ int relocCount = _buf->getUint16LEAt(18);
+ SciSpan <const byte> seeker = _buf->subspan(relocStart);
for (int i = 0; i < relocCount; ++i) {
- if (READ_SCI11ENDIAN_UINT32(seeker) == offset) {
+ if (seeker.getUint32SEAt(0) == offset) {
// TODO: Find out what UINT16 at (seeker + 8) means
- return READ_SCI11ENDIAN_UINT16(_buf + offset) + READ_SCI11ENDIAN_UINT32(seeker + 4);
+ return _buf->getUint16SEAt(offset) + seeker.getUint32SEAt(4);
}
seeker += 10;
}
@@ -722,39 +707,37 @@ int Script::relocateOffsetSci3(uint32 offset) const {
bool Script::relocateLocal(SegmentId segment, int location) {
if (_localsBlock)
- return relocateBlock(_localsBlock->_locals, _localsOffset, segment, location, _scriptSize);
+ return relocateBlock(_localsBlock->_locals, _localsOffset, segment, location, _script.size());
else
return false;
}
void Script::relocateSci0Sci21(reg_t block) {
- const byte *heap = _buf;
- uint16 heapSize = (uint16)_bufSize;
+ SciSpan<const byte> heap = *_buf;
uint16 heapOffset = 0;
if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
- heap = _heapStart;
- heapSize = (uint16)_heapSize;
- heapOffset = _scriptSize;
+ heap = _heap;
+ heapOffset = _script.size();
}
- if (block.getOffset() >= (uint16)heapSize ||
- READ_SCI11ENDIAN_UINT16(heap + block.getOffset()) * 2 + block.getOffset() >= (uint16)heapSize)
+ if (block.getOffset() >= (uint16)heap.size() ||
+ heap.getUint16SEAt(block.getOffset()) * 2 + block.getOffset() >= (uint16)heap.size())
error("Relocation block outside of script");
- int count = READ_SCI11ENDIAN_UINT16(heap + block.getOffset());
+ int count = heap.getUint16SEAt(block.getOffset());
int exportIndex = 0;
int pos = 0;
for (int i = 0; i < count; i++) {
- pos = READ_SCI11ENDIAN_UINT16(heap + block.getOffset() + 2 + (exportIndex * 2)) + heapOffset;
+ pos = heap.getUint16SEAt(block.getOffset() + 2 + (exportIndex * 2)) + heapOffset;
// This occurs in SCI01/SCI1 games where usually one export value is
// zero. It seems that in this situation, we should skip the export and
// move to the next one, though the total count of valid exports remains
// the same
if (!pos) {
exportIndex++;
- pos = READ_SCI11ENDIAN_UINT16(heap + block.getOffset() + 2 + (exportIndex * 2)) + heapOffset;
+ pos = heap.getUint16SEAt(block.getOffset() + 2 + (exportIndex * 2)) + heapOffset;
if (!pos)
error("Script::relocate(): Consecutive zero exports found");
}
@@ -768,7 +751,7 @@ void Script::relocateSci0Sci21(reg_t block) {
// object, relocate it.
const ObjMap::iterator end = _objects.end();
for (ObjMap::iterator it = _objects.begin(); it != end; ++it)
- if (it->_value.relocateSci0Sci21(block.getSegment(), pos, _scriptSize))
+ if (it->_value.relocateSci0Sci21(block.getSegment(), pos, _script.size()))
break;
}
@@ -777,18 +760,18 @@ void Script::relocateSci0Sci21(reg_t block) {
}
void Script::relocateSci3(reg_t block) {
- const byte *relocStart = _buf + READ_SCI11ENDIAN_UINT32(_buf + 8);
+ SciSpan<const byte> relocStart = _buf->subspan(_buf->getUint32SEAt(8));
//int count = _bufSize - READ_SCI11ENDIAN_UINT32(_buf + 8);
ObjMap::iterator it;
for (it = _objects.begin(); it != _objects.end(); ++it) {
- const byte *seeker = relocStart;
- while (seeker < _buf + _bufSize) {
+ SciSpan<const byte> seeker = relocStart;
+ while (seeker.size()) {
// TODO: Find out what UINT16 at (seeker + 8) means
it->_value.relocateSci3(block.getSegment(),
- READ_SCI11ENDIAN_UINT32(seeker),
- READ_SCI11ENDIAN_UINT32(seeker + 4),
- _scriptSize);
+ seeker.getUint32SEAt(0),
+ seeker.getUint32SEAt(4),
+ _script.size());
seeker += 10;
}
}
@@ -816,7 +799,7 @@ void Script::setLockers(int lockers) {
uint32 Script::validateExportFunc(int pubfunct, bool relocSci3) {
bool exportsAreWide = (g_sci->_features->detectLofsType() == SCI_VERSION_1_MIDDLE);
- if (_numExports <= pubfunct) {
+ if (_numExports <= (uint)pubfunct) {
error("validateExportFunc(): pubfunct is invalid");
return 0;
}
@@ -827,10 +810,10 @@ uint32 Script::validateExportFunc(int pubfunct, bool relocSci3) {
uint32 offset;
if (getSciVersion() != SCI_VERSION_3) {
- offset = READ_SCI11ENDIAN_UINT16(_exportTable + pubfunct);
+ offset = _exports.getUint16SEAt(pubfunct);
} else {
if (!relocSci3)
- offset = READ_SCI11ENDIAN_UINT16(_exportTable + pubfunct) + getCodeBlockOffsetSci3();
+ offset = _exports.getUint16SEAt(pubfunct) + getCodeBlockOffsetSci3();
else
offset = relocateOffsetSci3(pubfunct * 2 + 22);
}
@@ -842,11 +825,11 @@ uint32 Script::validateExportFunc(int pubfunct, bool relocSci3) {
// is located at a specific address, thus findBlockSCI0() won't work.
// Fixes bugs #3039785 and #3037595.
if (offset < 10 && getSciVersion() <= SCI_VERSION_1_LATE) {
- const uint16 *secondExportTable = (const uint16 *)findBlockSCI0(SCI_OBJ_EXPORTS, 0);
+ const SciSpan<const uint16> secondExportTable = findBlockSCI0(SCI_OBJ_EXPORTS, 0).subspan<const uint16>(0);
if (secondExportTable) {
- secondExportTable += 3; // skip header plus 2 bytes (secondExportTable is a uint16 pointer)
- offset = READ_SCI11ENDIAN_UINT16(secondExportTable + pubfunct);
+ // 3 skips header plus 2 bytes (secondExportTable is a uint16 pointer)
+ offset = secondExportTable.getUint16SEAt(3 + pubfunct);
}
}
@@ -855,61 +838,58 @@ uint32 Script::validateExportFunc(int pubfunct, bool relocSci3) {
offset = _codeOffset;
}
- if (offset >= _bufSize)
+ if (offset >= _buf->size())
error("Invalid export function pointer");
return offset;
}
-byte *Script::findBlockSCI0(int type, int startBlockIndex) {
- byte *buf = _buf;
+SciSpan<const byte> Script::findBlockSCI0(ScriptObjectTypes type, int startBlockIndex) {
+ SciSpan<const byte> buf = *_buf;
bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
int blockIndex = 0;
if (oldScriptHeader)
buf += 2;
- do {
- int blockType = READ_LE_UINT16(buf);
+ for (;;) {
+ const int blockType = buf.getUint16LEAt(0);
if (blockType == 0)
break;
- if (blockType == type && blockIndex > startBlockIndex)
- return buf;
- int blockSize = READ_LE_UINT16(buf + 2);
+ // the size in the block header includes the size of the header itself
+ const int blockSize = buf.getUint16LEAt(2);
assert(blockSize > 0);
+
+ if (blockType == type && blockIndex > startBlockIndex) {
+ return buf.subspan(0, blockSize, Common::String::format("%s, %s block", _buf->name().c_str(), sciObjectTypeNames[type]));
+ }
+
buf += blockSize;
blockIndex++;
- } while (1);
+ }
- return NULL;
+ return SciSpan<const byte>();
}
// memory operations
-void Script::mcpyInOut(int dst, const void *src, size_t n) {
- if (_buf) {
- assert(dst + n <= _bufSize);
- memcpy(_buf + dst, src, n);
- }
-}
-
bool Script::isValidOffset(uint16 offset) const {
- return offset < _bufSize;
+ return offset < _buf->size();
}
SegmentRef Script::dereference(reg_t pointer) {
- if (pointer.getOffset() > _bufSize) {
- error("Script::dereference(): Attempt to dereference invalid pointer %04x:%04x into script segment (script size=%d)",
- PRINT_REG(pointer), (uint)_bufSize);
+ if (pointer.getOffset() > _buf->size()) {
+ error("Script::dereference(): Attempt to dereference invalid pointer %04x:%04x into script segment (script size=%lu)",
+ PRINT_REG(pointer), _buf->size());
return SegmentRef();
}
SegmentRef ret;
ret.isRaw = true;
- ret.maxSize = _bufSize - pointer.getOffset();
- ret.raw = _buf + pointer.getOffset();
+ ret.maxSize = _buf->size() - pointer.getOffset();
+ ret.raw = const_cast<byte *>(_buf->getUnsafeDataAt(pointer.getOffset(), ret.maxSize));
return ret;
}
@@ -938,10 +918,10 @@ void Script::initializeLocals(SegManager *segMan) {
LocalVariables *locals = allocLocalsSegment(segMan);
if (locals) {
if (getSciVersion() > SCI_VERSION_0_EARLY) {
- const byte *base = (const byte *)(_buf + getLocalsOffset());
+ const SciSpan<const byte> base = _buf->subspan(getLocalsOffset());
for (uint16 i = 0; i < getLocalsCount(); i++)
- locals->_locals[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(base + i * 2));
+ locals->_locals[i] = make_reg(0, base.getUint16SEAt(i * 2));
} else {
// In SCI0 early, locals are set at run time, thus zero them all here
for (uint16 i = 0; i < getLocalsCount(); i++)
@@ -955,14 +935,19 @@ void Script::syncLocalsBlock(SegManager *segMan) {
}
void Script::initializeClasses(SegManager *segMan) {
- const byte *seeker = 0;
+ SciSpan<const byte> seeker;
uint16 mult = 0;
if (getSciVersion() <= SCI_VERSION_1_LATE) {
- seeker = findBlockSCI0(SCI_OBJ_CLASS);
+ seeker = _script;
mult = 1;
+
+ // SCI0 early has an extra two bytes of header
+ if (getSciVersion() == SCI_VERSION_0_EARLY) {
+ seeker += 2;
+ }
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
- seeker = _heapStart + 4 + READ_SCI11ENDIAN_UINT16(_heapStart + 2) * 2;
+ seeker = _heap.subspan(4 + _heap.getUint16SEAt(2) * 2);
mult = 2;
} else if (getSciVersion() == SCI_VERSION_3) {
seeker = getSci3ObjectsPointer();
@@ -977,10 +962,10 @@ void Script::initializeClasses(SegManager *segMan) {
uint32 classpos;
int16 species = 0;
- while (true) {
+ for (;;) {
// In SCI0-SCI1, this is the segment type. In SCI11, it's a marker (0x1234)
- marker = READ_SCI11ENDIAN_UINT16(seeker);
- classpos = seeker - _buf;
+ marker = seeker.getUint16SEAt(0);
+ classpos = seeker - *_buf;
if (getSciVersion() <= SCI_VERSION_1_LATE && !marker)
break;
@@ -991,14 +976,14 @@ void Script::initializeClasses(SegManager *segMan) {
if (getSciVersion() <= SCI_VERSION_1_LATE) {
isClass = (marker == SCI_OBJ_CLASS);
if (isClass)
- species = READ_SCI11ENDIAN_UINT16(seeker + 12);
+ species = seeker.getUint16SEAt(12);
classpos += 12;
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
- isClass = (READ_SCI11ENDIAN_UINT16(seeker + 14) & kInfoFlagClass); // -info- selector
- species = READ_SCI11ENDIAN_UINT16(seeker + 10);
+ isClass = (seeker.getUint16SEAt(14) & kInfoFlagClass); // -info- selector
+ species = seeker.getUint16SEAt(10);
} else if (getSciVersion() == SCI_VERSION_3) {
- isClass = (READ_SCI11ENDIAN_UINT16(seeker + 10) & kInfoFlagClass);
- species = READ_SCI11ENDIAN_UINT16(seeker + 4);
+ isClass = (seeker.getUint16SEAt(10) & kInfoFlagClass);
+ species = seeker.getUint16SEAt(4);
}
if (isClass) {
@@ -1022,7 +1007,7 @@ void Script::initializeClasses(SegManager *segMan) {
segMan->setClassOffset(species, make_reg(segmentId, classpos));
}
- seeker += READ_SCI11ENDIAN_UINT16(seeker + 2) * mult;
+ seeker += seeker.getUint16SEAt(2) * mult;
}
}
@@ -1032,10 +1017,10 @@ void Script::initializeObjectsSci0(SegManager *segMan, SegmentId segmentId) {
// We need to make two passes, as the objects in the script might be in the
// wrong order (e.g. in the demo of Iceman) - refer to bug #3034713
for (int pass = 1; pass <= 2; pass++) {
- const byte *seeker = _buf + (oldScriptHeader ? 2 : 0);
+ SciSpan<const byte> seeker = _buf->subspan(oldScriptHeader ? 2 : 0);
do {
- uint16 objType = READ_SCI11ENDIAN_UINT16(seeker);
+ uint16 objType = seeker.getUint16SEAt(0);
if (!objType)
break;
@@ -1043,7 +1028,7 @@ void Script::initializeObjectsSci0(SegManager *segMan, SegmentId segmentId) {
case SCI_OBJ_OBJECT:
case SCI_OBJ_CLASS:
{
- reg_t addr = make_reg(segmentId, seeker - _buf + 4);
+ reg_t addr = make_reg(segmentId, seeker - *_buf + 4);
Object *obj = scriptObjInit(addr);
obj->initSpecies(segMan, addr);
@@ -1069,20 +1054,20 @@ void Script::initializeObjectsSci0(SegManager *segMan, SegmentId segmentId) {
break;
}
- seeker += READ_SCI11ENDIAN_UINT16(seeker + 2);
- } while ((uint32)(seeker - _buf) < getScriptSize() - 2);
+ seeker += seeker.getUint16SEAt(2);
+ } while ((uint32)(seeker - *_buf) < getScriptSize() - 2);
}
- byte *relocationBlock = findBlockSCI0(SCI_OBJ_POINTERS);
+ const SciSpan<const byte> relocationBlock = findBlockSCI0(SCI_OBJ_POINTERS);
if (relocationBlock)
- relocateSci0Sci21(make_reg(segmentId, relocationBlock - getBuf() + 4));
+ relocateSci0Sci21(make_reg(segmentId, relocationBlock - *_buf + 4));
}
void Script::initializeObjectsSci11(SegManager *segMan, SegmentId segmentId) {
- const byte *seeker = _heapStart + 4 + READ_SCI11ENDIAN_UINT16(_heapStart + 2) * 2;
+ SciSpan<const byte> seeker = _heap.subspan(4 + _heap.getUint16SEAt(2) * 2);
- while (READ_SCI11ENDIAN_UINT16(seeker) == SCRIPT_OBJECT_MAGIC_NUMBER) {
- reg_t reg = make_reg(segmentId, seeker - _buf);
+ while (seeker.getUint16SEAt(0) == SCRIPT_OBJECT_MAGIC_NUMBER) {
+ reg_t reg = make_reg(segmentId, seeker - *_buf);
Object *obj = scriptObjInit(reg);
// Copy base from species class, as we need its selector IDs
@@ -1113,26 +1098,26 @@ void Script::initializeObjectsSci11(SegManager *segMan, SegmentId segmentId) {
// to be sufficient.
obj->setClassScriptSelector(make_reg(0, _nr));
- seeker += READ_SCI11ENDIAN_UINT16(seeker + 2) * 2;
+ seeker += seeker.getUint16SEAt(2) * 2;
}
- relocateSci0Sci21(make_reg(segmentId, READ_SCI11ENDIAN_UINT16(_heapStart)));
+ relocateSci0Sci21(make_reg(segmentId, _heap.getUint16SEAt(0)));
}
void Script::initializeObjectsSci3(SegManager *segMan, SegmentId segmentId) {
- const byte *seeker = getSci3ObjectsPointer();
+ SciSpan<const byte> seeker = getSci3ObjectsPointer();
- while (READ_SCI11ENDIAN_UINT16(seeker) == SCRIPT_OBJECT_MAGIC_NUMBER) {
+ while (seeker.getUint16SEAt(0) == SCRIPT_OBJECT_MAGIC_NUMBER) {
// We call setSegment and setOffset directly here, instead of using
// make_reg, as in large scripts, seeker - _buf can be larger than
// a 16-bit integer
reg_t reg;
reg.setSegment(segmentId);
- reg.setOffset(seeker - _buf);
+ reg.setOffset(seeker - *_buf);
Object *obj = scriptObjInit(reg);
obj->setSuperClassSelector(segMan->getClassAddress(obj->getSuperClassSelector().getOffset(), SCRIPT_GET_LOCK, 0));
- seeker += READ_SCI11ENDIAN_UINT16(seeker + 2);
+ seeker += seeker.getUint16SEAt(2);
}
relocateSci3(make_reg(segmentId, 0));
@@ -1170,7 +1155,7 @@ Common::Array<reg_t> Script::listAllDeallocatable(SegmentId segId) const {
Common::Array<reg_t> Script::listAllOutgoingReferences(reg_t addr) const {
Common::Array<reg_t> tmp;
- if (addr.getOffset() <= _bufSize && addr.getOffset() >= (uint)-SCRIPT_OBJECT_MAGIC_OFFSET && offsetIsObject(addr.getOffset())) {
+ if (addr.getOffset() <= _buf->size() && addr.getOffset() >= (uint)-SCRIPT_OBJECT_MAGIC_OFFSET && offsetIsObject(addr.getOffset())) {
const Object *obj = getObject(addr.getOffset());
if (obj) {
// Note all local variables, if we have a local variable environment
@@ -1207,7 +1192,7 @@ Common::Array<reg_t> Script::listObjectReferences() const {
}
bool Script::offsetIsObject(uint16 offset) const {
- return (READ_SCI11ENDIAN_UINT16((const byte *)_buf + offset + SCRIPT_OBJECT_MAGIC_OFFSET) == SCRIPT_OBJECT_MAGIC_NUMBER);
+ return _buf->getUint16SEAt(offset + SCRIPT_OBJECT_MAGIC_OFFSET) == SCRIPT_OBJECT_MAGIC_NUMBER;
}
} // End of namespace Sci
diff --git a/engines/sci/engine/script.h b/engines/sci/engine/script.h
index 677b367051..52b58eec2e 100644
--- a/engines/sci/engine/script.h
+++ b/engines/sci/engine/script.h
@@ -24,6 +24,7 @@
#define SCI_ENGINE_SCRIPT_H
#include "common/str.h"
+#include "sci/util.h"
#include "sci/engine/segment.h"
#include "sci/engine/script_patches.h"
@@ -67,19 +68,16 @@ typedef Common::Array<offsetLookupArrayEntry> offsetLookupArrayType;
class Script : public SegmentObj {
private:
int _nr; /**< Script number */
- byte *_buf; /**< Static data buffer, or NULL if not used */
- byte *_heapStart; /**< Start of heap if SCI1.1, NULL otherwise */
+ Common::SpanOwner<SciSpan<const byte> > _buf; /**< Static data buffer, or NULL if not used */
+ SciSpan<const byte> _script; /**< Script size includes alignment byte */
+ SciSpan<const byte> _heap; /**< Start of heap if SCI1.1, NULL otherwise */
int _lockers; /**< Number of classes and objects that require this script */
- size_t _scriptSize;
- size_t _heapSize;
- size_t _bufSize;
- const uint16 *_exportTable; /**< Abs. offset of the export table or 0 if not present */
- uint16 _numExports; /**< Number of entries in the exports table */
-
- const byte *_synonyms; /**< Synonyms block or 0 if not present */
- uint16 _numSynonyms; /**< Number of entries in the synonyms block */
+ SciSpan<const uint16> _exports; /**< Exports block or 0 if not present */
+ uint16 _numExports; /**< Number of export entries */
+ SciSpan<const byte> _synonyms; /**< Synonyms block or 0 if not present */
+ uint16 _numSynonyms; /**< Number of synonym entries */
int _codeOffset; /**< The absolute offset of the VM code block */
@@ -104,10 +102,11 @@ public:
int getLocalsOffset() const { return _localsOffset; }
uint16 getLocalsCount() const { return _localsCount; }
- uint32 getScriptSize() const { return _scriptSize; }
- uint32 getHeapSize() const { return _heapSize; }
- uint32 getBufSize() const { return _bufSize; }
- const byte *getBuf(uint offset = 0) const { return _buf + offset; }
+ uint32 getScriptSize() const { return _script.size(); }
+ uint32 getHeapSize() const { return _heap.size(); }
+ uint32 getBufSize() const { return _buf->size(); }
+
+ const byte *getBuf(uint offset = 0) const { return _buf->getUnsafeDataAt(offset); }
int getScriptNumber() const { return _nr; }
SegmentId getLocalsSegment() const { return _localsSegment; }
@@ -192,10 +191,10 @@ public:
void setLockers(int lockers);
/**
- * Retrieves a pointer to the exports of this script
- * @return pointer to the exports.
+ * Retrieves the offset of the export table in the script
+ * @return the exports offset.
*/
- const uint16 *getExportTable() const { return _exportTable; }
+ uint getExportsOffset() const { return _exports.sourceByteOffset(); }
/**
* Retrieves the number of exports of script.
@@ -207,7 +206,7 @@ public:
* Retrieves a pointer to the synonyms associated with this script
* @return pointer to the synonyms, in non-parsed format.
*/
- const byte *getSynonyms() const { return _synonyms; }
+ const SciSpan<const byte> &getSynonyms() const { return _synonyms; }
/**
* Retrieves the number of synonyms associated with this script.
@@ -244,18 +243,10 @@ public:
}
/**
- * Copies a byte string into a script's heap representation.
- * @param dst script-relative offset of the destination area
- * @param src pointer to the data source location
- * @param n number of bytes to copy
- */
- void mcpyInOut(int dst, const void *src, size_t n);
-
- /**
* Finds the pointer where a block of a specific type starts from,
* in SCI0 - SCI1 games
*/
- byte *findBlockSCI0(int type, int startBlockIndex = -1);
+ SciSpan<const byte> findBlockSCI0(ScriptObjectTypes type, int startBlockIndex = -1);
/**
* Syncs the string heap of a script. Used when saving/loading.
@@ -271,7 +262,7 @@ public:
/**
* Gets an offset to the beginning of the code block in a SCI3 script
*/
- int getCodeBlockOffsetSci3() { return READ_SCI11ENDIAN_UINT32(_buf); }
+ int getCodeBlockOffsetSci3() { return _buf->getInt32SEAt(0); }
/**
* Get the offset array
@@ -303,7 +294,7 @@ private:
/**
* Gets a pointer to the beginning of the objects in a SCI3 script
*/
- const byte *getSci3ObjectsPointer();
+ SciSpan<const byte> getSci3ObjectsPointer();
/**
* Initializes the script's objects (SCI0)
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index cf3a981347..d84d2ab780 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -4975,7 +4975,7 @@ ScriptPatcher::~ScriptPatcher() {
}
// will actually patch previously found signature area
-void ScriptPatcher::applyPatch(const SciScriptPatcherEntry *patchEntry, byte *scriptData, const uint32 scriptSize, int32 signatureOffset) {
+void ScriptPatcher::applyPatch(const SciScriptPatcherEntry *patchEntry, SciSpan<byte> scriptData, int32 signatureOffset) {
const uint16 *patchData = patchEntry->patchData;
byte orgData[PATCH_VALUELIMIT];
int32 offset = signatureOffset;
@@ -4983,10 +4983,10 @@ void ScriptPatcher::applyPatch(const SciScriptPatcherEntry *patchEntry, byte *sc
uint16 patchSelector = 0;
// Copy over original bytes from script
- uint32 orgDataSize = scriptSize - offset;
+ uint32 orgDataSize = scriptData.size() - offset;
if (orgDataSize > PATCH_VALUELIMIT)
orgDataSize = PATCH_VALUELIMIT;
- memcpy(&orgData, &scriptData[offset], orgDataSize);
+ scriptData.subspan(offset, orgDataSize).unsafeCopyDataTo(orgData);
while (patchWord != PATCH_END) {
uint16 patchCommand = patchWord & PATCH_COMMANDMASK;
@@ -5082,7 +5082,7 @@ void ScriptPatcher::applyPatch(const SciScriptPatcherEntry *patchEntry, byte *sc
}
}
-bool ScriptPatcher::verifySignature(uint32 byteOffset, const uint16 *signatureData, const char *signatureDescription, const byte *scriptData, const uint32 scriptSize) {
+bool ScriptPatcher::verifySignature(uint32 byteOffset, const uint16 *signatureData, const char *signatureDescription, const SciSpan<const byte> &scriptData) {
uint16 sigSelector = 0;
uint16 sigWord = *signatureData;
@@ -5097,7 +5097,7 @@ bool ScriptPatcher::verifySignature(uint32 byteOffset, const uint16 *signatureDa
}
case SIG_CODE_UINT16:
case SIG_CODE_SELECTOR16: {
- if ((byteOffset + 1) < scriptSize) {
+ if (byteOffset + 1 < scriptData.size()) {
byte byte1;
byte byte2;
@@ -5134,7 +5134,7 @@ bool ScriptPatcher::verifySignature(uint32 byteOffset, const uint16 *signatureDa
break;
}
case SIG_CODE_SELECTOR8: {
- if (byteOffset < scriptSize) {
+ if (byteOffset < scriptData.size()) {
sigSelector = _selectorIdTable[sigValue];
if (sigSelector & 0xFF00)
error("Script-Patcher: 8 bit selector required, game uses 16 bit selector\nFaulty signature: '%s'", signatureDescription);
@@ -5147,7 +5147,7 @@ bool ScriptPatcher::verifySignature(uint32 byteOffset, const uint16 *signatureDa
break;
}
case SIG_CODE_BYTE:
- if (byteOffset < scriptSize) {
+ if (byteOffset < scriptData.size()) {
if (scriptData[byteOffset] != sigWord)
sigWord = SIG_MISMATCH;
byteOffset++;
@@ -5169,20 +5169,20 @@ bool ScriptPatcher::verifySignature(uint32 byteOffset, const uint16 *signatureDa
}
// will return -1 if no match was found, otherwise an offset to the start of the signature match
-int32 ScriptPatcher::findSignature(uint32 magicDWord, int magicOffset, const uint16 *signatureData, const char *patchDescription, const byte *scriptData, const uint32 scriptSize) {
- if (scriptSize < 4) // we need to find a DWORD, so less than 4 bytes is not okay
+int32 ScriptPatcher::findSignature(uint32 magicDWord, int magicOffset, const uint16 *signatureData, const char *patchDescription, const SciSpan<const byte> &scriptData) {
+ if (scriptData.size() < 4) // we need to find a DWORD, so less than 4 bytes is not okay
return -1;
// magicDWord is in platform-specific BE/LE form, so that the later match will work, this was done for performance
- const uint32 searchLimit = scriptSize - 3;
+ const uint32 searchLimit = scriptData.size() - 3;
uint32 DWordOffset = 0;
// first search for the magic DWORD
while (DWordOffset < searchLimit) {
- if (magicDWord == READ_UINT32(scriptData + DWordOffset)) {
+ if (magicDWord == scriptData.getUint32At(DWordOffset)) {
// magic DWORD found, check if actual signature matches
uint32 offset = DWordOffset + magicOffset;
- if (verifySignature(offset, signatureData, patchDescription, scriptData, scriptSize))
+ if (verifySignature(offset, signatureData, patchDescription, scriptData))
return offset;
}
DWordOffset++;
@@ -5191,8 +5191,8 @@ int32 ScriptPatcher::findSignature(uint32 magicDWord, int magicOffset, const uin
return -1;
}
-int32 ScriptPatcher::findSignature(const SciScriptPatcherEntry *patchEntry, const SciScriptPatcherRuntimeEntry *runtimeEntry, const byte *scriptData, const uint32 scriptSize) {
- return findSignature(runtimeEntry->magicDWord, runtimeEntry->magicOffset, patchEntry->signatureData, patchEntry->description, scriptData, scriptSize);
+int32 ScriptPatcher::findSignature(const SciScriptPatcherEntry *patchEntry, const SciScriptPatcherRuntimeEntry *runtimeEntry, const SciSpan<const byte> &scriptData) {
+ return findSignature(runtimeEntry->magicDWord, runtimeEntry->magicOffset, patchEntry->signatureData, patchEntry->description, scriptData);
}
// Attention: Magic DWord is returned using platform specific byte order. This is done on purpose for performance.
@@ -5380,7 +5380,7 @@ void ScriptPatcher::enablePatch(const SciScriptPatcherEntry *patchTable, const c
error("Script-Patcher: no patch found to enable");
}
-void ScriptPatcher::processScript(uint16 scriptNr, byte *scriptData, const uint32 scriptSize) {
+void ScriptPatcher::processScript(uint16 scriptNr, SciSpan<byte> scriptData) {
const SciScriptPatcherEntry *signatureTable = NULL;
const SciScriptPatcherEntry *curEntry = NULL;
SciScriptPatcherRuntimeEntry *curRuntimeEntry = NULL;
@@ -5552,11 +5552,11 @@ void ScriptPatcher::processScript(uint16 scriptNr, byte *scriptData, const uint3
int32 foundOffset = 0;
int16 applyCount = curEntry->applyCount;
do {
- foundOffset = findSignature(curEntry, curRuntimeEntry, scriptData, scriptSize);
+ 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);
- applyPatch(curEntry, scriptData, scriptSize, foundOffset);
+ applyPatch(curEntry, scriptData, foundOffset);
}
applyCount--;
} while ((foundOffset != -1) && (applyCount));
diff --git a/engines/sci/engine/script_patches.h b/engines/sci/engine/script_patches.h
index b5797be847..69f9794764 100644
--- a/engines/sci/engine/script_patches.h
+++ b/engines/sci/engine/script_patches.h
@@ -97,14 +97,14 @@ public:
void calculateMagicDWordAndVerify(const char *signatureDescription, const uint16 *signatureData, bool magicDWordIncluded, uint32 &calculatedMagicDWord, int &calculatedMagicDWordOffset);
// Called when a script is loaded to check for signature matches and apply patches in such cases
- void processScript(uint16 scriptNr, byte *scriptData, const uint32 scriptSize);
+ void processScript(uint16 scriptNr, SciSpan<byte> scriptData);
// Verifies, if a given signature matches the given script data (pointed to by additional byte offset)
- bool verifySignature(uint32 byteOffset, const uint16 *signatureData, const char *signatureDescription, const byte *scriptData, const uint32 scriptSize);
+ bool verifySignature(uint32 byteOffset, const uint16 *signatureData, const char *signatureDescription, const SciSpan<const byte> &scriptData);
// searches for a given signature inside script data
// returns -1 in case it was not found or an offset to the matching data
- int32 findSignature(uint32 magicDWord, int magicOffset, const uint16 *signatureData, const char *patchDescription, const byte *scriptData, const uint32 scriptSize);
+ int32 findSignature(uint32 magicDWord, int magicOffset, const uint16 *signatureData, const char *patchDescription, const SciSpan<const byte> &scriptData);
private:
// Initializes a patch table and creates run time information for it (for enabling/disabling), also calculates magic DWORD)
@@ -115,10 +115,10 @@ private:
// Searches for a given signature entry inside script data
// returns -1 in case it was not found or an offset to the matching data
- int32 findSignature(const SciScriptPatcherEntry *patchEntry, const SciScriptPatcherRuntimeEntry *runtimeEntry, const byte *scriptData, const uint32 scriptSize);
+ int32 findSignature(const SciScriptPatcherEntry *patchEntry, const SciScriptPatcherRuntimeEntry *runtimeEntry, const SciSpan<const byte> &scriptData);
// Applies a patch to a given script + offset (overwrites parts)
- void applyPatch(const SciScriptPatcherEntry *patchEntry, byte *scriptData, const uint32 scriptSize, int32 signatureOffset);
+ void applyPatch(const SciScriptPatcherEntry *patchEntry, SciSpan<byte> scriptData, int32 signatureOffset);
Selector *_selectorIdTable;
SciScriptPatcherRuntimeEntry *_runtimeTable;
diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp
index 6002cbd8e4..d15cf83b71 100644
--- a/engines/sci/engine/scriptdebug.cpp
+++ b/engines/sci/engine/scriptdebug.cpp
@@ -71,8 +71,6 @@ const char *opcodeNames[] = {
reg_t disassemble(EngineState *s, reg32_t pos, reg_t objAddr, bool printBWTag, bool printBytecode) {
SegmentObj *mobj = s->_segMan->getSegment(pos.getSegment(), SEG_TYPE_SCRIPT);
Script *script_entity = NULL;
- const byte *scr;
- uint32 scr_size;
reg_t retval = make_reg(pos.getSegment(), pos.getOffset() + 1);
uint16 param_value = 0xffff; // Suppress GCC warning by setting default value, chose value as invalid to getKernelName etc.
uint i = 0;
@@ -84,14 +82,15 @@ reg_t disassemble(EngineState *s, reg32_t pos, reg_t objAddr, bool printBWTag, b
} else
script_entity = (Script *)mobj;
- scr = script_entity->getBuf();
- scr_size = script_entity->getBufSize();
+ uint scr_size = script_entity->getBufSize();
if (pos.getOffset() >= scr_size) {
warning("Trying to disassemble beyond end of script");
return NULL_REG;
}
+ const byte *scr = script_entity->getBuf();
+
int16 opparams[4];
byte opsize;
uint bytecount = readPMachineInstruction(scr + pos.getOffset(), opsize, opparams);
@@ -348,12 +347,13 @@ bool isJumpOpcode(EngineState *s, reg_t pos, reg_t& jumpTarget) {
return false;
Script *script_entity = (Script *)mobj;
- const byte *scr = script_entity->getBuf();
uint scr_size = script_entity->getScriptSize();
if (pos.getOffset() >= scr_size)
return false;
+ const byte *scr = script_entity->getBuf();
+
int16 opparams[4];
byte opsize;
int bytecount = readPMachineInstruction(scr + pos.getOffset(), opsize, opparams);
@@ -449,107 +449,114 @@ void SciEngine::scriptDebug() {
_console->attach();
}
-void Kernel::dumpScriptObject(char *data, int seeker, int objsize) {
- int selectors, overloads, selectorsize;
- int species = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + 8 + seeker);
- int superclass = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + 10 + seeker);
- int namepos = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + 14 + seeker);
+void Kernel::dumpScriptObject(const SciSpan<const byte> &script, SciSpan <const byte> object) {
+ const int16 species = object.getInt16SEAt(8);
+ const int16 superclass = object.getInt16SEAt(10);
+ const int16 namepos = object.getInt16SEAt(14);
int i = 0;
debugN("Object\n");
- Common::hexdump((unsigned char *) data + seeker, objsize - 4, 16, seeker);
//-4 because the size includes the two-word header
+ Common::hexdump(object.getUnsafeDataAt(0, object.size() - 4), object.size() - 4, 16, object.sourceByteOffset());
- debugN("Name: %s\n", namepos ? ((char *)(data + namepos)) : "<unknown>");
+ debugN("Name: %s\n", namepos ? script.getStringAt(namepos).c_str() : "<unknown>");
debugN("Superclass: %x\n", superclass);
debugN("Species: %x\n", species);
- debugN("-info-:%x\n", (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + 12 + seeker) & 0xffff);
+ debugN("-info-: %x\n", object.getInt16SEAt(12) & 0xFFFF);
+
+ debugN("Function area offset: %x\n", object.getInt16SEAt(4));
- debugN("Function area offset: %x\n", (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + seeker + 4));
- debugN("Selectors [%x]:\n", selectors = (selectorsize = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + seeker + 6)));
+ int16 selectors = object.getInt16SEAt(6);
+ debugN("Selectors [%x]:\n", selectors);
- seeker += 8;
+ object += 8;
while (selectors--) {
- debugN(" [#%03x] = 0x%x\n", i++, (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker) & 0xffff);
- seeker += 2;
+ debugN(" [#%03x] = 0x%x\n", i++, object.getInt16SEAt(0) & 0xFFFF);
+ object += 2;
}
- debugN("Overridden functions: %x\n", selectors = overloads = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker));
+ selectors = object.getInt16SEAt(0);
+ int16 overloads = selectors;
+ debugN("Overridden functions: %x\n", overloads);
- seeker += 2;
+ object += 2;
- if (overloads < 100)
+ if (overloads < 100) {
while (overloads--) {
- int selector = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + (seeker));
+ const int16 selector = object.getInt16SEAt(0);
- debugN(" [%03x] %s: @", selector & 0xffff, (selector >= 0 && selector < (int)_selectorNames.size()) ? _selectorNames[selector].c_str() : "<?>");
- debugN("%04x\n", (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker + selectors*2 + 2) & 0xffff);
+ debugN(" [%03x] %s: @", selector & 0xFFFF, (selector >= 0 && selector < (int)_selectorNames.size()) ? _selectorNames[selector].c_str() : "<?>");
+ debugN("%04x\n", object.getInt16SEAt(selectors * 2 + 2) & 0xFFFF);
- seeker += 2;
+ object += 2;
}
+ }
}
-void Kernel::dumpScriptClass(char *data, int seeker, int objsize) {
- int selectors, overloads, selectorsize;
- int species = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + 8 + seeker);
- int superclass = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + 10 + seeker);
- int namepos = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + 14 + seeker);
+void Kernel::dumpScriptClass(const SciSpan<const byte> &script, SciSpan<const byte> clazz) {
+ const int16 species = clazz.getInt16SEAt(8);
+ const int16 superclass = clazz.getInt16SEAt(10);
+ const int16 namepos = clazz.getInt16SEAt(14);
debugN("Class\n");
- Common::hexdump((unsigned char *) data + seeker, objsize - 4, 16, seeker);
+ Common::hexdump(clazz.getUnsafeDataAt(0, clazz.size() - 4), clazz.size() - 4, 16, clazz.sourceByteOffset());
- debugN("Name: %s\n", namepos ? ((char *)data + namepos) : "<unknown>");
+ debugN("Name: %s\n", namepos ? script.getStringAt(namepos).c_str() : "<unknown>");
debugN("Superclass: %x\n", superclass);
debugN("Species: %x\n", species);
- debugN("-info-:%x\n", (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + 12 + seeker) & 0xffff);
+ debugN("-info-: %x\n", clazz.getInt16SEAt(12) & 0xFFFF);
+
+ debugN("Function area offset: %x\n", clazz.getInt16SEAt(4));
- debugN("Function area offset: %x\n", (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker + 4));
- debugN("Selectors [%x]:\n", selectors = (selectorsize = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker + 6)));
+ int16 selectors = clazz.getInt16SEAt(6);
+ int16 selectorsize = selectors;
+ debugN("Selectors [%x]:\n", selectors);
- seeker += 8;
+ clazz += 8;
selectorsize <<= 1;
while (selectors--) {
- int selector = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *) data + (seeker) + selectorsize);
+ const int16 selector = clazz.getInt16SEAt(selectorsize);
- debugN(" [%03x] %s = 0x%x\n", 0xffff & selector, (selector >= 0 && selector < (int)_selectorNames.size()) ? _selectorNames[selector].c_str() : "<?>",
- (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker) & 0xffff);
+ debugN(" [%03x] %s = 0x%x\n", selector & 0xFFFF, (selector >= 0 && selector < (int)_selectorNames.size()) ? _selectorNames[selector].c_str() : "<?>", clazz.getInt16SEAt(0) & 0xFFFF);
- seeker += 2;
+ clazz += 2;
}
- seeker += selectorsize;
+ clazz += selectorsize;
- debugN("Overloaded functions: %x\n", selectors = overloads = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker));
+ int16 overloads = clazz.getInt16SEAt(0);
+ selectors = overloads;
+ debugN("Overloaded functions: %x\n", overloads);
- seeker += 2;
+ clazz += 2;
while (overloads--) {
- int selector = (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + (seeker));
+ int16 selector = clazz.getInt16SEAt(0);
debugN("selector=%d; selectorNames.size() =%d\n", selector, _selectorNames.size());
- debugN(" [%03x] %s: @", selector & 0xffff, (selector >= 0 && selector < (int)_selectorNames.size()) ?
+ debugN(" [%03x] %s: @", selector & 0xFFFF, (selector >= 0 && selector < (int)_selectorNames.size()) ?
_selectorNames[selector].c_str() : "<?>");
- debugN("%04x\n", (int16)READ_SCI11ENDIAN_UINT16((unsigned char *)data + seeker + selectors * 2 + 2) & 0xffff);
+ debugN("%04x\n", clazz.getInt16SEAt(selectors * 2 + 2) & 0xFFFF);
- seeker += 2;
+ clazz += 2;
}
}
void Kernel::dissectScript(int scriptNumber, Vocabulary *vocab) {
int objectctr[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint32 _seeker = 0;
- Resource *script = _resMan->findResource(ResourceId(kResourceTypeScript, scriptNumber), 0);
+ Resource *script = _resMan->findResource(ResourceId(kResourceTypeScript, scriptNumber), false);
if (!script) {
warning("dissectScript(): Script not found!\n");
return;
}
- while (_seeker < script->size) {
- int objType = (int16)READ_SCI11ENDIAN_UINT16(script->data + _seeker);
+ while (_seeker < script->size()) {
+ int objType = script->getInt16SEAt(_seeker);
int objsize;
uint32 seeker = _seeker + 4;
@@ -562,7 +569,7 @@ void Kernel::dissectScript(int scriptNumber, Vocabulary *vocab) {
debugN("\n");
- objsize = (int16)READ_SCI11ENDIAN_UINT16(script->data + _seeker + 2);
+ objsize = script->getInt16SEAt(_seeker + 2);
debugN("Obj type #%x, size 0x%x: ", objType, objsize);
@@ -573,34 +580,35 @@ void Kernel::dissectScript(int scriptNumber, Vocabulary *vocab) {
switch (objType) {
case SCI_OBJ_OBJECT:
- dumpScriptObject((char *)script->data, seeker, objsize);
+ dumpScriptObject(*script, script->subspan(seeker, objsize));
break;
case SCI_OBJ_CODE:
debugN("Code\n");
- Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
+ Common::hexdump(script->getUnsafeDataAt(seeker, objsize - 4), objsize - 4, 16, seeker);
break;
case SCI_OBJ_SYNONYMS:
debugN("Synonyms\n");
- Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
+ Common::hexdump(script->getUnsafeDataAt(seeker, objsize - 4), objsize - 4, 16, seeker);
break;
case SCI_OBJ_SAID:
debugN("Said\n");
- Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
+ Common::hexdump(script->getUnsafeDataAt(seeker, objsize - 4), objsize - 4, 16, seeker);
debugN("%04x: ", seeker);
- vocab->debugDecipherSaidBlock(script->data + seeker);
+ vocab->debugDecipherSaidBlock(script->subspan(seeker));
debugN("\n");
break;
case SCI_OBJ_STRINGS:
debugN("Strings\n");
- while (script->data [seeker]) {
- debugN("%04x: %s", seeker, script->data + seeker);
- seeker += Common::strnlen((char *)script->data + seeker, script->size - seeker) + 1;
- if (seeker > script->size) {
+ while (script->getUint8At(seeker)) {
+ const Common::String string = script->getStringAt(seeker);
+ debugN("%04x: %s", seeker, string.c_str());
+ seeker += string.size() + 1;
+ if (seeker > script->size()) {
debugN("[TRUNCATED]");
}
debugN("\n");
@@ -609,27 +617,27 @@ void Kernel::dissectScript(int scriptNumber, Vocabulary *vocab) {
break;
case SCI_OBJ_CLASS:
- dumpScriptClass((char *)script->data, seeker, objsize);
+ dumpScriptClass(*script, script->subspan(seeker, objsize));
break;
case SCI_OBJ_EXPORTS:
debugN("Exports\n");
- Common::hexdump((unsigned char *)script->data + seeker, objsize - 4, 16, seeker);
+ Common::hexdump(script->getUnsafeDataAt(seeker, objsize - 4), objsize - 4, 16, seeker);
break;
case SCI_OBJ_POINTERS:
debugN("Pointers\n");
- Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
+ Common::hexdump(script->getUnsafeDataAt(seeker, objsize - 4), objsize - 4, 16, seeker);
break;
case 9:
debugN("<unknown>\n");
- Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
+ Common::hexdump(script->getUnsafeDataAt(seeker, objsize - 4), objsize - 4, 16, seeker);
break;
case SCI_OBJ_LOCALVARS:
debugN("Local vars\n");
- Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
+ Common::hexdump(script->getUnsafeDataAt(seeker, objsize - 4), objsize - 4, 16, seeker);
break;
default:
@@ -821,7 +829,7 @@ void logKernelCall(const KernelFunction *kernelCall, const KernelSubFunction *ke
SegmentRef saidSpec = s->_segMan->dereference(argv[parmNr]);
if (saidSpec.isRaw) {
debugN(" ('");
- g_sci->getVocabulary()->debugDecipherSaidBlock(saidSpec.raw);
+ g_sci->getVocabulary()->debugDecipherSaidBlock(SciSpan<const byte>(saidSpec.raw, saidSpec.maxSize, Common::String::format("said %04x:%04x", PRINT_REG(argv[parmNr]))));
debugN("')");
} else {
debugN(" (non-raw said-spec)");
diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index 9ccd1098d3..3157c84f85 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -976,11 +976,11 @@ void SegManager::createClassTable() {
if (!vocab996)
error("SegManager: failed to open vocab 996");
- int totalClasses = vocab996->size >> 2;
+ int totalClasses = vocab996->size() >> 2;
_classTable.resize(totalClasses);
for (uint16 classNr = 0; classNr < totalClasses; classNr++) {
- uint16 scriptNr = READ_SCI11ENDIAN_UINT16(vocab996->data + classNr * 4 + 2);
+ uint16 scriptNr = vocab996->getUint16SEAt(classNr * 4 + 2);
_classTable[classNr].reg = NULL_REG;
_classTable[classNr].script = scriptNr;
@@ -993,15 +993,13 @@ reg_t SegManager::getClassAddress(int classnr, ScriptLoadType lock, uint16 calle
if (classnr < 0 || (int)_classTable.size() <= classnr || _classTable[classnr].script < 0) {
error("[VM] Attempt to dereference class %x, which doesn't exist (max %x)", classnr, _classTable.size());
- return NULL_REG;
} else {
Class *the_class = &_classTable[classnr];
if (!the_class->reg.getSegment()) {
getScriptSegment(the_class->script, lock);
if (!the_class->reg.getSegment()) {
- error("[VM] Trying to instantiate class %x by instantiating script 0x%x (%03d) failed;", classnr, the_class->script, the_class->script);
- return NULL_REG;
+ error("[VM] Trying to instantiate class %x by instantiating script 0x%x (%03d) failed", classnr, the_class->script, the_class->script);
}
} else
if (callerSegment != the_class->reg.getSegment())
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index ed913b27eb..84211fd432 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -929,7 +929,7 @@ SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroun
}
// now actually check for signature match
- if (g_sci->getScriptPatcher()->verifySignature(curLocalCallOffset, workaround->localCallSignature, "workaround signature", curScriptPtr, curScriptSize)) {
+ if (g_sci->getScriptPatcher()->verifySignature(curLocalCallOffset, workaround->localCallSignature, "workaround signature", SciSpan<const byte>(curScriptPtr, curScriptSize))) {
matched = true;
}
diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp
index 8d92cb905f..317e98feab 100644
--- a/engines/sci/graphics/animate.cpp
+++ b/engines/sci/graphics/animate.cpp
@@ -122,7 +122,7 @@ bool GfxAnimate::detectFastCast() {
// within that game. Which means even though we detect it as having the capability, it's never actually used.
// The original multilingual KQ5 interpreter did have this feature disabled.
// Sierra probably used latest system scripts and that's why we detect it.
- if (_scriptPatcher->findSignature(magicDWord, magicDWordOffset, fastCastSignature, "fast cast detection", scriptData, scriptSize) >= 0) {
+ if (_scriptPatcher->findSignature(magicDWord, magicDWordOffset, fastCastSignature, "fast cast detection", SciSpan<const byte>(scriptData, scriptSize)) >= 0) {
// Signature found, game seems to use fast cast for kAnimate
return true;
}
diff --git a/engines/sci/graphics/celobj32.cpp b/engines/sci/graphics/celobj32.cpp
index 8540b636fc..75f6280460 100644
--- a/engines/sci/graphics/celobj32.cpp
+++ b/engines/sci/graphics/celobj32.cpp
@@ -30,6 +30,7 @@
#include "sci/graphics/remap32.h"
#include "sci/graphics/text32.h"
#include "sci/engine/workarounds.h"
+#include "sci/util.h"
namespace Sci {
#pragma mark CelScaler
@@ -273,8 +274,15 @@ public:
_sourceHeight(celObj._height),
#endif
_sourceWidth(celObj._width) {
- const byte *resource = celObj.getResPointer();
- _pixels = resource + READ_SCI11ENDIAN_UINT32(resource + celObj._celHeaderOffset + 24);
+ const SciSpan<const byte> resource = celObj.getResPointer();
+ const uint32 pixelsOffset = resource.getUint32SEAt(celObj._celHeaderOffset + 24);
+ const int32 numPixels = MIN<int32>(resource.size() - pixelsOffset, celObj._width * celObj._height);
+
+ if (numPixels < celObj._width * celObj._height) {
+ warning("%s is truncated", celObj._info.toString().c_str());
+ }
+
+ _pixels = resource.getUnsafeDataAt(pixelsOffset, numPixels);
}
inline const byte *getRow(const int16 y) const {
@@ -285,7 +293,7 @@ public:
struct READER_Compressed {
private:
- const byte *const _resource;
+ const SciSpan<const byte> _resource;
byte _buffer[kCelScalerTableSize];
uint32 _controlOffset;
uint32 _dataOffset;
@@ -304,20 +312,38 @@ public:
_maxWidth(maxWidth) {
assert(maxWidth <= celObj._width);
- const byte *const celHeader = _resource + celObj._celHeaderOffset;
- _dataOffset = READ_SCI11ENDIAN_UINT32(celHeader + 24);
- _uncompressedDataOffset = READ_SCI11ENDIAN_UINT32(celHeader + 28);
- _controlOffset = READ_SCI11ENDIAN_UINT32(celHeader + 32);
+ const SciSpan<const byte> celHeader = _resource.subspan(celObj._celHeaderOffset);
+ _dataOffset = celHeader.getUint32SEAt(24);
+ _uncompressedDataOffset = celHeader.getUint32SEAt(28);
+ _controlOffset = celHeader.getUint32SEAt(32);
}
inline const byte *getRow(const int16 y) {
assert(y >= 0 && y < _sourceHeight);
if (y != _y) {
// compressed data segment for row
- const byte *row = _resource + _dataOffset + READ_SCI11ENDIAN_UINT32(_resource + _controlOffset + y * 4);
+ const uint32 rowOffset = _resource.getUint32SEAt(_controlOffset + y * sizeof(uint32));
+
+ uint32 rowCompressedSize;
+ if (y + 1 < _sourceHeight) {
+ rowCompressedSize = _resource.getUint32SEAt(_controlOffset + (y + 1) * sizeof(uint32)) - rowOffset;
+ } else {
+ rowCompressedSize = _resource.size() - rowOffset - _dataOffset;
+ }
+
+ const byte *row = _resource.getUnsafeDataAt(_dataOffset + rowOffset, rowCompressedSize);
// uncompressed data segment for row
- const byte *literal = _resource + _uncompressedDataOffset + READ_SCI11ENDIAN_UINT32(_resource + _controlOffset + _sourceHeight * 4 + y * 4);
+ const uint32 literalOffset = _resource.getUint32SEAt(_controlOffset + _sourceHeight * sizeof(uint32) + y * sizeof(uint32));
+
+ uint32 literalRowSize;
+ if (y + 1 < _sourceHeight) {
+ literalRowSize = _resource.getUint32SEAt(_controlOffset + _sourceHeight * sizeof(uint32) + (y + 1) * sizeof(uint32)) - literalOffset;
+ } else {
+ literalRowSize = _resource.size() - literalOffset - _uncompressedDataOffset;
+ }
+
+ const byte *literal = _resource.getUnsafeDataAt(_uncompressedDataOffset + literalOffset, literalRowSize);
uint8 length;
for (int16 i = 0; i < _maxWidth; i += length) {
@@ -573,7 +599,8 @@ uint8 CelObj::readPixel(uint16 x, const uint16 y, bool mirrorX) const {
void CelObj::submitPalette() const {
if (_hunkPaletteOffset) {
- const HunkPalette palette(getResPointer() + _hunkPaletteOffset);
+ const SciSpan<const byte> data = getResPointer();
+ const HunkPalette palette(data.subspan(_hunkPaletteOffset));
g_sci->_gfxPalette32->submit(palette);
}
}
@@ -817,8 +844,7 @@ int16 CelObjView::getNumLoops(const GuiResourceId viewId) {
return 0;
}
- assert(resource->size >= 3);
- return resource->data[2];
+ return resource->getUint8At(2);
}
int16 CelObjView::getNumCels(const GuiResourceId viewId, int16 loopNo) {
@@ -828,7 +854,7 @@ int16 CelObjView::getNumCels(const GuiResourceId viewId, int16 loopNo) {
return 0;
}
- const byte *const data = resource->data;
+ const SciSpan<const byte> &data = *resource;
const uint16 loopCount = data[2];
@@ -849,19 +875,14 @@ int16 CelObjView::getNumCels(const GuiResourceId viewId, int16 loopNo) {
return 0;
}
- const uint16 viewHeaderSize = READ_SCI11ENDIAN_UINT16(data);
+ const uint16 viewHeaderSize = data.getUint16SEAt(0);
const uint8 loopHeaderSize = data[12];
const uint8 viewHeaderFieldSize = 2;
-#ifndef NDEBUG
- const byte *const dataMax = data + resource->size;
-#endif
- const byte *loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * loopNo);
- assert(loopHeader + 3 <= dataMax);
+ SciSpan<const byte> loopHeader = data.subspan(viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * loopNo));
- if ((int8)loopHeader[0] != -1) {
- loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * (int8)loopHeader[0]);
- assert(loopHeader >= data && loopHeader + 3 <= dataMax);
+ if (loopHeader.getInt8At(0) != -1) {
+ loopHeader = data.subspan(viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * loopHeader.getInt8At(0)));
}
return loopHeader[2];
@@ -889,10 +910,6 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
return;
}
- // TODO: The next code should be moved to a common file that
- // generates view resource metadata for both SCI16 and SCI32
- // implementations
-
const Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, viewId), false);
// NOTE: SCI2.1/SQ6 just silently returns here.
@@ -900,10 +917,10 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
error("View resource %d not found", viewId);
}
- const byte *const data = resource->data;
+ const Resource &data = *resource;
- _xResolution = READ_SCI11ENDIAN_UINT16(data + 14);
- _yResolution = READ_SCI11ENDIAN_UINT16(data + 16);
+ _xResolution = data.getUint16SEAt(14);
+ _yResolution = data.getUint16SEAt(16);
if (_xResolution == 0 && _yResolution == 0) {
byte sizeFlag = data[5];
@@ -930,18 +947,18 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
error("Loop is less than 0");
}
- const uint16 viewHeaderSize = READ_SCI11ENDIAN_UINT16(data);
+ const uint16 viewHeaderSize = data.getUint16SEAt(0);
const uint8 loopHeaderSize = data[12];
const uint8 viewHeaderFieldSize = 2;
- const byte *loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * _info.loopNo);
+ SciSpan<const byte> loopHeader = data.subspan(viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * _info.loopNo));
- if ((int8)loopHeader[0] != -1) {
+ if (loopHeader.getInt8At(0) != -1) {
if (loopHeader[1] == 1) {
_mirrorX = true;
}
- loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * (int8)loopHeader[0]);
+ loopHeader = data.subspan(viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * loopHeader.getInt8At(0)));
}
uint8 celCount = loopHeader[2];
@@ -962,18 +979,19 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
error("Cel is less than 0 on loop 0");
}
- _hunkPaletteOffset = READ_SCI11ENDIAN_UINT32(data + 8);
- _celHeaderOffset = READ_SCI11ENDIAN_UINT32(loopHeader + 12) + (data[13] * _info.celNo);
+ _hunkPaletteOffset = data.getUint32SEAt(8);
+ _celHeaderOffset = loopHeader.getUint32SEAt(12) + (data[13] * _info.celNo);
- const byte *const celHeader = data + _celHeaderOffset;
+ const SciSpan<const byte> celHeader = data.subspan(_celHeaderOffset);
- _width = READ_SCI11ENDIAN_UINT16(celHeader);
- _height = READ_SCI11ENDIAN_UINT16(celHeader + 2);
- _origin.x = _width / 2 - (int16)READ_SCI11ENDIAN_UINT16(celHeader + 4);
+ _width = celHeader.getUint16SEAt(0);
+ _height = celHeader.getUint16SEAt(2);
+ assert(_width <= kCelScalerTableSize && _height <= kCelScalerTableSize);
+ _origin.x = _width / 2 - celHeader.getInt16SEAt(4);
if (g_sci->_features->usesAlternateSelectors() && _mirrorX) {
_origin.x = _width - _origin.x - 1;
}
- _origin.y = _height - (int16)READ_SCI11ENDIAN_UINT16(celHeader + 6) - 1;
+ _origin.y = _height - celHeader.getInt16SEAt(6) - 1;
_skipColor = celHeader[8];
_compressionType = (CelCompressionType)celHeader[9];
@@ -984,7 +1002,7 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
if (celHeader[10] & 128) {
// NOTE: This is correct according to SCI2.1/SQ6/DOS;
// the engine re-reads the byte value as a word value
- uint16 flags = READ_SCI11ENDIAN_UINT16(celHeader + 10);
+ const uint16 flags = celHeader.getUint16SEAt(10);
_transparent = flags & 1 ? true : false;
_remap = flags & 2 ? true : false;
} else if (_compressionType == kCelCompressionNone) {
@@ -997,7 +1015,9 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
}
bool CelObjView::analyzeUncompressedForRemap() const {
- const byte *pixels = getResPointer() + READ_SCI11ENDIAN_UINT32(getResPointer() + _celHeaderOffset + 24);
+ const SciSpan<const byte> data = getResPointer();
+ const uint32 pixelsOffset = data.getUint32SEAt(_celHeaderOffset + 24);
+ const byte *pixels = data.getUnsafeDataAt(pixelsOffset, _width * _height);
for (int i = 0; i < _width * _height; ++i) {
const byte pixel = pixels[i];
if (
@@ -1038,12 +1058,12 @@ CelObjView *CelObjView::duplicate() const {
return new CelObjView(*this);
}
-byte *CelObjView::getResPointer() const {
+const SciSpan<const byte> CelObjView::getResPointer() const {
Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, _info.resourceId), false);
if (resource == nullptr) {
error("Failed to load view %d from resource manager", _info.resourceId);
}
- return resource->data;
+ return *resource;
}
#pragma mark -
@@ -1079,31 +1099,31 @@ CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) {
error("Pic resource %d not found", picId);
}
- const byte *const data = resource->data;
+ const Resource &data = *resource;
- _celCount = data[2];
+ _celCount = data.getUint8At(2);
if (_info.celNo >= _celCount) {
error("Cel number %d greater than cel count %d", _info.celNo, _celCount);
}
- _celHeaderOffset = READ_SCI11ENDIAN_UINT16(data) + (READ_SCI11ENDIAN_UINT16(data + 4) * _info.celNo);
- _hunkPaletteOffset = READ_SCI11ENDIAN_UINT32(data + 6);
+ _celHeaderOffset = data.getUint16SEAt(0) + (data.getUint16SEAt(4) * _info.celNo);
+ _hunkPaletteOffset = data.getUint32SEAt(6);
- const byte *const celHeader = data + _celHeaderOffset;
+ const SciSpan<const byte> celHeader = data.subspan(_celHeaderOffset);
- _width = READ_SCI11ENDIAN_UINT16(celHeader);
- _height = READ_SCI11ENDIAN_UINT16(celHeader + 2);
- _origin.x = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 4);
- _origin.y = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 6);
+ _width = celHeader.getUint16SEAt(0);
+ _height = celHeader.getUint16SEAt(2);
+ _origin.x = celHeader.getInt16SEAt(4);
+ _origin.y = celHeader.getInt16SEAt(6);
_skipColor = celHeader[8];
_compressionType = (CelCompressionType)celHeader[9];
- _priority = READ_SCI11ENDIAN_UINT16(celHeader + 36);
- _relativePosition.x = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 38);
- _relativePosition.y = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 40);
+ _priority = celHeader.getInt16SEAt(36);
+ _relativePosition.x = celHeader.getInt16SEAt(38);
+ _relativePosition.y = celHeader.getInt16SEAt(40);
- const uint16 sizeFlag1 = READ_SCI11ENDIAN_UINT16(data + 10);
- const uint16 sizeFlag2 = READ_SCI11ENDIAN_UINT16(data + 12);
+ const uint16 sizeFlag1 = data.getUint16SEAt(10);
+ const uint16 sizeFlag2 = data.getUint16SEAt(12);
if (sizeFlag2) {
_xResolution = sizeFlag1;
@@ -1119,10 +1139,10 @@ CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) {
_yResolution = 400;
}
- if (celHeader[10] & 128) {
+ if (celHeader.getUint8At(10) & 128) {
// NOTE: This is correct according to SCI2.1/SQ6/DOS;
// the engine re-reads the byte value as a word value
- const uint16 flags = READ_SCI11ENDIAN_UINT16(celHeader + 10);
+ const uint16 flags = celHeader.getUint16SEAt(10);
_transparent = flags & 1 ? true : false;
_remap = flags & 2 ? true : false;
} else {
@@ -1137,9 +1157,16 @@ CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) {
}
bool CelObjPic::analyzeUncompressedForSkip() const {
- const byte *const resource = getResPointer();
- const byte *const pixels = resource + READ_SCI11ENDIAN_UINT32(resource + _celHeaderOffset + 24);
- for (int i = 0; i < _width * _height; ++i) {
+ const SciSpan<const byte> resource = getResPointer();
+ const uint32 pixelsOffset = resource.getUint32SEAt(_celHeaderOffset + 24);
+ const int32 numPixels = MIN<int32>(resource.size() - pixelsOffset, _width * _height);
+
+ if (numPixels < _width * _height) {
+ warning("%s is truncated", _info.toString().c_str());
+ }
+
+ const byte *const pixels = resource.getUnsafeDataAt(pixelsOffset, numPixels);
+ for (int32 i = 0; i < numPixels; ++i) {
uint8 pixel = pixels[i];
if (pixel == _skipColor) {
return true;
@@ -1159,12 +1186,12 @@ CelObjPic *CelObjPic::duplicate() const {
return new CelObjPic(*this);
}
-byte *CelObjPic::getResPointer() const {
+const SciSpan<const byte> CelObjPic::getResPointer() const {
const Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypePic, _info.resourceId), false);
if (resource == nullptr) {
error("Failed to load pic %d from resource manager", _info.resourceId);
}
- return resource->data;
+ return *resource;
}
#pragma mark -
@@ -1199,8 +1226,9 @@ CelObjMem *CelObjMem::duplicate() const {
return new CelObjMem(*this);
}
-byte *CelObjMem::getResPointer() const {
- return g_sci->getEngineState()->_segMan->lookupBitmap(_info.bitmap)->getRawData();
+const SciSpan<const byte> CelObjMem::getResPointer() const {
+ SciBitmap &bitmap = *g_sci->getEngineState()->_segMan->lookupBitmap(_info.bitmap);
+ return SciSpan<const byte>(bitmap.getRawData(), bitmap.getRawSize(), Common::String::format("bitmap %04x:%04x", PRINT_REG(_info.bitmap)));
}
#pragma mark -
@@ -1237,7 +1265,7 @@ CelObjColor *CelObjColor::duplicate() const {
return new CelObjColor(*this);
}
-byte *CelObjColor::getResPointer() const {
+const SciSpan<const byte> CelObjColor::getResPointer() const {
error("Unsupported method");
}
} // End of namespace Sci
diff --git a/engines/sci/graphics/celobj32.h b/engines/sci/graphics/celobj32.h
index 3e3f81ac62..351a8856b2 100644
--- a/engines/sci/graphics/celobj32.h
+++ b/engines/sci/graphics/celobj32.h
@@ -27,6 +27,7 @@
#include "common/rect.h"
#include "sci/resource.h"
#include "sci/engine/vm_types.h"
+#include "sci/util.h"
namespace Sci {
typedef Common::Rational Ratio;
@@ -413,7 +414,7 @@ public:
* Retrieves a pointer to the raw resource data for this
* cel. This method cannot be used with a CelObjColor.
*/
- virtual byte *getResPointer() const = 0;
+ virtual const SciSpan<const byte> getResPointer() const = 0;
/**
* Reads the pixel at the given coordinates. This method
@@ -535,7 +536,7 @@ public:
void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, bool mirrorX, const Ratio &scaleX, const Ratio &scaleY);
virtual CelObjView *duplicate() const override;
- virtual byte *getResPointer() const override;
+ virtual const SciSpan<const byte> getResPointer() const override;
};
#pragma mark -
@@ -580,7 +581,7 @@ public:
virtual void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX) override;
virtual CelObjPic *duplicate() const override;
- virtual byte *getResPointer() const override;
+ virtual const SciSpan<const byte> getResPointer() const override;
};
#pragma mark -
@@ -598,7 +599,7 @@ public:
virtual ~CelObjMem() override {};
virtual CelObjMem *duplicate() const override;
- virtual byte *getResPointer() const override;
+ virtual const SciSpan<const byte> getResPointer() const override;
};
#pragma mark -
@@ -622,7 +623,7 @@ public:
virtual void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX) override;
virtual CelObjColor *duplicate() const override;
- virtual byte *getResPointer() const override;
+ virtual const SciSpan<const byte> getResPointer() const override;
};
} // End of namespace Sci
diff --git a/engines/sci/graphics/compare.cpp b/engines/sci/graphics/compare.cpp
index 36026a8134..582dd328dc 100644
--- a/engines/sci/graphics/compare.cpp
+++ b/engines/sci/graphics/compare.cpp
@@ -197,7 +197,7 @@ bool GfxCompare::kernelIsItSkip(GuiResourceId viewId, int16 loopNo, int16 celNo,
const CelInfo *celInfo = tmpView->getCelInfo(loopNo, celNo);
position.x = CLIP<int>(position.x, 0, celInfo->width - 1);
position.y = CLIP<int>(position.y, 0, celInfo->height - 1);
- const byte *celData = tmpView->getBitmap(loopNo, celNo);
+ const SciSpan<const byte> &celData = tmpView->getBitmap(loopNo, celNo);
bool result = (celData[position.y * celInfo->width + position.x] == celInfo->clearKey);
return result;
}
diff --git a/engines/sci/graphics/cursor.cpp b/engines/sci/graphics/cursor.cpp
index 7cf9a574ef..c29e547b83 100644
--- a/engines/sci/graphics/cursor.cpp
+++ b/engines/sci/graphics/cursor.cpp
@@ -58,7 +58,6 @@ GfxCursor::GfxCursor(ResourceManager *resMan, GfxPalette *palette, GfxScreen *sc
_zoomPicView = 0;
_zoomColor = 0;
_zoomMultiplier = 0;
- _cursorSurface = 0;
if (g_sci && g_sci->getGameId() == GID_KQ6 && g_sci->getPlatform() == Common::kPlatformWindows)
_useOriginalKQ6WinCursors = ConfMan.getBool("windows_cursors");
@@ -110,20 +109,17 @@ void GfxCursor::purgeCache() {
void GfxCursor::kernelSetShape(GuiResourceId resourceId) {
Resource *resource;
- byte *resourceData;
Common::Point hotspot = Common::Point(0, 0);
byte colorMapping[4];
int16 x, y;
byte color;
int16 maskA, maskB;
byte *pOut;
- byte *rawBitmap = new byte[SCI_CURSOR_SCI0_HEIGHTWIDTH * SCI_CURSOR_SCI0_HEIGHTWIDTH];
int16 heightWidth;
if (resourceId == -1) {
// no resourceId given, so we actually hide the cursor
kernelHide();
- delete[] rawBitmap;
return;
}
@@ -131,20 +127,18 @@ void GfxCursor::kernelSetShape(GuiResourceId resourceId) {
resource = _resMan->findResource(ResourceId(kResourceTypeCursor, resourceId), false);
if (!resource)
error("cursor resource %d not found", resourceId);
- if (resource->size != SCI_CURSOR_SCI0_RESOURCESIZE)
+ if (resource->size() != SCI_CURSOR_SCI0_RESOURCESIZE)
error("cursor resource %d has invalid size", resourceId);
- resourceData = resource->data;
-
if (getSciVersion() <= SCI_VERSION_01) {
// SCI0 cursors contain hotspot flags, not actual hotspot coordinates.
// If bit 0 of resourceData[3] is set, the hotspot should be centered,
// otherwise it's in the top left of the mouse cursor.
- hotspot.x = hotspot.y = resourceData[3] ? SCI_CURSOR_SCI0_HEIGHTWIDTH / 2 : 0;
+ hotspot.x = hotspot.y = resource->getUint8At(3) ? SCI_CURSOR_SCI0_HEIGHTWIDTH / 2 : 0;
} else {
// Cursors in newer SCI versions contain actual hotspot coordinates.
- hotspot.x = READ_LE_UINT16(resourceData);
- hotspot.y = READ_LE_UINT16(resourceData + 2);
+ hotspot.x = resource->getUint16LEAt(0);
+ hotspot.y = resource->getUint16LEAt(2);
}
// Now find out what colors we are supposed to use
@@ -160,13 +154,13 @@ void GfxCursor::kernelSetShape(GuiResourceId resourceId) {
if (g_sci->getGameId() == GID_LONGBOW)
colorMapping[3] = _palette->matchColor(223, 223, 223) & SCI_PALETTE_MATCH_COLORMASK; // Light Grey
- // Seek to actual data
- resourceData += 4;
+ Common::SpanOwner<SciSpan<byte> > rawBitmap;
+ rawBitmap->allocate(SCI_CURSOR_SCI0_HEIGHTWIDTH * SCI_CURSOR_SCI0_HEIGHTWIDTH, resource->name() + " copy");
- pOut = rawBitmap;
+ pOut = rawBitmap->getUnsafeDataAt(0, SCI_CURSOR_SCI0_HEIGHTWIDTH * SCI_CURSOR_SCI0_HEIGHTWIDTH);
for (y = 0; y < SCI_CURSOR_SCI0_HEIGHTWIDTH; y++) {
- maskA = READ_LE_UINT16(resourceData + (y << 1));
- maskB = READ_LE_UINT16(resourceData + 32 + (y << 1));
+ maskA = resource->getUint16LEAt(4 + (y << 1));
+ maskB = resource->getUint16LEAt(4 + 32 + (y << 1));
for (x = 0; x < SCI_CURSOR_SCI0_HEIGHTWIDTH; x++) {
color = (((maskA << x) & 0x8000) | (((maskB << x) >> 1) & 0x4000)) >> 14;
@@ -181,9 +175,10 @@ void GfxCursor::kernelSetShape(GuiResourceId resourceId) {
heightWidth *= 2;
hotspot.x *= 2;
hotspot.y *= 2;
- byte *upscaledBitmap = new byte[heightWidth * heightWidth];
- _screen->scale2x(rawBitmap, upscaledBitmap, SCI_CURSOR_SCI0_HEIGHTWIDTH, SCI_CURSOR_SCI0_HEIGHTWIDTH);
- delete[] rawBitmap;
+
+ Common::SpanOwner<SciSpan<byte> > upscaledBitmap;
+ upscaledBitmap->allocate(heightWidth * heightWidth, "upscaled cursor bitmap");
+ _screen->scale2x(*rawBitmap, *upscaledBitmap, SCI_CURSOR_SCI0_HEIGHTWIDTH, SCI_CURSOR_SCI0_HEIGHTWIDTH);
rawBitmap = upscaledBitmap;
}
@@ -192,10 +187,8 @@ void GfxCursor::kernelSetShape(GuiResourceId resourceId) {
resourceId, hotspot.x, hotspot.y, heightWidth, heightWidth);
}
- CursorMan.replaceCursor(rawBitmap, heightWidth, heightWidth, hotspot.x, hotspot.y, SCI_CURSOR_SCI0_TRANSPARENCYCOLOR);
+ CursorMan.replaceCursor(rawBitmap->getUnsafeDataAt(0, heightWidth * heightWidth), heightWidth, heightWidth, hotspot.x, hotspot.y, SCI_CURSOR_SCI0_TRANSPARENCYCOLOR);
kernelShow();
-
- delete[] rawBitmap;
}
void GfxCursor::kernelSetView(GuiResourceId viewNum, int loopNum, int celNum, Common::Point *hotspot) {
@@ -261,19 +254,19 @@ void GfxCursor::kernelSetView(GuiResourceId viewNum, int loopNum, int celNum, Co
return;
}
- const byte *rawBitmap = cursorView->getBitmap(loopNum, celNum);
+ const SciSpan<const byte> &rawBitmap = cursorView->getBitmap(loopNum, celNum);
if (_upscaledHires && !_useOriginalKQ6WinCursors) {
// Scale cursor by 2x - note: sierra didn't do this, but it looks much better
width *= 2;
height *= 2;
cursorHotspot->x *= 2;
cursorHotspot->y *= 2;
- byte *cursorBitmap = new byte[width * height];
- _screen->scale2x(rawBitmap, cursorBitmap, celInfo->width, celInfo->height);
- CursorMan.replaceCursor(cursorBitmap, width, height, cursorHotspot->x, cursorHotspot->y, clearKey);
- delete[] cursorBitmap;
+ Common::SpanOwner<SciSpan<byte> > cursorBitmap;
+ cursorBitmap->allocate(width * height, "upscaled cursor bitmap");
+ _screen->scale2x(rawBitmap, *cursorBitmap, celInfo->width, celInfo->height);
+ CursorMan.replaceCursor(cursorBitmap->getUnsafeDataAt(0, width * height), width, height, cursorHotspot->x, cursorHotspot->y, clearKey);
} else {
- CursorMan.replaceCursor(rawBitmap, width, height, cursorHotspot->x, cursorHotspot->y, clearKey);
+ CursorMan.replaceCursor(rawBitmap.getUnsafeDataAt(0, width * height), width, height, cursorHotspot->x, cursorHotspot->y, clearKey);
}
kernelShow();
@@ -386,10 +379,10 @@ void GfxCursor::refreshPosition() {
if (_zoomZoneActive) {
// Cursor
const CelInfo *cursorCelInfo = _zoomCursorView->getCelInfo(_zoomCursorLoop, _zoomCursorCel);
- const byte *cursorBitmap = _zoomCursorView->getBitmap(_zoomCursorLoop, _zoomCursorCel);
+ const SciSpan<const byte> &cursorBitmap = _zoomCursorView->getBitmap(_zoomCursorLoop, _zoomCursorCel);
// Pic
const CelInfo *picCelInfo = _zoomPicView->getCelInfo(0, 0);
- const byte *rawPicBitmap = _zoomPicView->getBitmap(0, 0);
+ const SciSpan<const byte> &rawPicBitmap = _zoomPicView->getBitmap(0, 0);
// Compute hotspot of cursor
Common::Point cursorHotspot = Common::Point((cursorCelInfo->width >> 1) - cursorCelInfo->displaceX, cursorCelInfo->height - cursorCelInfo->displaceY - 1);
@@ -426,7 +419,7 @@ void GfxCursor::refreshPosition() {
}
}
- CursorMan.replaceCursor(_cursorSurface, cursorCelInfo->width, cursorCelInfo->height, cursorHotspot.x, cursorHotspot.y, cursorCelInfo->clearKey);
+ CursorMan.replaceCursor(_cursorSurface->getUnsafeDataAt(0, cursorCelInfo->width * cursorCelInfo->height), cursorCelInfo->width, cursorCelInfo->height, cursorHotspot.x, cursorHotspot.y, cursorCelInfo->clearKey);
}
}
@@ -449,8 +442,7 @@ void GfxCursor::kernelClearZoomZone() {
_zoomCursorView = 0;
delete _zoomPicView;
_zoomPicView = 0;
- delete[] _cursorSurface;
- _cursorSurface = 0;
+ _cursorSurface.clear();
}
void GfxCursor::kernelSetZoomZone(byte multiplier, Common::Rect zone, GuiResourceId viewNum, int loopNum, int celNum, GuiResourceId picNum, byte zoomColor) {
@@ -474,10 +466,7 @@ void GfxCursor::kernelSetZoomZone(byte multiplier, Common::Rect zone, GuiResourc
_zoomCursorLoop = (byte)loopNum;
_zoomCursorCel = (byte)celNum;
_zoomPicView = new GfxView(_resMan, _screen, _palette, picNum);
- const CelInfo *cursorCelInfo = _zoomCursorView->getCelInfo(_zoomCursorLoop, _zoomCursorCel);
- const byte *cursorBitmap = _zoomCursorView->getBitmap(_zoomCursorLoop, _zoomCursorCel);
- _cursorSurface = new byte[cursorCelInfo->width * cursorCelInfo->height];
- memcpy(_cursorSurface, cursorBitmap, cursorCelInfo->width * cursorCelInfo->height);
+ _cursorSurface->allocateFromSpan(_zoomCursorView->getBitmap(_zoomCursorLoop, _zoomCursorCel));
_zoomZone = zone;
kernelSetMoveZone(_zoomZone);
@@ -537,7 +526,7 @@ void GfxCursor::kernelSetMacCursor(GuiResourceId viewNum, int loopNum, int celNu
assert(resource);
- Common::MemoryReadStream resStream(resource->data, resource->size);
+ Common::MemoryReadStream resStream(resource->toStream());
Graphics::MacCursor *macCursor = new Graphics::MacCursor();
if (!macCursor->readFromStream(resStream)) {
diff --git a/engines/sci/graphics/cursor.h b/engines/sci/graphics/cursor.h
index 36518ea5db..8d9ce7c0ab 100644
--- a/engines/sci/graphics/cursor.h
+++ b/engines/sci/graphics/cursor.h
@@ -27,13 +27,15 @@
#include "common/hashmap.h"
#include "sci/sci.h"
#include "sci/graphics/helpers.h"
+#include "sci/util.h"
namespace Sci {
-#define SCI_CURSOR_SCI0_HEIGHTWIDTH 16
-#define SCI_CURSOR_SCI0_RESOURCESIZE 68
-
-#define SCI_CURSOR_SCI0_TRANSPARENCYCOLOR 1
+enum {
+ SCI_CURSOR_SCI0_HEIGHTWIDTH = 16,
+ SCI_CURSOR_SCI0_RESOURCESIZE = 68,
+ SCI_CURSOR_SCI0_TRANSPARENCYCOLOR = 1
+};
class GfxView;
class GfxPalette;
@@ -117,7 +119,7 @@ private:
GfxView *_zoomPicView;
byte _zoomColor;
byte _zoomMultiplier;
- byte *_cursorSurface;
+ Common::SpanOwner<SciSpan<byte> > _cursorSurface;
CursorCache _cachedCursors;
diff --git a/engines/sci/graphics/cursor32.cpp b/engines/sci/graphics/cursor32.cpp
index 34a6d547e1..e8450b773e 100644
--- a/engines/sci/graphics/cursor32.cpp
+++ b/engines/sci/graphics/cursor32.cpp
@@ -244,7 +244,7 @@ void GfxCursor32::setView(const GuiResourceId viewId, const int16 loopNo, const
debug(0, "Mac cursor %d not found", viewNum);
return;
}
- Common::MemoryReadStream resStream(resource->data, resource->size);
+ Common::MemoryReadStream resStream(resource->toStream());
Graphics::MacCursor *macCursor = new Graphics::MacCursor();
if (!macCursor->readFromStream(resStream)) {
diff --git a/engines/sci/graphics/font.cpp b/engines/sci/graphics/font.cpp
index 2268ec0459..ff2f361d93 100644
--- a/engines/sci/graphics/font.cpp
+++ b/engines/sci/graphics/font.cpp
@@ -40,16 +40,15 @@ GfxFontFromResource::GfxFontFromResource(ResourceManager *resMan, GfxScreen *scr
if (!_resource) {
error("font resource %d not found", resourceId);
}
- _resourceData = _resource->data;
- _numChars = READ_SCI32ENDIAN_UINT16(_resourceData + 2);
- _fontHeight = READ_SCI32ENDIAN_UINT16(_resourceData + 4);
+ _numChars = _resource->getUint16SE32At(2);
+ _fontHeight = _resource->getUint16SE32At(4);
_chars = new Charinfo[_numChars];
// filling info for every char
for (int16 i = 0; i < _numChars; i++) {
- _chars[i].offset = READ_SCI32ENDIAN_UINT16(_resourceData + 6 + i * 2);
- _chars[i].width = _resourceData[_chars[i].offset];
- _chars[i].height = _resourceData[_chars[i].offset + 1];
+ _chars[i].offset = _resource->getUint16SE32At(6 + i * 2);
+ _chars[i].width = _resource->getUint8At(_chars[i].offset);
+ _chars[i].height = _resource->getUint8At(_chars[i].offset + 1);
}
}
@@ -62,20 +61,33 @@ GuiResourceId GfxFontFromResource::getResourceId() {
return _resourceId;
}
-byte GfxFontFromResource::getHeight() {
+uint8 GfxFontFromResource::getHeight() {
return _fontHeight;
}
-byte GfxFontFromResource::getCharWidth(uint16 chr) {
+uint8 GfxFontFromResource::getCharWidth(uint16 chr) {
return chr < _numChars ? _chars[chr].width : 0;
}
-byte GfxFontFromResource::getCharHeight(uint16 chr) {
+uint8 GfxFontFromResource::getCharHeight(uint16 chr) {
return chr < _numChars ? _chars[chr].height : 0;
}
-byte *GfxFontFromResource::getCharData(uint16 chr) {
- return chr < _numChars ? _resourceData + _chars[chr].offset + 2 : 0;
+SciSpan<const byte> GfxFontFromResource::getCharData(uint16 chr) {
+ if (chr >= _numChars) {
+ return SciSpan<const byte>();
+ }
+
+ const uint32 size = (chr + 1 >= _numChars ? _resource->size() : _chars[chr + 1].offset) - _chars[chr].offset - 2;
+ return _resource->subspan(_chars[chr].offset + 2, size);
}
void GfxFontFromResource::draw(uint16 chr, int16 top, int16 left, byte color, bool greyedOutput) {
+ if (chr >= _numChars) {
+ // SSCI silently ignores attempts to draw characters that do not exist
+ // in the font; for now, emit warnings if this happens, to learn if
+ // it leads to any bugs
+ warning("%s is missing glyph %d", _resource->name().c_str(), chr);
+ return;
+ }
+
// Make sure we're comparing against the correct dimensions
// If the font we're drawing is already upscaled, make sure we use the full screen width/height
uint16 screenWidth = _screen->fontIsUpscaled() ? _screen->getDisplayWidth() : _screen->getWidth();
@@ -87,13 +99,13 @@ void GfxFontFromResource::draw(uint16 chr, int16 top, int16 left, byte color, bo
int y = 0;
int16 greyedTop = top;
- byte *pIn = getCharData(chr);
+ SciSpan<const byte> charData = getCharData(chr);
for (int i = 0; i < charHeight; i++, y++) {
if (greyedOutput)
mask = ((greyedTop++) % 2) ? 0xAA : 0x55;
for (int done = 0; done < charWidth; done++) {
if ((done & 7) == 0) // fetching next data byte
- b = *(pIn++) & mask;
+ b = *(charData++) & mask;
if (b & 0x80) // if MSB is set - paint it
_screen->putFontPixel(top, left + done, y, color);
b = b << 1;
@@ -104,19 +116,27 @@ void GfxFontFromResource::draw(uint16 chr, int16 top, int16 left, byte color, bo
#ifdef ENABLE_SCI32
void GfxFontFromResource::drawToBuffer(uint16 chr, int16 top, int16 left, byte color, bool greyedOutput, byte *buffer, int16 bufWidth, int16 bufHeight) {
+ if (chr >= _numChars) {
+ // SSCI silently ignores attempts to draw characters that do not exist
+ // in the font; for now, emit warnings if this happens, to learn if
+ // it leads to any bugs
+ warning("%s is missing glyph %d", _resource->name().c_str(), chr);
+ return;
+ }
+
int charWidth = MIN<int>(getCharWidth(chr), bufWidth - left);
int charHeight = MIN<int>(getCharHeight(chr), bufHeight - top);
byte b = 0, mask = 0xFF;
int y = 0;
int16 greyedTop = top;
- byte *pIn = getCharData(chr);
+ SciSpan<const byte> charData = getCharData(chr);
for (int i = 0; i < charHeight; i++, y++) {
if (greyedOutput)
mask = ((greyedTop++) % 2) ? 0xAA : 0x55;
for (int done = 0; done < charWidth; done++) {
if ((done & 7) == 0) // fetching next data byte
- b = *(pIn++) & mask;
+ b = *(charData++) & mask;
if (b & 0x80) { // if MSB is set - paint it
int offset = (top + y) * bufWidth + (left + done);
buffer[offset] = color;
diff --git a/engines/sci/graphics/font.h b/engines/sci/graphics/font.h
index b79fb2f0ba..4e26510804 100644
--- a/engines/sci/graphics/font.h
+++ b/engines/sci/graphics/font.h
@@ -24,6 +24,7 @@
#define SCI_GRAPHICS_FONT_H
#include "sci/graphics/helpers.h"
+#include "sci/util.h"
namespace Sci {
@@ -51,8 +52,8 @@ public:
~GfxFontFromResource();
GuiResourceId getResourceId();
- byte getHeight();
- byte getCharWidth(uint16 chr);
+ uint8 getHeight();
+ uint8 getCharWidth(uint16 chr);
void draw(uint16 chr, int16 top, int16 left, byte color, bool greyedOutput);
#ifdef ENABLE_SCI32
// SCI2/2.1 equivalent
@@ -60,23 +61,21 @@ public:
#endif
private:
- byte getCharHeight(uint16 chr);
- byte *getCharData(uint16 chr);
+ uint8 getCharHeight(uint16 chr);
+ SciSpan<const byte> getCharData(uint16 chr);
ResourceManager *_resMan;
GfxScreen *_screen;
Resource *_resource;
GuiResourceId _resourceId;
- byte *_resourceData;
struct Charinfo {
- byte width;
- byte height;
+ uint8 width, height;
int16 offset;
};
- byte _fontHeight;
+ uint8 _fontHeight;
uint16 _numChars;
Charinfo *_chars;
};
diff --git a/engines/sci/graphics/maciconbar.cpp b/engines/sci/graphics/maciconbar.cpp
index e10b9fddbf..3a62760398 100644
--- a/engines/sci/graphics/maciconbar.cpp
+++ b/engines/sci/graphics/maciconbar.cpp
@@ -203,11 +203,11 @@ void GfxMacIconBar::setInventoryIcon(int16 icon) {
Graphics::Surface *GfxMacIconBar::loadPict(ResourceId id) {
Resource *res = g_sci->getResMan()->findResource(id, false);
- if (!res || res->size == 0)
+ if (!res || res->size() == 0)
return 0;
Image::PICTDecoder pictDecoder;
- Common::MemoryReadStream stream(res->data, res->size);
+ Common::MemoryReadStream stream(res->toStream());
if (!pictDecoder.loadStream(stream))
return 0;
diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp
index 6fe1fb1b49..307c8aedde 100644
--- a/engines/sci/graphics/palette.cpp
+++ b/engines/sci/graphics/palette.cpp
@@ -134,12 +134,12 @@ void GfxPalette::setDefault() {
#define SCI_PAL_FORMAT_CONSTANT 1
#define SCI_PAL_FORMAT_VARIABLE 0
-void GfxPalette::createFromData(byte *data, int bytesLeft, Palette *paletteOut) const {
+void GfxPalette::createFromData(const SciSpan<const byte> &data, Palette *paletteOut) const {
int palFormat = 0;
- int palOffset = 0;
- int palColorStart = 0;
- int palColorCount = 0;
- int colorNo = 0;
+ uint palOffset = 0;
+ uint palColorStart = 0;
+ uint palColorCount = 0;
+ uint colorNo = 0;
memset(paletteOut, 0, sizeof(Palette));
@@ -148,16 +148,16 @@ void GfxPalette::createFromData(byte *data, int bytesLeft, Palette *paletteOut)
paletteOut->mapping[colorNo] = colorNo;
}
- if (bytesLeft < 37) {
+ if (data.size() < 37) {
// This happens when loading palette of picture 0 in sq5 - the resource is broken and doesn't contain a full
// palette
- debugC(kDebugLevelResMan, "GfxPalette::createFromData() - not enough bytes in resource (%d), expected palette header", bytesLeft);
+ debugC(kDebugLevelResMan, "GfxPalette::createFromData() - not enough bytes in resource (%lu), expected palette header", data.size());
return;
}
// palette formats in here are not really version exclusive, we can not use sci-version to differentiate between them
// they were just called that way, because they started appearing in sci1.1 for example
- if ((data[0] == 0 && data[1] == 1) || (data[0] == 0 && data[1] == 0 && READ_SCI11ENDIAN_UINT16(data + 29) == 0)) {
+ if ((data[0] == 0 && data[1] == 1) || (data[0] == 0 && data[1] == 0 && data.getUint16SEAt(29) == 0)) {
// SCI0/SCI1 palette
palFormat = SCI_PAL_FORMAT_VARIABLE; // CONSTANT;
palOffset = 260;
@@ -168,13 +168,13 @@ void GfxPalette::createFromData(byte *data, int bytesLeft, Palette *paletteOut)
palFormat = data[32];
palOffset = 37;
palColorStart = data[25];
- palColorCount = READ_SCI11ENDIAN_UINT16(data + 29);
+ palColorCount = data.getUint16SEAt(29);
}
switch (palFormat) {
case SCI_PAL_FORMAT_CONSTANT:
// Check, if enough bytes left
- if (bytesLeft < palOffset + (3 * palColorCount)) {
+ if (data.size() < palOffset + (3 * palColorCount)) {
warning("GfxPalette::createFromData() - not enough bytes in resource, expected palette colors");
return;
}
@@ -187,7 +187,7 @@ void GfxPalette::createFromData(byte *data, int bytesLeft, Palette *paletteOut)
}
break;
case SCI_PAL_FORMAT_VARIABLE:
- if (bytesLeft < palOffset + (4 * palColorCount)) {
+ if (data.size() < palOffset + (4 * palColorCount)) {
warning("GfxPalette::createFromData() - not enough bytes in resource, expected palette colors");
return;
}
@@ -237,7 +237,7 @@ bool GfxPalette::setAmiga() {
}
// Called from picture class, some amiga sci1 games set half of the palette
-void GfxPalette::modifyAmigaPalette(byte *data) {
+void GfxPalette::modifyAmigaPalette(const SciSpan<const byte> &data) {
int16 curPos = 0;
for (int curColor = 0; curColor < 16; curColor++) {
@@ -525,7 +525,7 @@ bool GfxPalette::kernelSetFromResource(GuiResourceId resourceId, bool force) {
Palette palette;
if (palResource) {
- createFromData(palResource->data, palResource->size, &palette);
+ createFromData(*palResource, &palette);
set(&palette, force);
return true;
}
@@ -723,7 +723,7 @@ bool GfxPalette::palVaryLoadTargetPalette(GuiResourceId resourceId) {
Resource *palResource = _resMan->findResource(ResourceId(kResourceTypePalette, resourceId), false);
if (palResource) {
// Load and initialize destination palette
- createFromData(palResource->data, palResource->size, &_palVaryTargetPalette);
+ createFromData(*palResource, &_palVaryTargetPalette);
return true;
}
return false;
@@ -810,7 +810,7 @@ int16 GfxPalette::kernelPalVaryChangeTarget(GuiResourceId resourceId) {
Resource *palResource = _resMan->findResource(ResourceId(kResourceTypePalette, resourceId), false);
if (palResource) {
Palette insertPalette;
- createFromData(palResource->data, palResource->size, &insertPalette);
+ createFromData(*palResource, &insertPalette);
// insert new palette into target
insert(&insertPalette, &_palVaryTargetPalette);
// update palette and set on screen
diff --git a/engines/sci/graphics/palette.h b/engines/sci/graphics/palette.h
index 2178de8a91..af74169976 100644
--- a/engines/sci/graphics/palette.h
+++ b/engines/sci/graphics/palette.h
@@ -25,6 +25,7 @@
#include "common/array.h"
#include "sci/graphics/helpers.h"
+#include "sci/util.h"
namespace Sci {
@@ -47,9 +48,9 @@ public:
bool isUsing16bitColorMatch();
void setDefault();
- void createFromData(byte *data, int bytesLeft, Palette *paletteOut) const;
+ void createFromData(const SciSpan<const byte> &data, Palette *paletteOut) const;
bool setAmiga();
- void modifyAmigaPalette(byte *data);
+ void modifyAmigaPalette(const SciSpan<const byte> &data);
void setEGA();
void set(Palette *sciPal, bool force, bool forceRealMerge = false);
bool insert(Palette *newPalette, Palette *destPalette);
diff --git a/engines/sci/graphics/palette32.cpp b/engines/sci/graphics/palette32.cpp
index 56e1940224..febb6820d0 100644
--- a/engines/sci/graphics/palette32.cpp
+++ b/engines/sci/graphics/palette32.cpp
@@ -37,15 +37,15 @@ namespace Sci {
#pragma mark HunkPalette
-HunkPalette::HunkPalette(byte *rawPalette) :
+HunkPalette::HunkPalette(const SciSpan<const byte> &rawPalette) :
_version(0),
// NOTE: The header size in palettes is garbage. In at least KQ7 2.00b and
// Phant1, the 999.pal sets this value to 0. In most other palettes it is
// set to 14, but the *actual* size of the header structure used in SSCI is
// 13, which is reflected by `kHunkPaletteHeaderSize`.
// _headerSize(rawPalette[0]),
- _numPalettes(rawPalette[10]),
- _data(nullptr) {
+ _numPalettes(rawPalette.getUint8At(10)),
+ _data() {
assert(_numPalettes == 0 || _numPalettes == 1);
if (_numPalettes) {
_data = rawPalette;
@@ -54,7 +54,7 @@ HunkPalette::HunkPalette(byte *rawPalette) :
}
void HunkPalette::setVersion(const uint32 version) const {
- if (_numPalettes != _data[10]) {
+ if (_numPalettes != _data.getUint8At(10)) {
error("Invalid HunkPalette");
}
@@ -64,20 +64,21 @@ void HunkPalette::setVersion(const uint32 version) const {
error("Invalid HunkPalette");
}
- WRITE_SCI11ENDIAN_UINT32(getPalPointer() + kEntryVersionOffset, version);
+ byte *palette = const_cast<byte *>(getPalPointer().getUnsafeDataAt(kEntryVersionOffset, sizeof(uint32)));
+ WRITE_SCI11ENDIAN_UINT32(palette, version);
_version = version;
}
}
const HunkPalette::EntryHeader HunkPalette::getEntryHeader() const {
- const byte *const data = getPalPointer();
+ const SciSpan<const byte> data(getPalPointer());
EntryHeader header;
- header.startColor = data[10];
- header.numColors = READ_SCI11ENDIAN_UINT16(data + 14);
- header.used = data[16];
- header.sharedUsed = data[17];
- header.version = READ_SCI11ENDIAN_UINT32(data + kEntryVersionOffset);
+ header.startColor = data.getUint8At(10);
+ header.numColors = data.getUint16SEAt(14);
+ header.used = data.getUint8At(16);
+ header.sharedUsed = data.getUint8At(17);
+ header.version = data.getUint32SEAt(kEntryVersionOffset);
return header;
}
@@ -94,7 +95,8 @@ const Palette HunkPalette::toPalette() const {
if (_numPalettes) {
const EntryHeader header = getEntryHeader();
- const byte *data = getPalPointer() + kEntryHeaderSize;
+ const uint32 dataSize = header.numColors * (/* RGB */ 3 + (header.sharedUsed ? 0 : 1));
+ const byte *data = getPalPointer().getUnsafeDataAt(kEntryHeaderSize, dataSize);
const int16 end = header.startColor + header.numColors;
assert(end <= 256);
@@ -169,7 +171,7 @@ bool GfxPalette32::loadPalette(const GuiResourceId resourceId) {
return false;
}
- const HunkPalette palette(palResource->data);
+ const HunkPalette palette(*palResource);
submit(palette);
return true;
}
@@ -296,7 +298,7 @@ Palette GfxPalette32::getPaletteFromResource(const GuiResourceId resourceId) con
error("Could not load vary palette %d", resourceId);
}
- const HunkPalette rawPalette(palResource->data);
+ const HunkPalette rawPalette(*palResource);
return rawPalette.toPalette();
}
diff --git a/engines/sci/graphics/palette32.h b/engines/sci/graphics/palette32.h
index c4cfb35096..d6d7d0dbd1 100644
--- a/engines/sci/graphics/palette32.h
+++ b/engines/sci/graphics/palette32.h
@@ -35,7 +35,7 @@ namespace Sci {
*/
class HunkPalette {
public:
- HunkPalette(byte *rawPalette);
+ HunkPalette(const SciSpan<const byte> &rawPalette);
/**
* Gets the version of the palette. Used to avoid resubmitting a HunkPalette
@@ -118,7 +118,7 @@ private:
/**
* The raw palette data for this hunk palette.
*/
- byte *_data;
+ SciSpan<const byte> _data;
/**
* Returns a struct that describes the palette held by this HunkPalette. The
@@ -129,8 +129,8 @@ private:
/**
* Returns a pointer to the palette data within the hunk palette.
*/
- byte *getPalPointer() const {
- return _data + kHunkPaletteHeaderSize + (2 * _numPalettes);
+ SciSpan<const byte> getPalPointer() const {
+ return _data.subspan(kHunkPaletteHeaderSize + (2 * _numPalettes));
}
};
diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp
index 864327feaa..9e9dede1ae 100644
--- a/engines/sci/graphics/picture.cpp
+++ b/engines/sci/graphics/picture.cpp
@@ -20,6 +20,7 @@
*
*/
+#include "common/span.h"
#include "common/stack.h"
#include "common/system.h"
@@ -68,22 +69,16 @@ void GfxPicture::draw(int16 animationNr, bool mirroredFlag, bool addToFlag, int1
_EGApaletteNo = EGApaletteNo;
_priority = 0;
- headerSize = READ_LE_UINT16(_resource->data);
+ headerSize = _resource->getUint16LEAt(0);
switch (headerSize) {
case 0x26: // SCI 1.1 VGA picture
_resourceType = SCI_PICTURE_TYPE_SCI11;
drawSci11Vga();
break;
-#ifdef ENABLE_SCI32
- case 0x0e: // SCI32 VGA picture
- _resourceType = SCI_PICTURE_TYPE_SCI32;
- drawSci32Vga(0, 0, 0, 0, 0, false);
- break;
-#endif
default:
// VGA, EGA or Amiga vector data
_resourceType = SCI_PICTURE_TYPE_REGULAR;
- drawVectorData(_resource->data, _resource->size);
+ drawVectorData(*_resource);
}
}
@@ -100,16 +95,15 @@ void GfxPicture::reset() {
}
void GfxPicture::drawSci11Vga() {
- byte *inbuffer = _resource->data;
- int size = _resource->size;
+ SciSpan<const byte> inbuffer(*_resource);
int priorityBandsCount = inbuffer[3];
int has_cel = inbuffer[4];
- int vector_dataPos = READ_LE_UINT32(inbuffer + 16);
- int vector_size = size - vector_dataPos;
- int palette_data_ptr = READ_LE_UINT32(inbuffer + 28);
- int cel_headerPos = READ_LE_UINT32(inbuffer + 32);
- int cel_RlePos = READ_LE_UINT32(inbuffer + cel_headerPos + 24);
- int cel_LiteralPos = READ_LE_UINT32(inbuffer + cel_headerPos + 28);
+ int vector_dataPos = inbuffer.getUint32LEAt(16);
+ int vector_size = _resource->size() - vector_dataPos;
+ int palette_data_ptr = inbuffer.getUint32LEAt(28);
+ int cel_headerPos = inbuffer.getUint32LEAt(32);
+ int cel_RlePos = inbuffer.getUint32LEAt(cel_headerPos + 24);
+ int cel_LiteralPos = inbuffer.getUint32LEAt(cel_headerPos + 28);
Palette palette;
// Header
@@ -132,113 +126,24 @@ void GfxPicture::drawSci11Vga() {
// display Cel-data
if (has_cel) {
// Create palette and set it
- _palette->createFromData(inbuffer + palette_data_ptr, size - palette_data_ptr, &palette);
+ _palette->createFromData(inbuffer.subspan(palette_data_ptr), &palette);
_palette->set(&palette, true);
- drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0, 0, 0, false);
+ drawCelData(inbuffer, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0, 0, 0, false);
}
// process vector data
- drawVectorData(inbuffer + vector_dataPos, vector_size);
+ drawVectorData(inbuffer.subspan(vector_dataPos, vector_size));
// Set priority band information
- _ports->priorityBandsInitSci11(inbuffer + 40);
-}
-
-#ifdef ENABLE_SCI32
-int16 GfxPicture::getSci32celCount() {
- byte *inbuffer = _resource->data;
- return inbuffer[2];
-}
-
-int16 GfxPicture::getSci32celX(int16 celNo) {
- byte *inbuffer = _resource->data;
- int header_size = READ_SCI11ENDIAN_UINT16(inbuffer);
- int cel_headerPos = header_size + 42 * celNo;
- return READ_SCI11ENDIAN_UINT16(inbuffer + cel_headerPos + 38);
-}
-
-int16 GfxPicture::getSci32celY(int16 celNo) {
- byte *inbuffer = _resource->data;
- int header_size = READ_SCI11ENDIAN_UINT16(inbuffer);
- int cel_headerPos = header_size + 42 * celNo;
- return READ_SCI11ENDIAN_UINT16(inbuffer + cel_headerPos + 40);
-}
-
-int16 GfxPicture::getSci32celWidth(int16 celNo) {
- byte *inbuffer = _resource->data;
- int header_size = READ_SCI11ENDIAN_UINT16(inbuffer);
- int cel_headerPos = header_size + 42 * celNo;
- return READ_SCI11ENDIAN_UINT16(inbuffer + cel_headerPos + 0);
-}
-
-int16 GfxPicture::getSci32celHeight(int16 celNo) {
- byte *inbuffer = _resource->data;
- int header_size = READ_SCI11ENDIAN_UINT16(inbuffer);
- int cel_headerPos = header_size + 42 * celNo;
- return READ_SCI11ENDIAN_UINT16(inbuffer + cel_headerPos + 2);
-}
-
-
-int16 GfxPicture::getSci32celPriority(int16 celNo) {
- byte *inbuffer = _resource->data;
- int header_size = READ_SCI11ENDIAN_UINT16(inbuffer);
- int cel_headerPos = header_size + 42 * celNo;
- return READ_SCI11ENDIAN_UINT16(inbuffer + cel_headerPos + 36);
-}
-
-void GfxPicture::drawSci32Vga(int16 celNo, int16 drawX, int16 drawY, int16 pictureX, int16 pictureY, bool mirrored) {
- byte *inbuffer = _resource->data;
- int size = _resource->size;
- int header_size = READ_SCI11ENDIAN_UINT16(inbuffer);
- int palette_data_ptr = READ_SCI11ENDIAN_UINT32(inbuffer + 6);
-// int celCount = inbuffer[2];
- int cel_headerPos = header_size;
- int cel_RlePos, cel_LiteralPos;
- Palette palette;
-
- // HACK
- _mirroredFlag = mirrored;
- _addToFlag = false;
- _resourceType = SCI_PICTURE_TYPE_SCI32;
-
- if (celNo == 0) {
- // Create palette and set it
- _palette->createFromData(inbuffer + palette_data_ptr, size - palette_data_ptr, &palette);
- _palette->set(&palette, true);
- }
-
- // Header
- // 0[headerSize:WORD] 2[celCount:BYTE] 3[Unknown:BYTE] 4[celHeaderSize:WORD] 6[paletteOffset:DWORD] 10[Unknown:WORD] 12[Unknown:WORD]
- // cel-header follow afterwards, each is 42 bytes
- // Cel-Header
- // 0[width:WORD] 2[height:WORD] 4[displaceX:WORD] 6[displaceY:WORD] 8[clearColor:BYTE] 9[compressed:BYTE]
- // offset 10-23 is unknown
- // 24[rleOffset:DWORD] 28[literalOffset:DWORD] 32[Unknown:WORD] 34[Unknown:WORD] 36[priority:WORD] 38[relativeXpos:WORD] 40[relativeYpos:WORD]
-
- cel_headerPos += 42 * celNo;
-
- if (mirrored) {
- // switch around relativeXpos
- Common::Rect displayArea = _coordAdjuster->pictureGetDisplayArea();
- drawX = displayArea.width() - drawX - READ_SCI11ENDIAN_UINT16(inbuffer + cel_headerPos + 0);
- }
-
- cel_RlePos = READ_SCI11ENDIAN_UINT32(inbuffer + cel_headerPos + 24);
- cel_LiteralPos = READ_SCI11ENDIAN_UINT32(inbuffer + cel_headerPos + 28);
-
- drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, drawX, drawY, pictureX, pictureY, false);
- cel_headerPos += 42;
+ _ports->priorityBandsInitSci11(inbuffer.subspan(40));
}
-#endif
-extern void unpackCelData(byte *inBuffer, byte *celBitmap, byte clearColor, int pixelCount, int rlePos, int literalPos, ViewType viewType, uint16 width, bool isMacSci11ViewData);
+extern void unpackCelData(const SciSpan<const byte> &inBuffer, SciSpan<byte> &celBitmap, byte clearColor, int rlePos, int literalPos, ViewType viewType, uint16 width, bool isMacSci11ViewData);
-void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 drawX, int16 drawY, int16 pictureX, int16 pictureY, bool isEGA) {
- byte *celBitmap = NULL;
- byte *ptr = NULL;
- byte *headerPtr = inbuffer + headerPos;
- byte *rlePtr = inbuffer + rlePos;
+void GfxPicture::drawCelData(const SciSpan<const byte> &inbuffer, int headerPos, int rlePos, int literalPos, int16 drawX, int16 drawY, int16 pictureX, int16 pictureY, bool isEGA) {
+ const SciSpan<const byte> headerPtr = inbuffer.subspan(headerPos);
+ const SciSpan<const byte> rlePtr = inbuffer.subspan(rlePos);
// displaceX, displaceY fields are ignored, and may contain garbage
// (e.g. pic 261 in Dr. Brain 1 Spanish - bug #3614914)
//int16 displaceX, displaceY;
@@ -254,30 +159,16 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos
if (!isEGA && !_addToFlag)
priority = 0;
-#ifdef ENABLE_SCI32
- if (_resourceType != SCI_PICTURE_TYPE_SCI32) {
-#endif
- // Width/height here are always LE, even in Mac versions
- width = READ_LE_UINT16(headerPtr + 0);
- height = READ_LE_UINT16(headerPtr + 2);
- //displaceX = (signed char)headerPtr[4];
- //displaceY = (unsigned char)headerPtr[5];
- if (_resourceType == SCI_PICTURE_TYPE_SCI11)
- // SCI1.1 uses hardcoded clearcolor for pictures, even if cel header specifies otherwise
- clearColor = _screen->getColorWhite();
- else
- clearColor = headerPtr[6];
-#ifdef ENABLE_SCI32
- } else {
- width = READ_SCI11ENDIAN_UINT16(headerPtr + 0);
- height = READ_SCI11ENDIAN_UINT16(headerPtr + 2);
- //displaceX = READ_SCI11ENDIAN_UINT16(headerPtr + 4); // probably signed?!?
- //displaceY = READ_SCI11ENDIAN_UINT16(headerPtr + 6); // probably signed?!?
- clearColor = headerPtr[8];
- if (headerPtr[9] == 0)
- compression = false;
- }
-#endif
+ // Width/height here are always LE, even in Mac versions
+ width = headerPtr.getUint16LEAt(0);
+ height = headerPtr.getUint16LEAt(2);
+ //displaceX = (signed char)headerPtr[4];
+ //displaceY = (unsigned char)headerPtr[5];
+ if (_resourceType == SCI_PICTURE_TYPE_SCI11)
+ // SCI1.1 uses hardcoded clearcolor for pictures, even if cel header specifies otherwise
+ clearColor = _screen->getColorWhite();
+ else
+ clearColor = headerPtr[6];
//if (displaceX || displaceY)
// error("unsupported embedded cel-data in picture");
@@ -285,7 +176,8 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos
// We will unpack cel-data into a temporary buffer and then plot it to screen
// That needs to be done cause a mirrored picture may be requested
pixelCount = width * height;
- celBitmap = new byte[pixelCount];
+ Common::SpanOwner<SciSpan<byte> > celBitmap;
+ celBitmap->allocate(pixelCount, _resource->name());
if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2) {
// See GfxView::unpackCel() for why this black/white swap is done
@@ -296,22 +188,11 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos
clearColor = 0;
}
- if (compression)
- unpackCelData(inbuffer, celBitmap, clearColor, pixelCount, rlePos, literalPos, _resMan->getViewType(), width, false);
- else
+ if (compression) {
+ unpackCelData(inbuffer, *celBitmap, clearColor, rlePos, literalPos, _resMan->getViewType(), width, false);
+ } else
// No compression (some SCI32 pictures)
- memcpy(celBitmap, rlePtr, pixelCount);
-
- if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2) {
- // See GfxView::unpackCel() for why this black/white swap is done
- // This picture swap is only needed in SCI32, not SCI1.1
- for (int i = 0; i < pixelCount; i++) {
- if (celBitmap[i] == 0)
- celBitmap[i] = 0xff;
- else if (celBitmap[i] == 0xff)
- celBitmap[i] = 0;
- }
- }
+ memcpy(celBitmap->getUnsafeDataAt(0, pixelCount), rlePtr.getUnsafeDataAt(0, pixelCount), pixelCount);
Common::Rect displayArea = _coordAdjuster->pictureGetDisplayArea();
@@ -356,13 +237,12 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos
// but white and that won't matter because the screen is supposed to be already white. It seems that most (if not all)
// SCI1.1 games use color 0 as transparency and SCI1 games use color 255 as transparency. Sierra SCI seems to paint
// the whole data to screen and wont skip over transparent pixels. So this will actually make it work like Sierra.
- // SCI32 doesn't use _addToFlag at all.
- if (!_addToFlag && _resourceType != SCI_PICTURE_TYPE_SCI32)
+ if (!_addToFlag)
clearColor = _screen->getColorWhite();
byte drawMask = priority > 15 ? GFX_SCREEN_MASK_VISUAL : GFX_SCREEN_MASK_VISUAL | GFX_SCREEN_MASK_PRIORITY;
- ptr = celBitmap;
+ SciSpan<const byte> ptr = *celBitmap;
ptr += skipCelBitmapPixels;
ptr += skipCelBitmapLines * width;
@@ -440,8 +320,6 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos
}
}
}
-
- delete[] celBitmap;
}
enum {
@@ -549,7 +427,7 @@ static const byte vector_defaultEGApriority[PIC_EGAPRIORITY_SIZE] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
};
-void GfxPicture::drawVectorData(byte *data, int dataSize) {
+void GfxPicture::drawVectorData(const SciSpan<const byte> &data) {
byte pic_op;
byte pic_color = _screen->getColorDefaultVectorData();
byte pic_priority = 255, pic_control = 255;
@@ -558,7 +436,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
byte *EGApalette = &EGApalettes[_EGApaletteNo * PIC_EGAPALETTE_SIZE];
byte EGApriority[PIC_EGAPRIORITY_SIZE] = {0};
bool isEGA = false;
- int curPos = 0;
+ uint curPos = 0;
uint16 size;
byte pixel;
int i;
@@ -591,7 +469,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
}
// Drawing
- while (curPos < dataSize) {
+ while (curPos < data.size()) {
#ifdef DEBUG_PICTURE_DRAW
debug("Picture op: %X (%s) at %d", data[curPos], picOpcodeNames[data[curPos] - 0xF0], curPos);
_screen->copyToScreen();
@@ -774,7 +652,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
break;
case PIC_OPX_EGA_EMBEDDED_VIEW:
vectorGetAbsCoordsNoMirror(data, curPos, x, y);
- size = READ_LE_UINT16(data + curPos); curPos += 2;
+ size = data.getUint16LEAt(curPos); curPos += 2;
// hardcoded in SSCI, 16 for SCI1early excluding Space Quest 4, 0 for anything else
// fixes sq4 pictures 546+547 (Vohaul's head and Roger Jr trapped). Bug #5250
// fixes sq4 picture 631 (SQ1 view from cockpit). Bug 5249
@@ -783,11 +661,11 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
} else {
_priority = 0;
}
- drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y, 0, 0, true);
+ drawCelData(data, curPos, curPos + 8, 0, x, y, 0, 0, true);
curPos += size;
break;
case PIC_OPX_EGA_SET_PRIORITY_TABLE:
- _ports->priorityBandsInit(data + curPos);
+ _ports->priorityBandsInit(data.subspan(curPos, 14));
curPos += 14;
break;
default:
@@ -810,7 +688,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
curPos += 256 + 4 + 1024;
} else {
// Setting half of the Amiga palette
- _palette->modifyAmigaPalette(&data[curPos]);
+ _palette->modifyAmigaPalette(data.subspan(curPos));
curPos += 32;
}
} else {
@@ -824,7 +702,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
break;
case PIC_OPX_VGA_EMBEDDED_VIEW: // draw cel
vectorGetAbsCoordsNoMirror(data, curPos, x, y);
- size = READ_LE_UINT16(data + curPos); curPos += 2;
+ size = data.getUint16LEAt(curPos); curPos += 2;
if (getSciVersion() <= SCI_VERSION_1_EARLY) {
// During SCI1Early sierra always used 0 as priority for cels inside picture resources
// fixes Space Quest 4 orange ship lifting off (bug #6446)
@@ -832,15 +710,15 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
} else {
_priority = pic_priority; // set global priority so the cel gets drawn using current priority as well
}
- drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y, 0, 0, false);
+ drawCelData(data, curPos, curPos + 8, 0, x, y, 0, 0, false);
curPos += size;
break;
case PIC_OPX_VGA_PRIORITY_TABLE_EQDIST:
- _ports->priorityBandsInit(-1, READ_LE_UINT16(data + curPos), READ_LE_UINT16(data + curPos + 2));
+ _ports->priorityBandsInit(-1, data.getUint16LEAt(curPos), data.getUint16LEAt(curPos + 2));
curPos += 4;
break;
case PIC_OPX_VGA_PRIORITY_TABLE_EXPLICIT:
- _ports->priorityBandsInit(data + curPos);
+ _ports->priorityBandsInit(data.subspan(curPos, 14));
curPos += 14;
break;
default:
@@ -886,20 +764,20 @@ bool GfxPicture::vectorIsNonOpcode(byte pixel) {
return true;
}
-void GfxPicture::vectorGetAbsCoords(byte *data, int &curPos, int16 &x, int16 &y) {
+void GfxPicture::vectorGetAbsCoords(const SciSpan<const byte> &data, uint &curPos, int16 &x, int16 &y) {
byte pixel = data[curPos++];
x = data[curPos++] + ((pixel & 0xF0) << 4);
y = data[curPos++] + ((pixel & 0x0F) << 8);
if (_mirroredFlag) x = 319 - x;
}
-void GfxPicture::vectorGetAbsCoordsNoMirror(byte *data, int &curPos, int16 &x, int16 &y) {
+void GfxPicture::vectorGetAbsCoordsNoMirror(const SciSpan<const byte> &data, uint &curPos, int16 &x, int16 &y) {
byte pixel = data[curPos++];
x = data[curPos++] + ((pixel & 0xF0) << 4);
y = data[curPos++] + ((pixel & 0x0F) << 8);
}
-void GfxPicture::vectorGetRelCoords(byte *data, int &curPos, int16 &x, int16 &y) {
+void GfxPicture::vectorGetRelCoords(const SciSpan<const byte> &data, uint &curPos, int16 &x, int16 &y) {
byte pixel = data[curPos++];
if (pixel & 0x80) {
x -= ((pixel >> 4) & 7) * (_mirroredFlag ? -1 : 1);
@@ -913,7 +791,7 @@ void GfxPicture::vectorGetRelCoords(byte *data, int &curPos, int16 &x, int16 &y)
}
}
-void GfxPicture::vectorGetRelCoordsMed(byte *data, int &curPos, int16 &x, int16 &y) {
+void GfxPicture::vectorGetRelCoordsMed(const SciSpan<const byte> &data, uint &curPos, int16 &x, int16 &y) {
byte pixel = data[curPos++];
if (pixel & 0x80) {
y -= (pixel & 0x7F);
@@ -928,7 +806,7 @@ void GfxPicture::vectorGetRelCoordsMed(byte *data, int &curPos, int16 &x, int16
}
}
-void GfxPicture::vectorGetPatternTexture(byte *data, int &curPos, int16 pattern_Code, int16 &pattern_Texture) {
+void GfxPicture::vectorGetPatternTexture(const SciSpan<const byte> &data, uint &curPos, int16 pattern_Code, int16 &pattern_Texture) {
if (pattern_Code & SCI_PATTERN_CODE_USE_TEXTURE) {
pattern_Texture = (data[curPos++] >> 1) & 0x7f;
}
diff --git a/engines/sci/graphics/picture.h b/engines/sci/graphics/picture.h
index 1be1ae3004..48f80323b1 100644
--- a/engines/sci/graphics/picture.h
+++ b/engines/sci/graphics/picture.h
@@ -23,6 +23,8 @@
#ifndef SCI_GRAPHICS_PICTURE_H
#define SCI_GRAPHICS_PICTURE_H
+#include "sci/util.h"
+
namespace Sci {
#define SCI_PATTERN_CODE_RECTANGLE 0x10
@@ -54,28 +56,18 @@ public:
GuiResourceId getResourceId();
void draw(int16 animationNr, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo);
-#ifdef ENABLE_SCI32
- int16 getSci32celCount();
- int16 getSci32celY(int16 celNo);
- int16 getSci32celX(int16 celNo);
- int16 getSci32celWidth(int16 celNo);
- int16 getSci32celHeight(int16 celNo);
- int16 getSci32celPriority(int16 celNo);
- void drawSci32Vga(int16 celNo, int16 callerX, int16 callerY, int16 pictureX, int16 pictureY, bool mirrored);
-#endif
-
private:
void initData(GuiResourceId resourceId);
void reset();
void drawSci11Vga();
- void drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 drawX, int16 drawY, int16 pictureX, int16 pictureY, bool isEGA);
- void drawVectorData(byte *data, int size);
+ void drawCelData(const SciSpan<const byte> &inbuffer, int headerPos, int rlePos, int literalPos, int16 drawX, int16 drawY, int16 pictureX, int16 pictureY, bool isEGA);
+ void drawVectorData(const SciSpan<const byte> &data);
bool vectorIsNonOpcode(byte pixel);
- void vectorGetAbsCoords(byte *data, int &curPos, int16 &x, int16 &y);
- void vectorGetAbsCoordsNoMirror(byte *data, int &curPos, int16 &x, int16 &y);
- void vectorGetRelCoords(byte *data, int &curPos, int16 &x, int16 &y);
- void vectorGetRelCoordsMed(byte *data, int &curPos, int16 &x, int16 &y);
- void vectorGetPatternTexture(byte *data, int &curPos, int16 pattern_Code, int16 &pattern_Texture);
+ void vectorGetAbsCoords(const SciSpan<const byte> &data, uint &curPos, int16 &x, int16 &y);
+ void vectorGetAbsCoordsNoMirror(const SciSpan<const byte> &data, uint &curPos, int16 &x, int16 &y);
+ void vectorGetRelCoords(const SciSpan<const byte> &data, uint &curPos, int16 &x, int16 &y);
+ void vectorGetRelCoordsMed(const SciSpan<const byte> &data, uint &curPos, int16 &x, int16 &y);
+ void vectorGetPatternTexture(const SciSpan<const byte> &data, uint &curPos, int16 pattern_Code, int16 &pattern_Texture);
void vectorFloodFill(int16 x, int16 y, byte color, byte prio, byte control);
void vectorPattern(int16 x, int16 y, byte pic_color, byte pic_priority, byte pic_control, byte code, byte texture);
void vectorPatternBox(Common::Rect box, byte color, byte prio, byte control);
diff --git a/engines/sci/graphics/portrait.cpp b/engines/sci/graphics/portrait.cpp
index 045a923569..675883e6d3 100644
--- a/engines/sci/graphics/portrait.cpp
+++ b/engines/sci/graphics/portrait.cpp
@@ -39,12 +39,6 @@ Portrait::Portrait(ResourceManager *resMan, EventManager *event, GfxScreen *scre
init();
}
-Portrait::~Portrait() {
- delete[] _lipSyncDataOffsetTable;
- delete[] _bitmaps;
- delete[] _fileData;
-}
-
void Portrait::init() {
// .BIN files are loaded from actors directory and from .\ directory
// header:
@@ -90,31 +84,28 @@ void Portrait::init() {
// 4 bytes appended, seem to be random
// 9E11120E for alex
// 9E9E9E9E for vizier
- int32 fileSize = 0;
- Common::SeekableReadStream *file =
- SearchMan.createReadStreamForMember("actors/" + _resourceName + ".bin");
+ Common::String fileName = "actors/" + _resourceName + ".bin";
+ Common::SeekableReadStream *file = SearchMan.createReadStreamForMember(fileName);
+ ;
if (!file) {
- file = SearchMan.createReadStreamForMember(_resourceName + ".bin");
+ fileName = _resourceName + ".bin";
+ file = SearchMan.createReadStreamForMember(fileName);
if (!file)
error("portrait %s.bin not found", _resourceName.c_str());
}
- fileSize = file->size();
- _fileData = new byte[fileSize];
- file->read(_fileData, fileSize);
+ _fileData->allocateFromStream(*file, Common::kSpanMaxSize, fileName);
delete file;
- if (strncmp((char *)_fileData, "WIN", 3)) {
+ if (strncmp((const char *)_fileData->getUnsafeDataAt(0, 3), "WIN", 3)) {
error("portrait %s doesn't have valid header", _resourceName.c_str());
}
- _width = READ_LE_UINT16(_fileData + 3);
- _height = READ_LE_UINT16(_fileData + 5);
- _bitmapCount = READ_LE_UINT16(_fileData + 7);
- _lipSyncIDCount = READ_LE_UINT16(_fileData + 11);
-
- _bitmaps = new PortraitBitmap[_bitmapCount];
+ _width = _fileData->getUint16LEAt(3);
+ _height = _fileData->getUint16LEAt(5);
+ _bitmaps.resize(_fileData->getUint16LEAt(7));
+ _lipSyncIDCount = _fileData->getUint16LEAt(11);
- uint16 portraitPaletteSize = READ_LE_UINT16(_fileData + 13);
- byte *data = _fileData + 17;
+ uint16 portraitPaletteSize = _fileData->getUint16LEAt(13);
+ SciSpan<const byte> data = _fileData->subspan(17);
// Read palette
memset(&_portraitPalette, 0, sizeof(Palette));
uint16 palSize = 0, palNr = 0;
@@ -128,42 +119,40 @@ void Portrait::init() {
}
// Read all bitmaps
- PortraitBitmap *curBitmap = _bitmaps;
uint16 bitmapNr;
uint16 bytesPerLine;
- for (bitmapNr = 0; bitmapNr < _bitmapCount; bitmapNr++) {
- curBitmap->width = READ_LE_UINT16(data + 2);
- curBitmap->height = READ_LE_UINT16(data + 4);
- bytesPerLine = READ_LE_UINT16(data + 6);
- if (bytesPerLine < curBitmap->width)
+ for (bitmapNr = 0; bitmapNr < _bitmaps.size(); bitmapNr++) {
+ PortraitBitmap &curBitmap = _bitmaps[bitmapNr];
+ curBitmap.width = data.getUint16LEAt(2);
+ curBitmap.height = data.getUint16LEAt(4);
+ bytesPerLine = data.getUint16LEAt(6);
+ if (bytesPerLine < curBitmap.width)
error("kPortrait: bytesPerLine larger than actual width");
- curBitmap->extraBytesPerLine = bytesPerLine - curBitmap->width;
- curBitmap->rawBitmap = data + 14;
- data += 14 + (curBitmap->height * bytesPerLine);
- curBitmap++;
+ curBitmap.extraBytesPerLine = bytesPerLine - curBitmap.width;
+ curBitmap.rawBitmap = data.subspan(14, curBitmap.width * curBitmap.height);
+ data += 14 + (curBitmap.height * bytesPerLine);
}
// Offset table follows
- curBitmap = _bitmaps;
- int32 offsetTableSize = READ_LE_UINT32(data);
- assert((bitmapNr + 1) * 14 <= offsetTableSize);
+ uint32 offsetTableSize = data.getUint32LEAt(0);
+ assert((bitmapNr + 1U) * 14U <= offsetTableSize);
data += 4;
- byte *dataOffsetTable = data + 14; // we skip first bitmap offsets
- for (bitmapNr = 0; bitmapNr < _bitmapCount; bitmapNr++) {
- curBitmap->displaceX = READ_LE_UINT16(dataOffsetTable);
- curBitmap->displaceY = READ_LE_UINT16(dataOffsetTable + 2);
+ SciSpan<const byte> dataOffsetTable = data.subspan(14); // we skip first bitmap offsets
+ for (bitmapNr = 0; bitmapNr < _bitmaps.size(); bitmapNr++) {
+ PortraitBitmap &curBitmap = _bitmaps[bitmapNr];
+ curBitmap.displaceX = dataOffsetTable.getUint16LEAt(0);
+ curBitmap.displaceY = dataOffsetTable.getUint16LEAt(2);
dataOffsetTable += 14;
- curBitmap++;
}
data += offsetTableSize;
// raw lip-sync ID table follows
uint32 lipSyncIDTableSize;
- lipSyncIDTableSize = READ_LE_UINT32(data);
+ lipSyncIDTableSize = data.getUint32LEAt(0);
data += 4;
- assert( lipSyncIDTableSize == (_lipSyncIDCount * 4) );
+ assert(lipSyncIDTableSize == _lipSyncIDCount * 4);
_lipSyncIDTable = data;
data += lipSyncIDTableSize;
@@ -174,23 +163,23 @@ void Portrait::init() {
uint16 lipSyncDataNr;
uint16 lipSyncCurOffset;
- lipSyncDataTableSize = READ_LE_UINT32(data);
+ lipSyncDataTableSize = data.getUint32LEAt(0);
data += 4;
- assert( lipSyncDataTableSize == 0x220 ); // always this size, just a safety-check
+ assert(lipSyncDataTableSize == 0x220); // always this size, just a safety-check
_lipSyncData = data;
lipSyncDataTableLastOffset = lipSyncDataTableSize - 1;
- _lipSyncDataOffsetTable = new uint16[ _lipSyncIDCount ];
+ _lipSyncDataOffsetTable.resize(_lipSyncIDCount);
lipSyncDataNr = 0;
lipSyncCurOffset = 0;
- while ( (lipSyncCurOffset < lipSyncDataTableSize) && (lipSyncDataNr < _lipSyncIDCount) ) {
+ while (lipSyncCurOffset < lipSyncDataTableSize && lipSyncDataNr < _lipSyncIDCount) {
// We are currently at the start of ID-frame data
_lipSyncDataOffsetTable[lipSyncDataNr] = lipSyncCurOffset;
// Look for end of ID-frame data
lipSyncData = *data++; lipSyncCurOffset++;
- while ( (lipSyncData != 0xFF) && (lipSyncCurOffset < lipSyncDataTableLastOffset) ) {
+ while (lipSyncData != 0xFF && lipSyncCurOffset < lipSyncDataTableLastOffset) {
// Either terminator (0xFF) or frame-data (1 byte tick count and 1 byte bitmap ID)
data++;
lipSyncData = *data++;
@@ -198,7 +187,6 @@ void Portrait::init() {
}
lipSyncDataNr++;
}
- _lipSyncDataOffsetTableEnd = data;
// last 4 bytes seem to be garbage
}
@@ -277,7 +265,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
// Do animation depending on rave resource till audio is done playing
int16 raveTicks;
uint16 raveID;
- byte *raveLipSyncData;
+ SciSpan<const byte> raveLipSyncData;
byte raveLipSyncTicks;
byte raveLipSyncBitmapNr;
int timerPosition = 0;
@@ -286,7 +274,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
SciEvent curEvent;
bool userAbort = false;
- while ((raveOffset < raveResource->size) && (!userAbort)) {
+ while (raveOffset < raveResource->size() && !userAbort) {
// rave string starts with tick count, followed by lipSyncID, tick count and so on
raveTicks = raveGetTicks(raveResource, &raveOffset);
if (raveTicks < 0)
@@ -297,7 +285,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
if (raveID) {
raveLipSyncData = raveGetLipSyncData(raveID);
} else {
- raveLipSyncData = NULL;
+ raveLipSyncData = SciSpan<const byte>();
}
#ifdef DEBUG_PORTRAIT
@@ -330,7 +318,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
// Tick = 0xFF is the terminator for the data
timerPositionWithin = timerPosition;
raveLipSyncTicks = *raveLipSyncData++;
- while ( (raveLipSyncData < _lipSyncDataOffsetTableEnd) && (raveLipSyncTicks != 0xFF) ) {
+ while (raveLipSyncData.size() && raveLipSyncTicks != 0xFF) {
if (raveLipSyncTicks)
raveLipSyncTicks--; // 1 -> wait 0 ticks, 2 -> wait 1 tick, etc.
timerPositionWithin += raveLipSyncTicks;
@@ -357,7 +345,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
// bitmap nr within sync data is base 1, we need base 0
raveLipSyncBitmapNr--;
- if (raveLipSyncBitmapNr < _bitmapCount) {
+ if (raveLipSyncBitmapNr < _bitmaps.size()) {
drawBitmap(0);
drawBitmap(raveLipSyncBitmapNr);
bitsShow();
@@ -435,14 +423,14 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
// returns ASCII ticks from lip sync string as uint16
int16 Portrait::raveGetTicks(Resource *resource, uint *offset) {
uint curOffset = *offset;
- byte *curData = resource->data + curOffset;
+ SciSpan<const byte> curData = resource->subspan(curOffset);
byte curByte;
uint16 curValue = 0;
- if (curOffset >= resource->size)
+ if (curOffset >= resource->size())
return -1;
- while (curOffset < resource->size) {
+ while (curOffset < resource->size()) {
curByte = *curData++; curOffset++;
if ( curByte == ' ' )
break;
@@ -460,11 +448,11 @@ int16 Portrait::raveGetTicks(Resource *resource, uint *offset) {
// returns ASCII ID from lip sync string as uint16
uint16 Portrait::raveGetID(Resource *resource, uint *offset) {
uint curOffset = *offset;
- byte *curData = resource->data + curOffset;
+ SciSpan<const byte> curData = resource->subspan(curOffset);
byte curByte = 0;
uint16 curValue = 0;
- while (curOffset < resource->size) {
+ while (curOffset < resource->size()) {
curByte = *curData++; curOffset++;
if ( curByte == ' ' )
break;
@@ -480,9 +468,9 @@ uint16 Portrait::raveGetID(Resource *resource, uint *offset) {
}
// Searches for a specific lip sync ID and returns pointer to lip sync data or NULL in case ID was not found
-byte *Portrait::raveGetLipSyncData(uint16 raveID) {
+SciSpan<const byte> Portrait::raveGetLipSyncData(const uint16 raveID) {
uint lipSyncIDNr = 0;
- byte *lipSyncIDPtr = _lipSyncIDTable;
+ SciSpan<const byte> lipSyncIDPtr = _lipSyncIDTable;
byte lipSyncIDByte1, lipSyncIDByte2;
uint16 lipSyncID;
@@ -490,20 +478,19 @@ byte *Portrait::raveGetLipSyncData(uint16 raveID) {
while (lipSyncIDNr < _lipSyncIDCount) {
lipSyncIDByte1 = *lipSyncIDPtr++;
lipSyncIDByte2 = *lipSyncIDPtr++;
- lipSyncID = ( lipSyncIDByte1 << 8 ) | lipSyncIDByte2;
+ lipSyncID = (lipSyncIDByte1 << 8) | lipSyncIDByte2;
- if ( lipSyncID == raveID ) {
- return _lipSyncData + _lipSyncDataOffsetTable[lipSyncIDNr];
+ if (lipSyncID == raveID) {
+ return _lipSyncData.subspan(_lipSyncDataOffsetTable[lipSyncIDNr]);
}
lipSyncIDNr++;
lipSyncIDPtr += 2; // ID is every 4 bytes
}
- return NULL;
+ return SciSpan<const byte>();
}
void Portrait::drawBitmap(uint16 bitmapNr) {
- byte *data = _bitmaps[bitmapNr].rawBitmap;
uint16 bitmapHeight = _bitmaps[bitmapNr].height;
uint16 bitmapWidth = _bitmaps[bitmapNr].width;
Common::Point bitmapPosition = _position;
@@ -511,6 +498,7 @@ void Portrait::drawBitmap(uint16 bitmapNr) {
bitmapPosition.x += _bitmaps[bitmapNr].displaceX;
bitmapPosition.y += _bitmaps[bitmapNr].displaceY;
+ const byte *data = _bitmaps[bitmapNr].rawBitmap.getUnsafeDataAt(0, bitmapWidth * bitmapHeight);
for (int y = 0; y < bitmapHeight; y++) {
for (int x = 0; x < bitmapWidth; x++) {
_screen->putPixelOnDisplay(bitmapPosition.x + x, bitmapPosition.y + y, _portraitPalette.mapping[*data++]);
diff --git a/engines/sci/graphics/portrait.h b/engines/sci/graphics/portrait.h
index e0888daa86..b6f5a17af7 100644
--- a/engines/sci/graphics/portrait.h
+++ b/engines/sci/graphics/portrait.h
@@ -23,13 +23,15 @@
#ifndef SCI_GRAPHICS_PORTRAITS_H
#define SCI_GRAPHICS_PORTRAITS_H
+#include "sci/util.h"
+
namespace Sci {
struct PortraitBitmap {
int16 width, height;
int16 extraBytesPerLine;
uint16 displaceX, displaceY;
- byte *rawBitmap;
+ SciSpan<const byte> rawBitmap;
};
/**
@@ -40,7 +42,6 @@ struct PortraitBitmap {
class Portrait {
public:
Portrait(ResourceManager *resMan, EventManager *event, GfxScreen *screen, GfxPalette *palette, AudioPlayer *audio, Common::String resourceName);
- ~Portrait();
void setupAudio(uint16 resourceId, uint16 noun, uint16 verb, uint16 cond, uint16 seq);
void doit(Common::Point position, uint16 resourceId, uint16 noun, uint16 verb, uint16 cond, uint16 seq);
@@ -54,7 +55,7 @@ private:
int16 raveGetTicks(Resource *resource, uint *offset);
uint16 raveGetID(Resource *resource, uint *offset);
- byte *raveGetLipSyncData(uint16 raveID);
+ SciSpan<const byte> raveGetLipSyncData(const uint16 raveID);
ResourceManager *_resMan;
EventManager *_event;
@@ -66,19 +67,17 @@ private:
uint16 _width;
Palette _portraitPalette;
- uint16 _bitmapCount;
- PortraitBitmap *_bitmaps;
+ Common::Array<PortraitBitmap> _bitmaps;
Common::String _resourceName;
- byte *_fileData;
+ Common::SpanOwner<SciSpan<const byte> > _fileData;
uint32 _lipSyncIDCount;
- byte *_lipSyncIDTable;
+ SciSpan<const byte> _lipSyncIDTable;
- byte *_lipSyncData;
- uint16 *_lipSyncDataOffsetTable;
- byte *_lipSyncDataOffsetTableEnd;
+ SciSpan<const byte> _lipSyncData;
+ Common::Array<uint16> _lipSyncDataOffsetTable;
Common::Point _position;
};
diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp
index 0d00ce01e6..eb66896b53 100644
--- a/engines/sci/graphics/ports.cpp
+++ b/engines/sci/graphics/ports.cpp
@@ -674,13 +674,13 @@ void GfxPorts::priorityBandsInit(int16 bandCount, int16 top, int16 bottom) {
_priorityBottom--;
}
-void GfxPorts::priorityBandsInit(byte *data) {
+void GfxPorts::priorityBandsInit(const SciSpan<const byte> &data) {
int i = 0, inx;
byte priority = 0;
for (inx = 0; inx < 14; inx++) {
- priority = *data++;
- while (i < priority)
+ priority = data[inx];
+ while (i < priority && i < 200)
_priorityBands[i++] = inx;
}
while (i < 200)
@@ -688,13 +688,13 @@ void GfxPorts::priorityBandsInit(byte *data) {
}
// Gets used to read priority bands data from sci1.1 pictures
-void GfxPorts::priorityBandsInitSci11(byte *data) {
+void GfxPorts::priorityBandsInitSci11(SciSpan<const byte> data) {
byte priorityBands[14];
for (int bandNo = 0; bandNo < 14; bandNo++) {
- priorityBands[bandNo] = READ_LE_UINT16(data);
+ priorityBands[bandNo] = data.getUint16LEAt(0);
data += 2;
}
- priorityBandsInit(priorityBands);
+ priorityBandsInit(SciSpan<const byte>(priorityBands, 14));
}
void GfxPorts::kernelInitPriorityBands() {
diff --git a/engines/sci/graphics/ports.h b/engines/sci/graphics/ports.h
index 51aca09f54..cd25645df9 100644
--- a/engines/sci/graphics/ports.h
+++ b/engines/sci/graphics/ports.h
@@ -93,8 +93,8 @@ public:
void clipLine(Common::Point &start, Common::Point &end);
void priorityBandsInit(int16 bandCount, int16 top, int16 bottom);
- void priorityBandsInit(byte *data);
- void priorityBandsInitSci11(byte *data);
+ void priorityBandsInit(const SciSpan<const byte> &data);
+ void priorityBandsInitSci11(SciSpan<const byte> data);
void kernelInitPriorityBands();
void kernelGraphAdjustPriority(int top, int bottom);
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp
index de6df39bb9..e69c432712 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -719,40 +719,41 @@ void GfxScreen::debugShowMap(int mapNo) {
copyToScreen();
}
-void GfxScreen::scale2x(const byte *src, byte *dst, int16 srcWidth, int16 srcHeight, byte bytesPerPixel) {
+void GfxScreen::scale2x(const SciSpan<const byte> &src, SciSpan<byte> &dst, int16 srcWidth, int16 srcHeight, byte bytesPerPixel) {
assert(bytesPerPixel == 1 || bytesPerPixel == 2);
const int newWidth = srcWidth * 2;
const int pitch = newWidth * bytesPerPixel;
- const byte *srcPtr = src;
+ const byte *srcPtr = src.getUnsafeDataAt(0, srcWidth * srcHeight * bytesPerPixel);
+ byte *dstPtr = dst.getUnsafeDataAt(0, srcWidth * srcHeight * bytesPerPixel);
if (bytesPerPixel == 1) {
for (int y = 0; y < srcHeight; y++) {
for (int x = 0; x < srcWidth; x++) {
const byte color = *srcPtr++;
- dst[0] = color;
- dst[1] = color;
- dst[newWidth] = color;
- dst[newWidth + 1] = color;
- dst += 2;
+ dstPtr[0] = color;
+ dstPtr[1] = color;
+ dstPtr[newWidth] = color;
+ dstPtr[newWidth + 1] = color;
+ dstPtr += 2;
}
- dst += newWidth;
+ dstPtr += newWidth;
}
} else if (bytesPerPixel == 2) {
for (int y = 0; y < srcHeight; y++) {
for (int x = 0; x < srcWidth; x++) {
const byte color = *srcPtr++;
const byte color2 = *srcPtr++;
- dst[0] = color;
- dst[1] = color2;
- dst[2] = color;
- dst[3] = color2;
- dst[pitch] = color;
- dst[pitch + 1] = color2;
- dst[pitch + 2] = color;
- dst[pitch + 3] = color2;
- dst += 4;
+ dstPtr[0] = color;
+ dstPtr[1] = color2;
+ dstPtr[2] = color;
+ dstPtr[3] = color2;
+ dstPtr[pitch] = color;
+ dstPtr[pitch + 1] = color2;
+ dstPtr[pitch + 2] = color;
+ dstPtr[pitch + 3] = color2;
+ dstPtr += 4;
}
- dst += pitch;
+ dstPtr += pitch;
}
}
}
diff --git a/engines/sci/graphics/screen.h b/engines/sci/graphics/screen.h
index 63ee4ed09e..46214b71d4 100644
--- a/engines/sci/graphics/screen.h
+++ b/engines/sci/graphics/screen.h
@@ -31,8 +31,10 @@
namespace Sci {
-#define SCI_SCREEN_UPSCALEDMAXHEIGHT 200
-#define SCI_SCREEN_UPSCALEDMAXWIDTH 320
+enum {
+ SCI_SCREEN_UPSCALEDMAXHEIGHT = 200,
+ SCI_SCREEN_UPSCALEDMAXWIDTH = 320
+};
enum GfxScreenUpscaledMode {
GFX_SCREEN_UPSCALED_DISABLED = 0,
@@ -76,11 +78,6 @@ public:
byte getColorWhite() { return _colorWhite; }
byte getColorDefaultVectorData() { return _colorDefaultVectorData; }
-#ifdef ENABLE_SCI32
- byte *getDisplayScreen() { return _displayScreen; }
- byte *getPriorityScreen() { return _priorityScreen; }
-#endif
-
void clearForRestoreGame();
void copyToScreen();
void copyFromScreen(byte *buffer);
@@ -120,7 +117,7 @@ public:
void bitsGetRect(byte *memoryPtr, Common::Rect *destRect);
void bitsRestore(byte *memoryPtr);
- void scale2x(const byte *src, byte *dst, int16 srcWidth, int16 srcHeight, byte bytesPerPixel = 1);
+ void scale2x(const SciSpan<const byte> &src, SciSpan<byte> &dst, int16 srcWidth, int16 srcHeight, byte bytesPerPixel = 1);
void adjustToUpscaledCoordinates(int16 &y, int16 &x, Sci32ViewNativeResolution viewScalingType = SCI_VIEW_NATIVERES_NONE);
void adjustBackUpscaledCoordinates(int16 &y, int16 &x, Sci32ViewNativeResolution viewScalingType = SCI_VIEW_NATIVERES_NONE);
diff --git a/engines/sci/graphics/screen_item32.cpp b/engines/sci/graphics/screen_item32.cpp
index c07e07538e..77ff9a3d75 100644
--- a/engines/sci/graphics/screen_item32.cpp
+++ b/engines/sci/graphics/screen_item32.cpp
@@ -183,9 +183,9 @@ void ScreenItem::setFromObject(SegManager *segMan, const reg_t object, const boo
// NOTE: +2 because the header size field itself is excluded from
// the header size in the data
- const uint16 headerSize = READ_SCI11ENDIAN_UINT16(view->data) + 2;
- const uint8 loopCount = view->data[2];
- const uint8 loopSize = view->data[12];
+ const uint16 headerSize = view->getUint16SEAt(0) + 2;
+ const uint8 loopCount = view->getUint8At(2);
+ const uint8 loopSize = view->getUint8At(12);
// loopNo is set to be an unsigned integer in SSCI, so if it's a
// negative value, it'll be fixed accordingly
@@ -195,10 +195,10 @@ void ScreenItem::setFromObject(SegManager *segMan, const reg_t object, const boo
writeSelectorValue(segMan, object, SELECTOR(loop), maxLoopNo);
}
- byte *loopData = view->data + headerSize + (_celInfo.loopNo * loopSize);
+ SciSpan<const byte> loopData = view->subspan(headerSize + (_celInfo.loopNo * loopSize));
const int8 seekEntry = loopData[0];
if (seekEntry != -1) {
- loopData = view->data + headerSize + (seekEntry * loopSize);
+ loopData = view->subspan(headerSize + (seekEntry * loopSize));
}
// celNo is set to be an unsigned integer in SSCI, so if it's a
diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp
index 0c09fcbb30..2dc7775345 100644
--- a/engines/sci/graphics/view.cpp
+++ b/engines/sci/graphics/view.cpp
@@ -21,7 +21,6 @@
*/
#include "sci/sci.h"
-#include "sci/util.h"
#include "sci/engine/state.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/palette.h"
@@ -39,16 +38,7 @@ GfxView::GfxView(ResourceManager *resMan, GfxScreen *screen, GfxPalette *palette
}
GfxView::~GfxView() {
- // Iterate through the loops
- for (uint16 loopNum = 0; loopNum < _loopCount; loopNum++) {
- // and through the cells of each loop
- for (uint16 celNum = 0; celNum < _loop[loopNum].celCount; celNum++) {
- delete[] _loop[loopNum].cel[celNum].rawBitmap;
- }
- delete[] _loop[loopNum].cel;
- }
- delete[] _loop;
-
+ _loop.clear();
_resMan->unlockResource(_resource);
}
@@ -111,10 +101,8 @@ void GfxView::initData(GuiResourceId resourceId) {
if (!_resource) {
error("view resource %d not found", resourceId);
}
- _resourceData = _resource->data;
- _resourceSize = _resource->size;
- byte *celData, *loopData;
+ SciSpan<const byte> celData, loopData;
uint16 celOffset;
CelInfo *cel;
uint16 celCount = 0;
@@ -130,7 +118,7 @@ void GfxView::initData(GuiResourceId resourceId) {
_loopCount = 0;
_embeddedPal = false;
- _EGAmapping = NULL;
+ _EGAmapping.clear();
_sci2ScaleRes = SCI_VIEW_NATIVERES_NONE;
_isScaleable = true;
@@ -143,11 +131,10 @@ void GfxView::initData(GuiResourceId resourceId) {
// make them look better (like removing dithered colors that aren't caught
// by our undithering or even improve the graphics overall).
if (curViewType == kViewEga) {
- if (_resourceData[1] == 0x80) {
+ if (_resource->getUint8At(1) == 0x80) {
curViewType = kViewVga;
- } else {
- if (READ_LE_UINT16(_resourceData + 4) == 1)
- curViewType = kViewVga11;
+ } else if (_resource->getUint16LEAt(4) == 1) {
+ curViewType = kViewVga11;
}
}
@@ -159,12 +146,12 @@ void GfxView::initData(GuiResourceId resourceId) {
case kViewVga: // View-format SCI1
// LoopCount:WORD MirrorMask:WORD Version:WORD PaletteOffset:WORD LoopOffset0:WORD LoopOffset1:WORD...
- _loopCount = _resourceData[0];
+ _loopCount = _resource->getUint8At(0);
// bit 0x8000 of _resourceData[1] means palette is set
- if (_resourceData[1] & 0x40)
+ if (_resource->getUint8At(1) & 0x40)
isCompressed = false;
- mirrorBits = READ_LE_UINT16(_resourceData + 2);
- palOffset = READ_LE_UINT16(_resourceData + 6);
+ mirrorBits = _resource->getUint16LEAt(2);
+ palOffset = _resource->getUint16LEAt(6);
if (palOffset && palOffset != 0x100) {
// Some SCI0/SCI01 games also have an offset set. It seems that it
@@ -174,7 +161,7 @@ void GfxView::initData(GuiResourceId resourceId) {
// have this pointing to a 8x16 byte mapping table that needs to get
// applied then.
if (!isEGA) {
- _palette->createFromData(&_resourceData[palOffset], _resourceSize - palOffset, &_viewPalette);
+ _palette->createFromData(_resource->subspan(palOffset), &_viewPalette);
_embeddedPal = true;
} else {
// Only use the EGA-mapping, when being SCI1 EGA
@@ -182,44 +169,43 @@ void GfxView::initData(GuiResourceId resourceId) {
// with broken mapping tables. I guess those games won't use the mapping, so I rather disable it
// for them
if (getSciVersion() == SCI_VERSION_1_EGA_ONLY) {
- _EGAmapping = &_resourceData[palOffset];
for (EGAmapNr = 0; EGAmapNr < SCI_VIEW_EGAMAPPING_COUNT; EGAmapNr++) {
- if (memcmp(_EGAmapping, EGAmappingStraight, SCI_VIEW_EGAMAPPING_SIZE) != 0)
+ const SciSpan<const byte> mapping = _resource->subspan(palOffset + EGAmapNr * SCI_VIEW_EGAMAPPING_SIZE, SCI_VIEW_EGAMAPPING_SIZE);
+ if (memcmp(mapping.getUnsafeDataAt(0, SCI_VIEW_EGAMAPPING_SIZE), EGAmappingStraight, SCI_VIEW_EGAMAPPING_SIZE) != 0)
break;
- _EGAmapping += SCI_VIEW_EGAMAPPING_SIZE;
}
// If all mappings are "straight", then we actually ignore the mapping
if (EGAmapNr == SCI_VIEW_EGAMAPPING_COUNT)
- _EGAmapping = NULL;
+ _EGAmapping.clear();
else
- _EGAmapping = &_resourceData[palOffset];
+ _EGAmapping = _resource->subspan(palOffset, SCI_VIEW_EGAMAPPING_COUNT * SCI_VIEW_EGAMAPPING_SIZE);
}
}
}
- _loop = new LoopInfo[_loopCount];
+ _loop.resize(_loopCount);
for (loopNo = 0; loopNo < _loopCount; loopNo++) {
- loopData = _resourceData + READ_LE_UINT16(_resourceData + 8 + loopNo * 2);
+ loopData = _resource->subspan(_resource->getUint16LEAt(8 + loopNo * 2));
// CelCount:WORD Unknown:WORD CelOffset0:WORD CelOffset1:WORD...
- celCount = READ_LE_UINT16(loopData);
+ celCount = loopData.getUint16LEAt(0);
_loop[loopNo].celCount = celCount;
_loop[loopNo].mirrorFlag = mirrorBits & 1 ? true : false;
mirrorBits >>= 1;
// read cel info
- _loop[loopNo].cel = new CelInfo[celCount];
+ _loop[loopNo].cel.resize(celCount);
for (celNo = 0; celNo < celCount; celNo++) {
- celOffset = READ_LE_UINT16(loopData + 4 + celNo * 2);
- celData = _resourceData + celOffset;
+ celOffset = loopData.getUint16LEAt(4 + celNo * 2);
+ celData = _resource->subspan(celOffset);
// For VGA
// Width:WORD Height:WORD DisplaceX:BYTE DisplaceY:BYTE ClearKey:BYTE Unknown:BYTE RLEData starts now directly
// For EGA
// Width:WORD Height:WORD DisplaceX:BYTE DisplaceY:BYTE ClearKey:BYTE EGAData starts now directly
cel = &_loop[loopNo].cel[celNo];
- cel->scriptWidth = cel->width = READ_LE_UINT16(celData);
- cel->scriptHeight = cel->height = READ_LE_UINT16(celData + 2);
+ cel->scriptWidth = cel->width = celData.getUint16LEAt(0);
+ cel->scriptHeight = cel->height = celData.getUint16LEAt(2);
cel->displaceX = (signed char)celData[4];
cel->displaceY = celData[5];
cel->clearKey = celData[6];
@@ -251,7 +237,7 @@ void GfxView::initData(GuiResourceId resourceId) {
cel->offsetLiteral = celOffset + 8;
}
}
- cel->rawBitmap = 0;
+ cel->rawBitmap.clear();
if (_loop[loopNo].mirrorFlag)
cel->displaceX = -cel->displaceX;
}
@@ -260,15 +246,15 @@ void GfxView::initData(GuiResourceId resourceId) {
case kViewVga11: // View-format SCI1.1+
// HeaderSize:WORD LoopCount:BYTE Flags:BYTE Version:WORD Unknown:WORD PaletteOffset:WORD
- headerSize = READ_SCI11ENDIAN_UINT16(_resourceData + 0) + 2; // headerSize is not part of the header, so it's added
+ headerSize = _resource->getUint16SEAt(0) + 2; // headerSize is not part of the header, so it's added
assert(headerSize >= 16);
- _loopCount = _resourceData[2];
+ _loopCount = _resource->getUint8At(2);
assert(_loopCount);
- palOffset = READ_SCI11ENDIAN_UINT32(_resourceData + 8);
+ palOffset = _resource->getUint32SEAt(8);
// For SCI32, this is a scale flag
if (getSciVersion() >= SCI_VERSION_2) {
- _sci2ScaleRes = (Sci32ViewNativeResolution)_resourceData[5];
+ _sci2ScaleRes = (Sci32ViewNativeResolution)_resource->getUint8At(5);
if (_screen->getUpscaledHires() == GFX_SCREEN_UPSCALED_DISABLED)
_sci2ScaleRes = SCI_VIEW_NATIVERES_NONE;
}
@@ -279,7 +265,7 @@ void GfxView::initData(GuiResourceId resourceId) {
// we assume that if flags is 0h the view does not support flags and default to scaleable
// if it's 1h then we assume that the view is not to be scaled
// if it's 40h then we assume that the view is scaleable
- switch (_resourceData[3]) {
+ switch (_resource->getUint8At(3)) {
case 1:
_isScaleable = false;
break;
@@ -288,31 +274,31 @@ void GfxView::initData(GuiResourceId resourceId) {
case 0:
break; // don't do anything, we already have _isScaleable set
default:
- error("unsupported flags byte (%d) inside sci1.1 view", _resourceData[3]);
+ error("unsupported flags byte (%d) inside sci1.1 view", _resource->getUint8At(3));
break;
}
- loopData = _resourceData + headerSize;
- loopSize = _resourceData[12];
+ loopData = _resource->subspan(headerSize);
+ loopSize = _resource->getUint8At(12);
assert(loopSize >= 16);
- celSize = _resourceData[13];
+ celSize = _resource->getUint8At(13);
assert(celSize >= 32);
if (palOffset) {
- _palette->createFromData(&_resourceData[palOffset], _resourceSize - palOffset, &_viewPalette);
+ _palette->createFromData(_resource->subspan(palOffset), &_viewPalette);
_embeddedPal = true;
}
- _loop = new LoopInfo[_loopCount];
+ _loop.resize(_loopCount);
for (loopNo = 0; loopNo < _loopCount; loopNo++) {
- loopData = _resourceData + headerSize + (loopNo * loopSize);
+ loopData = _resource->subspan(headerSize + (loopNo * loopSize));
seekEntry = loopData[0];
if (seekEntry != 255) {
if (seekEntry >= _loopCount)
error("Bad loop-pointer in sci 1.1 view");
_loop[loopNo].mirrorFlag = true;
- loopData = _resourceData + headerSize + (seekEntry * loopSize);
+ loopData = _resource->subspan(headerSize + (seekEntry * loopSize));
} else {
_loop[loopNo].mirrorFlag = false;
}
@@ -320,16 +306,18 @@ void GfxView::initData(GuiResourceId resourceId) {
celCount = loopData[2];
_loop[loopNo].celCount = celCount;
- celData = _resourceData + READ_SCI11ENDIAN_UINT32(loopData + 12);
+ const uint32 celDataOffset = loopData.getUint32SEAt(12);
// read cel info
- _loop[loopNo].cel = new CelInfo[celCount];
+ _loop[loopNo].cel.resize(celCount);
for (celNo = 0; celNo < celCount; celNo++) {
+ celData = _resource->subspan(celDataOffset + celNo * celSize, celSize);
+
cel = &_loop[loopNo].cel[celNo];
- cel->scriptWidth = cel->width = READ_SCI11ENDIAN_UINT16(celData);
- cel->scriptHeight = cel->height = READ_SCI11ENDIAN_UINT16(celData + 2);
- cel->displaceX = READ_SCI11ENDIAN_UINT16(celData + 4);
- cel->displaceY = READ_SCI11ENDIAN_UINT16(celData + 6);
+ cel->scriptWidth = cel->width = celData.getInt16SEAt(0);
+ cel->scriptHeight = cel->height = celData.getInt16SEAt(2);
+ cel->displaceX = celData.getInt16SEAt(4);
+ cel->displaceY = celData.getInt16SEAt(6);
if (cel->displaceY < 0)
cel->displaceY += 255; // sierra did this adjust in their sci1.1 getCelRect() - not sure about sci32
@@ -337,18 +325,16 @@ void GfxView::initData(GuiResourceId resourceId) {
cel->clearKey = celData[8];
cel->offsetEGA = 0;
- cel->offsetRLE = READ_SCI11ENDIAN_UINT32(celData + 24);
- cel->offsetLiteral = READ_SCI11ENDIAN_UINT32(celData + 28);
+ cel->offsetRLE = celData.getUint32SEAt(24);
+ cel->offsetLiteral = celData.getUint32SEAt(28);
// GK1-hires content is actually uncompressed, we need to swap both so that we process it as such
if ((cel->offsetRLE) && (!cel->offsetLiteral))
SWAP(cel->offsetRLE, cel->offsetLiteral);
- cel->rawBitmap = 0;
+ cel->rawBitmap.clear();
if (_loop[loopNo].mirrorFlag)
cel->displaceX = -cel->displaceX;
-
- celData += celSize;
}
}
break;
@@ -367,20 +353,16 @@ void GfxView::initData(GuiResourceId resourceId) {
// View 995, Loop 13, Cel 2 = "DUAL" (<- our injected view)
if ((g_sci->isCD()) && (resourceId == 995)) {
// security checks
- if (_loopCount >= 14) {
- if ((_loop[13].celCount == 2) && (_loop[13].cel[0].width == 46) && (_loop[13].cel[0].height == 11)) {
- // copy current cels over
- CelInfo *newCels = new CelInfo[3];
- memcpy(newCels, _loop[13].cel, sizeof(CelInfo) * 2);
- delete[] _loop[13].cel;
- _loop[13].celCount++;
- _loop[13].cel = newCels;
- // Duplicate cel 0 to cel 2
- memcpy(&_loop[13].cel[2], &_loop[13].cel[0], sizeof(CelInfo));
- // copy over our data (which is uncompressed bitmap data)
- _loop[13].cel[2].rawBitmap = new byte[sizeof(ViewInject_LauraBow2_Dual)];
- memcpy(_loop[13].cel[2].rawBitmap, ViewInject_LauraBow2_Dual, sizeof(ViewInject_LauraBow2_Dual));
- }
+ if (_loop.size() >= 14 &&
+ _loop[13].cel.size() == 2 &&
+ _loop[13].cel[0].width == 46 &&
+ _loop[13].cel[0].height == 11) {
+
+ _loop[13].cel.resize(3);
+ // Duplicate cel 0 to cel 2
+ _loop[13].cel[2] = _loop[13].cel[0];
+ // use our data (which is uncompressed bitmap data)
+ _loop[13].cel[2].rawBitmap->allocateFromSpan(SciSpan<const byte>(ViewInject_LauraBow2_Dual, sizeof(ViewInject_LauraBow2_Dual)));
}
}
break;
@@ -393,25 +375,18 @@ void GfxView::initData(GuiResourceId resourceId) {
// View 947, Loop 12, Cel 1 = "DUAL" (pressed) (<- our injected view)
if ((g_sci->isCD()) && (resourceId == 947)) {
// security checks
- if (_loopCount == 12) {
- if ((_loop[8].celCount == 2) && (_loop[8].cel[0].width == 50) && (_loop[8].cel[0].height == 15)) {
- // add another loop
- LoopInfo *newLoops = new LoopInfo[_loopCount + 1];
- memcpy(newLoops, _loop, sizeof(LoopInfo) * _loopCount);
- delete[] _loop;
- _loop = newLoops;
- _loopCount++;
- // copy loop 8 to loop 12
- memcpy(&_loop[12], &_loop[8], sizeof(LoopInfo));
- _loop[12].cel = new CelInfo[2];
- // duplicate all cels of loop 8 and into loop 12
- memcpy(_loop[12].cel, _loop[8].cel, sizeof(CelInfo) * _loop[8].celCount);
- // copy over our data (which is uncompressed bitmap data)
- _loop[12].cel[0].rawBitmap = new byte[sizeof(ViewInject_KingsQuest6_Dual1)];
- memcpy(_loop[12].cel[0].rawBitmap, ViewInject_KingsQuest6_Dual1, sizeof(ViewInject_KingsQuest6_Dual1));
- _loop[12].cel[1].rawBitmap = new byte[sizeof(ViewInject_KingsQuest6_Dual2)];
- memcpy(_loop[12].cel[1].rawBitmap, ViewInject_KingsQuest6_Dual2, sizeof(ViewInject_KingsQuest6_Dual2));
- }
+ if (_loop.size() == 12 &&
+ _loop[8].cel.size() == 2 &&
+ _loop[8].cel[0].width == 50 &&
+ _loop[8].cel[0].height == 15) {
+
+ // add another loop
+ _loop.resize(_loop.size() + 1);
+ // copy loop 8 to loop 12
+ _loop[12] = _loop[8];
+ // use our data (which is uncompressed bitmap data)
+ _loop[12].cel[0].rawBitmap->allocateFromSpan(SciSpan<const byte>(ViewInject_KingsQuest6_Dual1, sizeof(ViewInject_KingsQuest6_Dual1)));
+ _loop[12].cel[1].rawBitmap->allocateFromSpan(SciSpan<const byte>(ViewInject_KingsQuest6_Dual2, sizeof(ViewInject_KingsQuest6_Dual2)));
}
}
break;
@@ -491,16 +466,19 @@ void GfxView::getCelScaledRect(int16 loopNo, int16 celNo, int16 x, int16 y, int1
outRect.top = outRect.bottom - scaledHeight;
}
-void unpackCelData(byte *inBuffer, byte *celBitmap, byte clearColor, int pixelCount, int rlePos, int literalPos, ViewType viewType, uint16 width, bool isMacSci11ViewData) {
- byte *outPtr = celBitmap;
+void unpackCelData(const SciSpan<const byte> &inBuffer, SciSpan<byte> &celBitmap, byte clearColor, int rlePos, int literalPos, ViewType viewType, uint16 width, bool isMacSci11ViewData) {
+ const int pixelCount = celBitmap.size();
+ byte *outPtr = celBitmap.getUnsafeDataAt(0);
byte curByte, runLength;
- byte *rlePtr = inBuffer + rlePos;
+ // TODO: Calculate correct maximum dimensions
+ const byte *rlePtr = inBuffer.getUnsafeDataAt(rlePos);
// The existence of a literal position pointer signifies data with two
// separate streams, most likely a SCI1.1 view
- byte *literalPtr = inBuffer + literalPos;
+ const byte *literalPtr = inBuffer.getUnsafeDataAt(literalPos, inBuffer.size() - literalPos);
+ const byte *const endOfResource = inBuffer.getUnsafeDataAt(inBuffer.size(), 0);
int pixelNr = 0;
- memset(celBitmap, clearColor, pixelCount);
+ memset(celBitmap.getUnsafeDataAt(0), clearColor, celBitmap.size());
// View unpacking:
//
@@ -545,14 +523,17 @@ void unpackCelData(byte *inBuffer, byte *celBitmap, byte clearColor, int pixelCo
uint32 pixelLine = pixelNr;
if (hasByteLengths) {
+ assert (rlePtr + 2 <= endOfResource);
pixelNr += *rlePtr++;
runLength = *rlePtr++;
} else {
+ assert (rlePtr + 4 <= endOfResource);
pixelNr += READ_BE_UINT16(rlePtr);
runLength = READ_BE_UINT16(rlePtr + 2);
rlePtr += 4;
}
+ assert(literalPtr + MIN<int>(runLength, pixelCount - pixelNr) <= endOfResource);
while (runLength-- && pixelNr < pixelCount)
outPtr[pixelNr++] = *literalPtr++;
@@ -566,7 +547,7 @@ void unpackCelData(byte *inBuffer, byte *celBitmap, byte clearColor, int pixelCo
while (pixelNr < pixelCount) {
curByte = *rlePtr++;
runLength = curByte >> 4;
- memset(outPtr + pixelNr, curByte & 0x0F, MIN<uint16>(runLength, pixelCount - pixelNr));
+ memset(outPtr + pixelNr, curByte & 0x0F, MIN<uint16>(runLength, pixelCount - pixelNr));
pixelNr += runLength;
}
break;
@@ -576,7 +557,7 @@ void unpackCelData(byte *inBuffer, byte *celBitmap, byte clearColor, int pixelCo
if (curByte & 0x07) { // fill with color
runLength = curByte & 0x07;
curByte = curByte >> 3;
- memset(outPtr + pixelNr, curByte, MIN<uint16>(runLength, pixelCount - pixelNr));
+ memset(outPtr + pixelNr, curByte, MIN<uint16>(runLength, pixelCount - pixelNr));
} else { // skip the next pixels (transparency)
runLength = curByte >> 3;
}
@@ -589,7 +570,7 @@ void unpackCelData(byte *inBuffer, byte *celBitmap, byte clearColor, int pixelCo
if (curByte & 0xC0) { // fill with color
runLength = curByte >> 6;
curByte = curByte & 0x3F;
- memset(outPtr + pixelNr, curByte, MIN<uint16>(runLength, pixelCount - pixelNr));
+ memset(outPtr + pixelNr, curByte, MIN<uint16>(runLength, pixelCount - pixelNr));
} else { // skip the next pixels (transparency)
runLength = curByte & 0x3F;
}
@@ -638,12 +619,12 @@ void unpackCelData(byte *inBuffer, byte *celBitmap, byte clearColor, int pixelCo
}
}
-void GfxView::unpackCel(int16 loopNo, int16 celNo, byte *outPtr, uint32 pixelCount) {
+void GfxView::unpackCel(int16 loopNo, int16 celNo, SciSpan<byte> &outPtr) {
const CelInfo *celInfo = getCelInfo(loopNo, celNo);
if (celInfo->offsetEGA) {
// decompression for EGA views
- unpackCelData(_resourceData, outPtr, 0, pixelCount, celInfo->offsetEGA, 0, _resMan->getViewType(), celInfo->width, false);
+ unpackCelData(*_resource, outPtr, 0, celInfo->offsetEGA, 0, _resMan->getViewType(), celInfo->width, false);
} else {
// We fill the buffer with transparent pixels, so that we can later skip
// over pixels to automatically have them transparent
@@ -667,11 +648,11 @@ void GfxView::unpackCel(int16 loopNo, int16 celNo, byte *outPtr, uint32 pixelCou
}
bool isMacSci11ViewData = g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() == SCI_VERSION_1_1;
- unpackCelData(_resourceData, outPtr, clearColor, pixelCount, celInfo->offsetRLE, celInfo->offsetLiteral, _resMan->getViewType(), celInfo->width, isMacSci11ViewData);
+ unpackCelData(*_resource, outPtr, clearColor, celInfo->offsetRLE, celInfo->offsetLiteral, _resMan->getViewType(), celInfo->width, isMacSci11ViewData);
// Swap 0 and 0xff pixels for Mac SCI1.1+ games (see above)
if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_1_1) {
- for (uint32 i = 0; i < pixelCount; i++) {
+ for (uint32 i = 0; i < outPtr.size(); i++) {
if (outPtr[i] == 0)
outPtr[i] = 0xff;
else if (outPtr[i] == 0xff)
@@ -681,39 +662,44 @@ void GfxView::unpackCel(int16 loopNo, int16 celNo, byte *outPtr, uint32 pixelCou
}
}
-const byte *GfxView::getBitmap(int16 loopNo, int16 celNo) {
- loopNo = CLIP<int16>(loopNo, 0, _loopCount -1);
- celNo = CLIP<int16>(celNo, 0, _loop[loopNo].celCount - 1);
- if (_loop[loopNo].cel[celNo].rawBitmap)
- return _loop[loopNo].cel[celNo].rawBitmap;
+const SciSpan<const byte> &GfxView::getBitmap(int16 loopNo, int16 celNo) {
+ loopNo = CLIP<int16>(loopNo, 0, _loop.size() - 1);
+ celNo = CLIP<int16>(celNo, 0, _loop[loopNo].cel.size() - 1);
- uint16 width = _loop[loopNo].cel[celNo].width;
- uint16 height = _loop[loopNo].cel[celNo].height;
- // allocating memory to store cel's bitmap
- int pixelCount = width * height;
- _loop[loopNo].cel[celNo].rawBitmap = new byte[pixelCount];
- byte *pBitmap = _loop[loopNo].cel[celNo].rawBitmap;
+ CelInfo &cel = _loop[loopNo].cel[celNo];
+
+ if (cel.rawBitmap)
+ return *cel.rawBitmap;
+
+ const uint16 width = cel.width;
+ const uint16 height = cel.height;
+ const uint pixelCount = width * height;
+ const Common::String sourceName = Common::String::format("%s loop %d cel %d", _resource->name().c_str(), loopNo, celNo);
+
+ SciSpan<byte> outBitmap = cel.rawBitmap->allocate(pixelCount, sourceName);
// unpack the actual cel bitmap data
- unpackCel(loopNo, celNo, pBitmap, pixelCount);
+ unpackCel(loopNo, celNo, outBitmap);
if (_resMan->getViewType() == kViewEga)
- unditherBitmap(pBitmap, width, height, _loop[loopNo].cel[celNo].clearKey);
+ unditherBitmap(outBitmap, width, height, _loop[loopNo].cel[celNo].clearKey);
// mirroring the cel if needed
if (_loop[loopNo].mirrorFlag) {
+ byte *pBitmap = outBitmap.getUnsafeDataAt(0, width * height);
for (int i = 0; i < height; i++, pBitmap += width)
for (int j = 0; j < width / 2; j++)
SWAP(pBitmap[j], pBitmap[width - j - 1]);
}
- return _loop[loopNo].cel[celNo].rawBitmap;
+
+ return *cel.rawBitmap;
}
/**
* Called after unpacking an EGA cel, this will try to undither (parts) of the
* cel if the dithering in here matches dithering used by the current picture.
*/
-void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte clearKey) {
+void GfxView::unditherBitmap(SciSpan<byte> &bitmapPtr, int16 width, int16 height, byte clearKey) {
int16 *ditheredPicColors = _screen->unditherGetDitheredBgColors();
// It makes no sense to go further, if there isn't any dithered color data
@@ -731,7 +717,6 @@ void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte cl
// Walk through the bitmap and remember all combinations of colors
int16 ditheredBitmapColors[DITHERED_BG_COLORS_SIZE];
- byte *curPtr;
byte color1, color2;
byte nextColor1, nextColor2;
int16 y, x;
@@ -742,8 +727,8 @@ void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte cl
// pixels are adjacent and check pixels in the following line as well to
// be the reverse pixel combination
int16 checkHeight = height - 1;
- curPtr = bitmapPtr;
- byte *nextPtr = curPtr + width;
+ byte *curPtr = bitmapPtr.getUnsafeDataAt(0, checkHeight * width);
+ const byte *nextPtr = bitmapPtr.getUnsafeDataAt(width, checkHeight * width);
for (y = 0; y < checkHeight; y++) {
color1 = curPtr[0]; color2 = (curPtr[1] << 4) | curPtr[2];
nextColor1 = nextPtr[0] << 4; nextColor2 = (nextPtr[2] << 4) | nextPtr[1];
@@ -783,9 +768,9 @@ void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte cl
return;
// We now need to replace color-combinations
- curPtr = bitmapPtr;
+ curPtr = bitmapPtr.getUnsafeDataAt(0, height * width);
for (y = 0; y < height; y++) {
- color = *curPtr;
+ color = curPtr[0];
for (x = 1; x < width; x++) {
color = (color << 4) | curPtr[1];
if (unditherTable[color]) {
@@ -806,12 +791,11 @@ void GfxView::draw(const Common::Rect &rect, const Common::Rect &clipRect, const
int16 loopNo, int16 celNo, byte priority, uint16 EGAmappingNr, bool upscaledHires) {
const Palette *palette = _embeddedPal ? &_viewPalette : &_palette->_sysPalette;
const CelInfo *celInfo = getCelInfo(loopNo, celNo);
- const byte *bitmap = getBitmap(loopNo, celNo);
+ const SciSpan<const byte> &bitmap = getBitmap(loopNo, celNo);
const int16 celHeight = celInfo->height;
const int16 celWidth = celInfo->width;
const byte clearKey = celInfo->clearKey;
const byte drawMask = priority > 15 ? GFX_SCREEN_MASK_VISUAL : GFX_SCREEN_MASK_VISUAL|GFX_SCREEN_MASK_PRIORITY;
- int x, y;
if (_embeddedPal)
// Merge view palette in...
@@ -820,12 +804,16 @@ void GfxView::draw(const Common::Rect &rect, const Common::Rect &clipRect, const
const int16 width = MIN(clipRect.width(), celWidth);
const int16 height = MIN(clipRect.height(), celHeight);
- bitmap += (clipRect.top - rect.top) * celWidth + (clipRect.left - rect.left);
+ if (!width || !height) {
+ return;
+ }
+
+ const byte *bitmapData = bitmap.getUnsafeDataAt((clipRect.top - rect.top) * celWidth + (clipRect.left - rect.left), celWidth * (height - 1) + width);
if (!_EGAmapping) {
- for (y = 0; y < height; y++, bitmap += celWidth) {
- for (x = 0; x < width; x++) {
- const byte color = bitmap[x];
+ for (int y = 0; y < height; y++, bitmapData += celWidth) {
+ for (int x = 0; x < width; x++) {
+ const byte color = bitmapData[x];
if (color != clearKey) {
const int x2 = clipRectTranslated.left + x;
const int y2 = clipRectTranslated.top + y;
@@ -850,10 +838,10 @@ void GfxView::draw(const Common::Rect &rect, const Common::Rect &clipRect, const
}
}
} else {
- byte *EGAmapping = _EGAmapping + (EGAmappingNr * SCI_VIEW_EGAMAPPING_SIZE);
- for (y = 0; y < height; y++, bitmap += celWidth) {
- for (x = 0; x < width; x++) {
- const byte color = EGAmapping[bitmap[x]];
+ const SciSpan<const byte> EGAmapping = _EGAmapping.subspan(EGAmappingNr * SCI_VIEW_EGAMAPPING_SIZE, SCI_VIEW_EGAMAPPING_SIZE);
+ for (int y = 0; y < height; y++, bitmapData += celWidth) {
+ for (int x = 0; x < width; x++) {
+ const byte color = EGAmapping[bitmapData[x]];
const int x2 = clipRectTranslated.left + x;
const int y2 = clipRectTranslated.top + y;
if (color != clearKey && priority >= _screen->getPriority(x2, y2))
@@ -872,7 +860,7 @@ void GfxView::drawScaled(const Common::Rect &rect, const Common::Rect &clipRect,
int16 loopNo, int16 celNo, byte priority, int16 scaleX, int16 scaleY) {
const Palette *palette = _embeddedPal ? &_viewPalette : &_palette->_sysPalette;
const CelInfo *celInfo = getCelInfo(loopNo, celNo);
- const byte *bitmap = getBitmap(loopNo, celNo);
+ const SciSpan<const byte> &bitmap = getBitmap(loopNo, celNo);
const int16 celHeight = celInfo->height;
const int16 celWidth = celInfo->width;
const byte clearKey = celInfo->clearKey;
@@ -933,15 +921,17 @@ void GfxView::drawScaled(const Common::Rect &rect, const Common::Rect &clipRect,
const int16 offsetY = clipRect.top - rect.top;
const int16 offsetX = clipRect.left - rect.left;
+ // TODO: Remove? This class is not for SCI32
// Happens in SQ6, first room
if (offsetX < 0 || offsetY < 0)
return;
assert(scaledHeight + offsetY <= ARRAYSIZE(scalingY));
assert(scaledWidth + offsetX <= ARRAYSIZE(scalingX));
+ const byte *bitmapData = bitmap.getUnsafeDataAt(0, celWidth * celHeight);
for (int y = 0; y < scaledHeight; y++) {
for (int x = 0; x < scaledWidth; x++) {
- const byte color = bitmap[scalingY[y + offsetY] * celWidth + scalingX[x + offsetX]];
+ const byte color = bitmapData[scalingY[y + offsetY] * celWidth + scalingX[x + offsetX]];
const int x2 = clipRectTranslated.left + x;
const int y2 = clipRectTranslated.top + y;
if (color != clearKey && priority >= _screen->getPriority(x2, y2)) {
diff --git a/engines/sci/graphics/view.h b/engines/sci/graphics/view.h
index 5e422468b5..808e203682 100644
--- a/engines/sci/graphics/view.h
+++ b/engines/sci/graphics/view.h
@@ -23,6 +23,8 @@
#ifndef SCI_GRAPHICS_VIEW_H
#define SCI_GRAPHICS_VIEW_H
+#include "sci/util.h"
+
namespace Sci {
enum Sci32ViewNativeResolution {
@@ -41,17 +43,19 @@ struct CelInfo {
uint16 offsetEGA;
uint32 offsetRLE;
uint32 offsetLiteral;
- byte *rawBitmap;
+ Common::SpanOwner<SciSpan<const byte> > rawBitmap;
};
struct LoopInfo {
bool mirrorFlag;
uint16 celCount;
- CelInfo *cel;
+ Common::Array<CelInfo> cel;
};
-#define SCI_VIEW_EGAMAPPING_SIZE 16
-#define SCI_VIEW_EGAMAPPING_COUNT 8
+enum {
+ SCI_VIEW_EGAMAPPING_SIZE = 16,
+ SCI_VIEW_EGAMAPPING_COUNT = 8
+};
class GfxScreen;
class GfxPalette;
@@ -73,7 +77,7 @@ public:
void getCelRect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, Common::Rect &outRect) const;
void getCelSpecialHoyle4Rect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, Common::Rect &outRect) const;
void getCelScaledRect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, int16 scaleX, int16 scaleY, Common::Rect &outRect) const;
- const byte *getBitmap(int16 loopNo, int16 celNo);
+ const SciSpan<const byte> &getBitmap(int16 loopNo, int16 celNo);
void draw(const Common::Rect &rect, const Common::Rect &clipRect, const Common::Rect &clipRectTranslated, int16 loopNo, int16 celNo, byte priority, uint16 EGAmappingNr, bool upscaledHires);
void drawScaled(const Common::Rect &rect, const Common::Rect &clipRect, const Common::Rect &clipRectTranslated, int16 loopNo, int16 celNo, byte priority, int16 scaleX, int16 scaleY);
uint16 getLoopCount() const { return _loopCount; }
@@ -88,8 +92,8 @@ public:
private:
void initData(GuiResourceId resourceId);
- void unpackCel(int16 loopNo, int16 celNo, byte *outPtr, uint32 pixelCount);
- void unditherBitmap(byte *bitmap, int16 width, int16 height, byte clearKey);
+ void unpackCel(int16 loopNo, int16 celNo, SciSpan<byte> &outPtr);
+ void unditherBitmap(SciSpan<byte> &bitmap, int16 width, int16 height, byte clearKey);
ResourceManager *_resMan;
GfxCoordAdjuster16 *_coordAdjuster;
@@ -98,18 +102,16 @@ private:
GuiResourceId _resourceId;
Resource *_resource;
- byte *_resourceData;
- int _resourceSize;
uint16 _loopCount;
- LoopInfo *_loop;
+ Common::Array<LoopInfo> _loop;
bool _embeddedPal;
Palette _viewPalette;
// specifies scaling resolution for SCI2 views (see gk1/windows, Wolfgang in room 720)
Sci32ViewNativeResolution _sci2ScaleRes;
- byte *_EGAmapping;
+ SciSpan<const byte> _EGAmapping;
// this is set for sci0early to adjust for the getCelRect() change
int16 _adjustForSci0Early;
diff --git a/engines/sci/parser/vocabulary.cpp b/engines/sci/parser/vocabulary.cpp
index ea8722aefd..4fefff6e3b 100644
--- a/engines/sci/parser/vocabulary.cpp
+++ b/engines/sci/parser/vocabulary.cpp
@@ -104,14 +104,14 @@ bool Vocabulary::loadParserWords() {
VocabularyVersions resourceType = _vocabVersion;
if (resourceType == kVocabularySCI0) {
- if (resource->size < 26 * 2) {
+ if (resource->size() < 26 * 2) {
warning("Invalid main vocabulary encountered: Much too small");
return false;
}
// Check the alphabet-offset table for any content
int alphabetNr;
for (alphabetNr = 0; alphabetNr < 26; alphabetNr++) {
- if (READ_LE_UINT16(resource->data + alphabetNr * 2))
+ if (resource->getUint16LEAt(alphabetNr * 2))
break;
}
// If all of them were empty, we are definitely seeing SCI01 vocab in disguise (e.g. pq2 japanese)
@@ -127,7 +127,7 @@ bool Vocabulary::loadParserWords() {
else
seeker = 26 * 2; // vocab.000 starts with 26 16-bit pointers which we don't use
- if (resource->size < seeker) {
+ if (resource->size() < seeker) {
warning("Invalid main vocabulary encountered: Too small");
return false;
// Now this ought to be critical, but it'll just cause parse() and said() not to work
@@ -135,25 +135,25 @@ bool Vocabulary::loadParserWords() {
_parserWords.clear();
- while (seeker < resource->size) {
+ while (seeker < resource->size()) {
byte c;
- currentWordPos = resource->data[seeker++]; // Parts of previous words may be re-used
+ currentWordPos = resource->getUint8At(seeker++); // Parts of previous words may be re-used
if (resourceType == kVocabularySCI1) {
c = 1;
- while (seeker < resource->size && currentWordPos < 255 && c) {
- c = resource->data[seeker++];
+ while (seeker < resource->size() && currentWordPos < 255 && c) {
+ c = resource->getUint8At(seeker++);
currentWord[currentWordPos++] = c;
}
- if (seeker == resource->size) {
+ if (seeker == resource->size()) {
warning("SCI1: Vocabulary not usable, disabling");
_parserWords.clear();
return false;
}
} else {
do {
- c = resource->data[seeker++];
+ c = resource->getUint8At(seeker++);
currentWord[currentWordPos++] = c & 0x7f; // 0x80 is used to terminate the string
} while (c < 0x80);
}
@@ -161,10 +161,10 @@ bool Vocabulary::loadParserWords() {
currentWord[currentWordPos] = 0;
// Now decode class and group:
- c = resource->data[seeker + 1];
+ c = resource->getUint8At(seeker + 1);
ResultWord newWord;
- newWord._class = ((resource->data[seeker]) << 4) | ((c & 0xf0) >> 4);
- newWord._group = (resource->data[seeker + 2]) | ((c & 0x0f) << 8);
+ newWord._class = ((resource->getUint8At(seeker)) << 4) | ((c & 0xf0) >> 4);
+ newWord._group = (resource->getUint8At(seeker + 2)) | ((c & 0x0f) << 8);
// SCI01 was the first version to support multiple class/group pairs
// per word, so we clear the list in earlier versions
@@ -198,38 +198,38 @@ const char *Vocabulary::getAnyWordFromGroup(int group) {
bool Vocabulary::loadSuffixes() {
// Determine if we can find a SCI1 suffix vocabulary first
- Resource* resource = _resMan->findResource(ResourceId(kResourceTypeVocab, _resourceIdSuffixes), 1);
+ Resource* resource = _resMan->findResource(ResourceId(kResourceTypeVocab, _resourceIdSuffixes), true);
if (!resource)
return false; // No vocabulary found
uint32 seeker = 1;
- while ((seeker < resource->size - 1) && (resource->data[seeker + 1] != 0xff)) {
+ while (seeker < resource->size() - 1 && resource->getUint8At(seeker + 1) != 0xff) {
suffix_t suffix;
- int maxSize = resource->size - seeker;
- suffix.alt_suffix = (const char *)resource->data + seeker;
+ int maxSize = resource->size() - seeker;
+ suffix.alt_suffix = (const char *)resource->getUnsafeDataAt(seeker, maxSize);
suffix.alt_suffix_length = Common::strnlen(suffix.alt_suffix, maxSize);
if (suffix.alt_suffix_length == maxSize) {
- error("Vocabulary alt appears truncated for suffix %d in resource %d at %u", _parserSuffixes.size(), resource->getNumber(), seeker);
+ error("Vocabulary alt from %s appears truncated for suffix %d at %u", resource->name().c_str(), _parserSuffixes.size(), seeker);
}
seeker += suffix.alt_suffix_length + 1; // Hit end of string
- suffix.result_class = (int16)READ_BE_UINT16(resource->data + seeker);
+ suffix.result_class = resource->getInt16BEAt(seeker);
seeker += 2;
// Beginning of next string - skip leading '*'
seeker++;
- maxSize = resource->size - seeker;
- suffix.word_suffix = (const char *)resource->data + seeker;
+ maxSize = resource->size() - seeker;
+ suffix.word_suffix = (const char *)resource->getUnsafeDataAt(seeker, maxSize);
suffix.word_suffix_length = Common::strnlen(suffix.word_suffix, maxSize);
if (suffix.word_suffix_length == maxSize) {
- error("Vocabulary word appears truncated for suffix %d in resource %d at %u", _parserSuffixes.size(), resource->getNumber(), seeker);
+ error("Vocabulary word from %s appears truncated for suffix %d at %u", resource->name().c_str(), _parserSuffixes.size(), seeker);
}
seeker += suffix.word_suffix_length + 1;
- suffix.class_mask = (int16)READ_BE_UINT16(resource->data + seeker);
+ suffix.class_mask = resource->getUint16BEAt(seeker);
seeker += 3; // Next entry
_parserSuffixes.push_back(suffix);
@@ -239,7 +239,7 @@ bool Vocabulary::loadSuffixes() {
}
void Vocabulary::freeSuffixes() {
- Resource* resource = _resMan->findResource(ResourceId(kResourceTypeVocab, _resourceIdSuffixes), 0);
+ Resource* resource = _resMan->findResource(ResourceId(kResourceTypeVocab, _resourceIdSuffixes), false);
if (resource)
_resMan->unlockResource(resource);
@@ -254,7 +254,7 @@ bool Vocabulary::loadBranches() {
if (!resource)
return false; // No parser tree data found
- int branches_nr = resource->size / 20;
+ int branches_nr = resource->size() / 20;
if (branches_nr == 0) {
warning("Parser tree data is empty");
@@ -264,12 +264,12 @@ bool Vocabulary::loadBranches() {
_parserBranches.resize(branches_nr);
for (int i = 0; i < branches_nr; i++) {
- byte *base = resource->data + i * 20;
+ const SciSpan<const byte> base = resource->subspan(i * 20);
- _parserBranches[i].id = (int16)READ_LE_UINT16(base);
+ _parserBranches[i].id = base.getInt16LEAt(0);
for (int k = 0; k < 9; k++)
- _parserBranches[i].data[k] = READ_LE_UINT16(base + 2 + 2 * k);
+ _parserBranches[i].data[k] = base.getUint16LEAt(2 + 2 * k);
_parserBranches[i].data[9] = 0; // Always terminate
}
@@ -281,38 +281,38 @@ bool Vocabulary::loadBranches() {
}
bool Vocabulary::loadAltInputs() {
- Resource *resource = _resMan->findResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_ALT_INPUTS), 1);
+ Resource *resource = _resMan->findResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_ALT_INPUTS), true);
if (!resource)
return true; // it's not a problem if this resource doesn't exist
- const char *data = (const char*)resource->data;
- const char *data_end = data + resource->size;
+ Resource::const_iterator it = resource->cbegin();
+ const Resource::const_iterator end = resource->cend();
_altInputs.clear();
_altInputs.resize(256);
- while (data < data_end && *data) {
+ while (it != end && *it) {
AltInput t;
- t._input = data;
+ t._input = (const char *)&*it;
- uint32 maxSize = data_end - data;
- uint32 l = Common::strnlen(data, maxSize);
+ uint32 maxSize = end - it;
+ uint32 l = Common::strnlen(t._input, maxSize);
if (l == maxSize) {
- error("Alt input from %d appears truncated at %ld", resource->getNumber(), (const byte *)data - resource->data);
+ error("Alt input from %s appears truncated at %ld", resource->name().c_str(), it - resource->cbegin());
}
t._inputLength = l;
- data += l + 1;
+ it += l + 1;
- t._replacement = data;
- maxSize = data_end - data;
- l = Common::strnlen(data, maxSize);
+ t._replacement = (const char *)&*it;
+ maxSize = end - it;
+ l = Common::strnlen(t._replacement, maxSize);
if (l == maxSize) {
- error("Alt input replacement from %d appears truncated at %ld", resource->getNumber(), (const byte *)data - resource->data);
+ error("Alt input replacement from %s appears truncated at %ld", resource->name().c_str(), it - resource->cbegin());
}
- data += l + 1;
+ it += l + 1;
- if (data < data_end && strncmp(data, t._input, t._inputLength) == 0)
+ if (it < end && strncmp((const char *)&*it, t._input, t._inputLength) == 0)
t._prefix = true;
else
t._prefix = false;
@@ -325,7 +325,7 @@ bool Vocabulary::loadAltInputs() {
}
void Vocabulary::freeAltInputs() {
- Resource *resource = _resMan->findResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_ALT_INPUTS), 0);
+ Resource *resource = _resMan->findResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_ALT_INPUTS), false);
if (resource)
_resMan->unlockResource(resource);
@@ -466,10 +466,12 @@ void Vocabulary::lookupWord(ResultWordList& retval, const char *word, int word_l
}
}
-void Vocabulary::debugDecipherSaidBlock(const byte *addr) {
+void Vocabulary::debugDecipherSaidBlock(const SciSpan<const byte> &data) {
bool first = true;
uint16 nextItem;
+ SciSpan<const byte>::const_iterator addr = data.cbegin();
+
do {
nextItem = *addr++;
if (nextItem != 0xff) {
@@ -515,7 +517,7 @@ void Vocabulary::debugDecipherSaidBlock(const byte *addr) {
break;
}
}
- } while (nextItem != 0xff);
+ } while (nextItem != 0xff && addr != data.cend());
}
static const byte lowerCaseMap[256] = {
diff --git a/engines/sci/parser/vocabulary.h b/engines/sci/parser/vocabulary.h
index 59558ce18a..763c1fd189 100644
--- a/engines/sci/parser/vocabulary.h
+++ b/engines/sci/parser/vocabulary.h
@@ -30,6 +30,7 @@
#include "sci/sci.h"
#include "sci/engine/vm_types.h"
+#include "sci/util.h"
namespace Common {
@@ -260,7 +261,7 @@ public:
* For debugging only.
* @param pos pointer to the data to dump
*/
- void debugDecipherSaidBlock(const byte *pos);
+ void debugDecipherSaidBlock(const SciSpan<const byte> &data);
/**
* Prints the parser suffixes to the debug console.
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index aaa1c8ccfe..6f4248e094 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -192,27 +192,25 @@ ResourceType ResourceManager::convertResType(byte type) {
}
//-- Resource main functions --
-Resource::Resource(ResourceManager *resMan, ResourceId id) : _resMan(resMan), _id(id) {
- data = NULL;
- size = 0;
+Resource::Resource(ResourceManager *resMan, ResourceId id) : SciSpan<const byte>(nullptr, 0, id.toString()), _resMan(resMan), _id(id) {
_fileOffset = 0;
_status = kResStatusNoMalloc;
_lockers = 0;
- _source = NULL;
- _header = NULL;
+ _source = nullptr;
+ _header = nullptr;
_headerSize = 0;
}
Resource::~Resource() {
- delete[] data;
+ delete[] _data;
delete[] _header;
if (_source && _source->getSourceType() == kSourcePatch)
delete _source;
}
void Resource::unalloc() {
- delete[] data;
- data = NULL;
+ delete[] _data;
+ _data = nullptr;
_status = kResStatusNoMalloc;
}
@@ -221,12 +219,12 @@ void Resource::writeToStream(Common::WriteStream *stream) const {
stream->writeByte(_headerSize);
if (_headerSize > 0)
stream->write(_header, _headerSize);
- stream->write(data, size);
+ stream->write(_data, _size);
}
#ifdef ENABLE_SCI32
Common::SeekableReadStream *Resource::makeStream() const {
- return new Common::MemoryReadStream(data, size, DisposeAfterUse::NO);
+ return new Common::MemoryReadStream(_data, _size, DisposeAfterUse::NO);
}
#endif
@@ -304,25 +302,26 @@ bool Resource::loadPatch(Common::SeekableReadStream *file) {
// We assume that the resource type matches `type`
// We also assume that the current file position is right at the actual data (behind resourceid/headersize byte)
- data = new byte[size];
+ byte *ptr = new byte[size()];
+ _data = ptr;
if (_headerSize > 0)
_header = new byte[_headerSize];
- if (data == nullptr || (_headerSize > 0 && _header == nullptr)) {
- error("Can't allocate %d bytes needed for loading %s", size + _headerSize, _id.toString().c_str());
+ if (data() == nullptr || (_headerSize > 0 && _header == nullptr)) {
+ error("Can't allocate %lu bytes needed for loading %s", size() + _headerSize, _id.toString().c_str());
}
- uint32 really_read;
+ uint32 bytesRead;
if (_headerSize > 0) {
- really_read = file->read(_header, _headerSize);
- if (really_read != _headerSize)
- error("Read %d bytes from %s but expected %d", really_read, _id.toString().c_str(), _headerSize);
+ bytesRead = file->read(_header, _headerSize);
+ if (bytesRead != _headerSize)
+ error("Read %d bytes from %s but expected %d", bytesRead, _id.toString().c_str(), _headerSize);
}
- really_read = file->read(data, size);
- if (really_read != size)
- error("Read %d bytes from %s but expected %d", really_read, _id.toString().c_str(), size);
+ bytesRead = file->read(ptr, size());
+ if (bytesRead != size())
+ error("Read %d bytes from %s but expected %lu", bytesRead, _id.toString().c_str(), size());
_status = kResStatusAllocated;
return true;
@@ -425,10 +424,12 @@ bool MacResourceForkResourceSource::isCompressableResource(ResourceType type) co
}
#define OUTPUT_LITERAL() \
+ assert(ptr + literalLength <= bufferEnd); \
while (literalLength--) \
*ptr++ = stream->readByte();
#define OUTPUT_COPY() \
+ assert(ptr + copyLength <= bufferEnd); \
while (copyLength--) { \
byte value = ptr[-offset]; \
*ptr++ = value; \
@@ -450,27 +451,29 @@ void MacResourceForkResourceSource::decompressResource(Common::SeekableReadStrea
// Get the uncompressed size from the end of the resource
if (canBeCompressed && stream->size() > 4) {
- stream->seek(stream->size() - 4);
+ stream->seek(-4, SEEK_END);
uncompressedSize = stream->readUint32BE();
stream->seek(0);
}
if (uncompressedSize == 0) {
// Not compressed
- resource->size = stream->size();
+ resource->_size = stream->size();
// Cut out the 'non-compressed marker' (four zeroes) at the end
if (canBeCompressed)
- resource->size -= 4;
+ resource->_size -= 4;
- resource->data = new byte[resource->size];
- stream->read(resource->data, resource->size);
+ byte *ptr = new byte[resource->size()];
+ resource->_data = ptr;
+ stream->read(ptr, resource->size());
} else {
// Decompress
- resource->size = uncompressedSize;
- resource->data = new byte[uncompressedSize];
+ resource->_size = uncompressedSize;
+ byte *ptr = new byte[uncompressedSize];
+ resource->_data = ptr;
- byte *ptr = resource->data;
+ const byte *const bufferEnd = resource->data() + uncompressedSize;
while (stream->pos() < stream->size()) {
byte code = stream->readByte();
@@ -812,7 +815,7 @@ void ChunkResourceSource::scanSource(ResourceManager *resMan) {
if (!chunk)
error("Trying to load non-existent chunk");
- byte *ptr = chunk->data;
+ const byte *ptr = chunk->data();
uint32 firstOffset = 0;
for (;;) {
@@ -838,7 +841,7 @@ void ChunkResourceSource::scanSource(ResourceManager *resMan) {
if (!firstOffset)
firstOffset = entry.offset;
- if ((size_t)(ptr - chunk->data) >= firstOffset)
+ if ((size_t)(ptr - chunk->data()) >= firstOffset)
break;
}
}
@@ -850,14 +853,16 @@ void ChunkResourceSource::loadResource(ResourceManager *resMan, Resource *res) {
error("Trying to load non-existent resource from chunk %d: %s %d", _number, getResourceTypeName(res->_id.getType()), res->_id.getNumber());
ResourceEntry entry = _resMap[res->_id];
- res->data = new byte[entry.length];
- res->size = entry.length;
+ assert(entry.offset + entry.length <= chunk->_size);
+ byte *ptr = new byte[entry.length];
+ res->_data = ptr;
+ res->_size = entry.length;
res->_header = 0;
res->_headerSize = 0;
res->_status = kResStatusAllocated;
// Copy the resource data over
- memcpy(res->data, chunk->data + entry.offset, entry.length);
+ memcpy(ptr, chunk->data() + entry.offset, entry.length);
}
void ResourceManager::addResourcesFromChunk(uint16 id) {
@@ -996,7 +1001,7 @@ void ResourceManager::removeFromLRU(Resource *res) {
return;
}
_LRU.remove(res);
- _memoryLRU -= res->size;
+ _memoryLRU -= res->size();
res->_status = kResStatusAllocated;
}
@@ -1006,7 +1011,7 @@ void ResourceManager::addToLRU(Resource *res) {
return;
}
_LRU.push_front(res);
- _memoryLRU += res->size;
+ _memoryLRU += res->size();
#if SCI_VERBOSE_RESMAN
debug("Adding %s (%d bytes) to lru control: %d bytes total",
res->_id.toString().c_str(), res->size,
@@ -1023,8 +1028,8 @@ void ResourceManager::printLRU() {
while (it != _LRU.end()) {
res = *it;
- debug("\t%s: %d bytes", res->_id.toString().c_str(), res->size);
- mem += res->size;
+ debug("\t%s: %lu bytes", res->_id.toString().c_str(), res->size());
+ mem += res->size();
++entries;
++it;
}
@@ -1082,7 +1087,7 @@ Resource *ResourceManager::findResource(ResourceId id, bool lock) {
if (retval->_status == kResStatusAllocated) {
retval->_status = kResStatusLocked;
retval->_lockers = 0;
- _memoryLocked += retval->size;
+ _memoryLocked += retval->_size;
}
retval->_lockers++;
} else if (retval->_status != kResStatusLocked) { // Don't lock it
@@ -1090,11 +1095,11 @@ Resource *ResourceManager::findResource(ResourceId id, bool lock) {
addToLRU(retval);
}
- if (retval->data)
+ if (retval->data())
return retval;
else {
warning("resMan: Failed to read %s", retval->_id.toString().c_str());
- return NULL;
+ return nullptr;
}
}
@@ -1108,7 +1113,7 @@ void ResourceManager::unlockResource(Resource *res) {
if (!--res->_lockers) { // No more lockers?
res->_status = kResStatusAllocated;
- _memoryLocked -= res->size;
+ _memoryLocked -= res->size();
addToLRU(res);
}
@@ -1780,7 +1785,7 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
}
resource->_source = source;
resource->_fileOffset = fileOffset;
- resource->size = 0;
+ resource->_size = 0;
}
}
@@ -1913,7 +1918,7 @@ void ResourceManager::addResource(ResourceId resId, ResourceSource *src, uint32
_resMap.setVal(resId, res);
res->_source = src;
res->_fileOffset = offset;
- res->size = size;
+ res->_size = size;
}
}
@@ -1931,7 +1936,7 @@ Resource *ResourceManager::updateResource(ResourceId resId, ResourceSource *src,
res->_status = kResStatusNoMalloc;
res->_source = src;
res->_headerSize = 0;
- res->size = size;
+ res->_size = size;
return res;
}
@@ -2001,7 +2006,7 @@ int Resource::readResourceInfo(ResVersion volVersion, Common::SeekableReadStream
return SCI_ERROR_IO_ERROR;
_id = ResourceId(type, number);
- size = szUnpacked;
+ _size = szUnpacked;
// checking compression method
switch (wCompression) {
@@ -2075,9 +2080,10 @@ int Resource::decompress(ResVersion volVersion, Common::SeekableReadStream *file
return SCI_ERROR_UNKNOWN_COMPRESSION;
}
- data = new byte[size];
+ byte *ptr = new byte[_size];
+ _data = ptr;
_status = kResStatusAllocated;
- errorNum = data ? dec->unpack(file, data, szPacked, size) : SCI_ERROR_RESOURCE_TOO_BIG;
+ errorNum = ptr ? dec->unpack(file, ptr, szPacked, _size) : SCI_ERROR_RESOURCE_TOO_BIG;
if (errorNum)
unalloc();
@@ -2136,7 +2142,7 @@ ViewType ResourceManager::detectViewType() {
if (res->_source->getSourceType() == kSourcePatch)
continue;
- switch (res->data[1]) {
+ switch (res->getUint8At(1)) {
case 128:
// If the 2nd byte is 128, it's a VGA game.
// However, Longbow Amiga (AGA, 64 colors), also sets this byte
@@ -2149,28 +2155,28 @@ ViewType ResourceManager::detectViewType() {
case 0:
// EGA or Amiga, try to read as Amiga view
- if (res->size < 10)
+ if (res->size() < 10)
return kViewUnknown;
// Read offset of first loop
- uint16 offset = READ_LE_UINT16(res->data + 8);
+ uint16 offset = res->getUint16LEAt(8);
- if (offset + 6U >= res->size)
+ if (offset + 6U >= res->size())
return kViewUnknown;
// Read offset of first cel
- offset = READ_LE_UINT16(res->data + offset + 4);
+ offset = res->getUint16LEAt(offset + 4);
- if (offset + 4U >= res->size)
+ if (offset + 4U >= res->size())
return kViewUnknown;
// Check palette offset, amiga views have no palette
- if (READ_LE_UINT16(res->data + 6) != 0)
+ if (res->getUint16LEAt(6) != 0)
return kViewEga;
- uint16 width = READ_LE_UINT16(res->data + offset);
+ uint16 width = res->getUint16LEAt(offset);
offset += 2;
- uint16 height = READ_LE_UINT16(res->data + offset);
+ uint16 height = res->getUint16LEAt(offset);
offset += 6;
// To improve the heuristic, we skip very small views
@@ -2182,8 +2188,8 @@ ViewType ResourceManager::detectViewType() {
for (y = 0; y < height; y++) {
int x = 0;
- while ((x < width) && (offset < res->size)) {
- byte op = res->data[offset++];
+ while ((x < width) && (offset < res->size())) {
+ byte op = res->getUint8At(offset++);
x += (op & 0x07) ? op & 0x07 : op >> 3;
}
@@ -2226,26 +2232,25 @@ static const byte detectSci21NewStringSignature[] = {
bool ResourceManager::checkResourceDataForSignature(Resource *resource, const byte *signature) {
byte signatureSize = *signature;
- const byte *resourceData = resource->data;
signature++; // skip over size byte
if (signatureSize < 4)
error("resource signature is too small, internal error");
- if (signatureSize > resource->size)
+ if (signatureSize > resource->size())
return false;
const uint32 signatureDWord = READ_UINT32(signature);
signature += 4; signatureSize -= 4;
- const uint32 searchLimit = resource->size - signatureSize + 1;
+ const uint32 searchLimit = resource->size() - signatureSize + 1;
uint32 DWordOffset = 0;
while (DWordOffset < searchLimit) {
- if (signatureDWord == READ_UINT32(resourceData + DWordOffset)) {
+ if (signatureDWord == resource->getUint32At(DWordOffset)) {
// magic DWORD found, check if the rest matches as well
uint32 offset = DWordOffset + 4;
uint32 signaturePos = 0;
while (signaturePos < signatureSize) {
- if (resourceData[offset] != signature[signaturePos])
+ if (resource->getUint8At(offset) != signature[signaturePos])
break;
offset++;
signaturePos++;
@@ -2474,8 +2479,8 @@ bool ResourceManager::detectFontExtended() {
Resource *res = findResource(ResourceId(kResourceTypeFont, 0), 0);
if (res) {
- if (res->size >= 4) {
- uint16 numChars = READ_LE_UINT16(res->data + 2);
+ if (res->size() >= 4) {
+ uint16 numChars = READ_LE_UINT16(res->data() + 2);
if (numChars > 0x80)
return true;
}
@@ -2488,35 +2493,39 @@ bool ResourceManager::detectPaletteMergingSci11() {
// Load palette 999 (default palette)
Resource *res = findResource(ResourceId(kResourceTypePalette, 999), false);
- if ((res) && (res->size > 30)) {
- byte *data = res->data;
+ if (res && res->size() > 30) {
// Old palette format used in palette resource? -> it's merging
- if ((data[0] == 0 && data[1] == 1) || (data[0] == 0 && data[1] == 0 && READ_LE_UINT16(data + 29) == 0))
+ if ((res->getUint8At(0) == 0 && res->getUint8At(1) == 1) ||
+ (res->getUint8At(0) == 0 && res->getUint8At(1) == 0 && res->getUint16LEAt(29) == 0)) {
return true;
+ }
+
// Hardcoded: Laura Bow 2 floppy uses new palette resource, but still palette merging + 16 bit color matching
- if ((g_sci->getGameId() == GID_LAURABOW2) && (!g_sci->isCD()) && (!g_sci->isDemo()))
+ if (g_sci->getGameId() == GID_LAURABOW2 && !g_sci->isCD() && !g_sci->isDemo()) {
return true;
- return false;
+ }
}
+
return false;
}
// is called on SCI0EARLY games to make sure that sound resources are in fact also SCI0EARLY
bool ResourceManager::detectEarlySound() {
- Resource *res = findResource(ResourceId(kResourceTypeSound, 1), 0);
- if (res) {
- if (res->size >= 0x22) {
- if (READ_LE_UINT16(res->data + 0x1f) == 0) // channel 15 voice count + play mask is 0 in SCI0LATE
- if (res->data[0x21] == 0) // last byte right before actual data is 0 as well
- return false;
- }
+ Resource *res = findResource(ResourceId(kResourceTypeSound, 1), false);
+ if (res &&
+ res->size() >= 0x22 &&
+ res->getUint16LEAt(0x1f) == 0 && // channel 15 voice count + play mask is 0 in SCI0LATE
+ res->getUint8At(0x21) == 0) { // last byte right before actual data is 0 as well
+
+ return false;
}
+
return true;
}
// Functions below are based on PD code by Brian Provinciano (SCI Studio)
bool ResourceManager::hasOldScriptHeader() {
- Resource *res = findResource(ResourceId(kResourceTypeScript, 0), 0);
+ Resource *res = findResource(ResourceId(kResourceTypeScript, 0), false);
if (!res) {
// Script 0 missing -> corrupted / non-SCI resource files.
@@ -2528,13 +2537,13 @@ bool ResourceManager::hasOldScriptHeader() {
uint offset = 2;
const int objTypes = 17;
- while (offset < res->size) {
- uint16 objType = READ_LE_UINT16(res->data + offset);
+ while (offset < res->size()) {
+ uint16 objType = res->getUint16LEAt(offset);
if (!objType) {
offset += 2;
// We should be at the end of the resource now
- return offset == res->size;
+ return offset == res->size();
}
if (objType >= objTypes) {
@@ -2542,7 +2551,7 @@ bool ResourceManager::hasOldScriptHeader() {
return false;
}
- int skip = READ_LE_UINT16(res->data + offset + 2);
+ int skip = res->getUint16LEAt(offset + 2);
if (skip < 2) {
// Invalid size
@@ -2556,34 +2565,34 @@ bool ResourceManager::hasOldScriptHeader() {
}
bool ResourceManager::hasSci0Voc999() {
- Resource *res = findResource(ResourceId(kResourceTypeVocab, 999), 0);
+ Resource *res = findResource(ResourceId(kResourceTypeVocab, 999), false);
if (!res) {
// No vocab present, possibly a demo version
return false;
}
- if (res->size < 2)
+ if (res->size() < 2)
return false;
- uint16 count = READ_LE_UINT16(res->data);
+ uint16 count = res->getUint16LEAt(0);
// Make sure there's enough room for the pointers
- if (res->size < (uint)count * 2)
+ if (res->size() < (uint)count * 2)
return false;
// Iterate over all pointers
for (uint i = 0; i < count; i++) {
// Offset to string
- uint16 offset = READ_LE_UINT16(res->data + 2 + count * 2);
+ uint16 offset = res->getUint16LEAt(2 + count * 2);
// Look for end of string
do {
- if (offset >= res->size) {
+ if (offset >= res->size()) {
// Out of bounds
return false;
}
- } while (res->data[offset++]);
+ } while (res->getUint8At(offset++));
}
return true;
@@ -2595,62 +2604,62 @@ bool ResourceManager::hasSci1Voc900() {
if (!res )
return false;
- if (res->size < 0x1fe)
+ if (res->size() < 0x1fe)
return false;
uint16 offset = 0x1fe;
- while (offset < res->size) {
+ while (offset < res->size()) {
offset++;
do {
- if (offset >= res->size) {
+ if (offset >= res->size()) {
// Out of bounds;
return false;
}
- } while (res->data[offset++]);
+ } while (res->getUint8At(offset++));
offset += 3;
}
- return offset == res->size;
+ return offset == res->size();
}
// Same function as Script::findBlockSCI0(). Slight code
// duplication here, but this has been done to keep the resource
// manager independent from the rest of the engine
-static byte *findSci0ExportsBlock(byte *buffer) {
- byte *buf = buffer;
+static SciSpan<const byte>::const_iterator findSci0ExportsBlock(const SciSpan<const byte> &buffer) {
+ SciSpan<const byte>::const_iterator buf = buffer.cbegin();
bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
if (oldScriptHeader)
buf += 2;
- do {
- int seekerType = READ_LE_UINT16(buf);
+ for (;;) {
+ int seekerType = buf.getUint16LE();
if (seekerType == 0)
break;
if (seekerType == 7) // exports
return buf;
- int seekerSize = READ_LE_UINT16(buf + 2);
+ int seekerSize = (buf + 2).getUint16LE();
assert(seekerSize > 0);
buf += seekerSize;
- } while (1);
+ }
- return NULL;
+ return buffer.cend();
}
// This code duplicates Script::relocateOffsetSci3, but we can't use
// that here since we can't instantiate scripts at this point.
-static int relocateOffsetSci3(const byte *buf, uint32 offset) {
- int relocStart = READ_LE_UINT32(buf + 8);
- int relocCount = READ_LE_UINT16(buf + 18);
- const byte *seeker = buf + relocStart;
+static int relocateOffsetSci3(const SciSpan<const byte> &buf, uint32 offset) {
+ int relocStart = buf.getUint32LEAt(8);
+ int relocCount = buf.getUint16LEAt(18);
+ SciSpan<const byte>::const_iterator seeker = buf.cbegin() + relocStart;
for (int i = 0; i < relocCount; ++i) {
- if (READ_SCI11ENDIAN_UINT32(seeker) == offset) {
+ if (seeker.getUint32SE() == offset) {
// TODO: Find out what UINT16 at (seeker + 8) means
- return READ_SCI11ENDIAN_UINT16(buf + offset) + READ_SCI11ENDIAN_UINT32(seeker + 4);
+ return buf.getUint16SEAt(offset) + (seeker + 4).getUint32SE();
}
seeker += 10;
}
@@ -2664,41 +2673,41 @@ reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) {
if (!script)
return NULL_REG;
- byte *offsetPtr = 0;
+ SciSpan<const byte>::const_iterator offsetPtr;
if (getSciVersion() <= SCI_VERSION_1_LATE) {
- byte *buf = (getSciVersion() == SCI_VERSION_0_EARLY) ? script->data + 2 : script->data;
+ SciSpan<const byte> buf = (getSciVersion() == SCI_VERSION_0_EARLY) ? script->subspan(2) : *script;
// Check if the first block is the exports block (in most cases, it is)
- bool exportsIsFirst = (READ_LE_UINT16(buf + 4) == 7);
+ bool exportsIsFirst = buf.getUint16LEAt(4) == 7;
if (exportsIsFirst) {
- offsetPtr = buf + 4 + 2;
+ offsetPtr = buf.subspan(4 + 2).cbegin();
} else {
- offsetPtr = findSci0ExportsBlock(script->data);
- if (!offsetPtr)
+ offsetPtr = findSci0ExportsBlock(*script);
+ if (offsetPtr == buf.cend())
error("Unable to find exports block from script 0");
offsetPtr += 4 + 2;
}
- int16 offset = !isSci11Mac() ? READ_LE_UINT16(offsetPtr) : READ_BE_UINT16(offsetPtr);
+ int16 offset = !isSci11Mac() ? offsetPtr.getUint16LE() : offsetPtr.getUint16BE();
return make_reg(1, offset);
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) {
- offsetPtr = script->data + 4 + 2 + 2;
+ offsetPtr = script->cbegin() + 4 + 2 + 2;
// In SCI1.1 - SCI2.1, the heap is appended at the end of the script,
// so adjust the offset accordingly if requested
- int16 offset = !isSci11Mac() ? READ_LE_UINT16(offsetPtr) : READ_BE_UINT16(offsetPtr);
+ int16 offset = !isSci11Mac() ? offsetPtr.getUint16LE() : offsetPtr.getUint16BE();
if (addSci11ScriptOffset) {
- offset += script->size;
+ offset += script->size();
// Ensure that the start of the heap is word-aligned - same as in Script::init()
- if (script->size & 2)
+ if (script->size() & 2)
offset++;
}
return make_reg(1, offset);
} else {
- return make_reg(1, relocateOffsetSci3(script->data, 22));
+ return make_reg(1, relocateOffsetSci3(*script, 22));
}
}
@@ -2726,13 +2735,9 @@ Common::String ResourceManager::findSierraGameId() {
return "";
// Seek to the name selector of the first export
- byte *offsetPtr = heap->data + gameObjectOffset + nameSelector * 2;
- uint16 offset = !isSci11Mac() ? READ_LE_UINT16(offsetPtr) : READ_BE_UINT16(offsetPtr);
- byte *seeker = heap->data + offset;
- Common::String sierraId;
- sierraId += (const char *)seeker;
-
- return sierraId;
+ SciSpan<const byte>::const_iterator offsetPtr = heap->cbegin() + gameObjectOffset + nameSelector * 2;
+ uint16 offset = !isSci11Mac() ? offsetPtr.getUint16LE() : offsetPtr.getUint16BE();
+ return heap->getStringAt(offset);
}
const Common::String &Resource::getResourceLocation() const {
diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index 5589129553..a9a7a86c96 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -30,6 +30,7 @@
#include "sci/graphics/helpers.h" // for ViewType
#include "sci/decompressor.h"
#include "sci/sci.h"
+#include "sci/util.h"
namespace Common {
class File;
@@ -226,7 +227,7 @@ struct ResourceIdHash : public Common::UnaryFunction<ResourceId, uint> {
};
/** Class for storing resources in memory */
-class Resource {
+class Resource : public SciSpan<const byte> {
friend class ResourceManager;
// FIXME: These 'friend' declarations are meant to be a temporary hack to
@@ -243,8 +244,6 @@ class Resource {
// NOTE : Currently most member variables lack the underscore prefix and have
// public visibility to let the rest of the engine compile without changes.
public:
- byte *data;
- uint32 size;
byte *_header;
uint32 _headerSize;
@@ -595,11 +594,21 @@ public:
byte flags;
byte poly;
uint16 prio;
- uint16 size;
- byte *data;
+ SciSpan<const byte> data;
uint16 curPos;
long time;
byte prev;
+
+ Channel() :
+ number(0),
+ flags(0),
+ poly(0),
+ prio(0),
+ data(),
+ curPos(0) {
+ time = 0;
+ prev = 0;
+ }
};
struct Track {
diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp
index f17a684cc9..0125a0e19b 100644
--- a/engines/sci/resource_audio.cpp
+++ b/engines/sci/resource_audio.cpp
@@ -80,11 +80,12 @@ AudioVolumeResourceSource::~AudioVolumeResourceSource() {
}
bool Resource::loadFromWaveFile(Common::SeekableReadStream *file) {
- data = new byte[size];
+ byte *ptr = new byte[_size];
+ _data = ptr;
- uint32 really_read = file->read(data, size);
- if (really_read != size)
- error("Read %d bytes from %s but expected %d", really_read, _id.toString().c_str(), size);
+ uint32 bytesRead = file->read(ptr, _size);
+ if (bytesRead != _size)
+ error("Read %d bytes from %s but expected %lu", bytesRead, _id.toString().c_str(), _size);
_status = kResStatusAllocated;
return true;
@@ -95,7 +96,7 @@ bool Resource::loadFromAudioVolumeSCI11(Common::SeekableReadStream *file) {
uint32 riffTag = file->readUint32BE();
if (riffTag == MKTAG('R','I','F','F')) {
_headerSize = 0;
- size = file->readUint32LE() + 8;
+ _size = file->readUint32LE() + 8;
file->seek(-8, SEEK_CUR);
return loadFromWaveFile(file);
}
@@ -123,7 +124,8 @@ bool Resource::loadFromAudioVolumeSCI11(Common::SeekableReadStream *file) {
if (_headerSize != 7) { // Size is defined already from the map
// Load sample size
file->seek(7, SEEK_CUR);
- size = file->readUint32LE();
+ _size = file->readUint32LE();
+ assert(!file->err() && !file->eos());
// Adjust offset to point at the header data again
file->seek(-11, SEEK_CUR);
}
@@ -133,15 +135,16 @@ bool Resource::loadFromAudioVolumeSCI11(Common::SeekableReadStream *file) {
}
bool Resource::loadFromAudioVolumeSCI1(Common::SeekableReadStream *file) {
- data = new byte[size];
+ byte *ptr = new byte[size()];
+ _data = ptr;
- if (data == NULL) {
- error("Can't allocate %d bytes needed for loading %s", size, _id.toString().c_str());
+ if (!ptr) {
+ error("Can't allocate %lu bytes needed for loading %s", _size, _id.toString().c_str());
}
- uint32 really_read = file->read(data, size);
- if (really_read != size)
- warning("Read %d bytes from %s but expected %d", really_read, _id.toString().c_str(), size);
+ uint32 bytesRead = file->read(ptr, size());
+ if (bytesRead != size())
+ warning("Read %d bytes from %s but expected %lu", bytesRead, _id.toString().c_str(), _size);
_status = kResStatusAllocated;
return true;
@@ -300,11 +303,13 @@ int ResourceManager::readAudioMapSCI11(IntMapResourceSource *map) {
return SCI_ERROR_NO_RESOURCE_FILES_FOUND;
}
- byte *ptr = mapRes->data;
+ const uint32 srcSize = getVolumeFile(src)->size();
+
+ SciSpan<const byte>::const_iterator ptr = mapRes->cbegin();
// Heuristic to detect entry size
uint32 entrySize = 0;
- for (int i = mapRes->size - 1; i >= 0; --i) {
+ for (int i = mapRes->size() - 1; i >= 0; --i) {
if (ptr[i] == 0xff)
entrySize++;
else
@@ -312,52 +317,54 @@ int ResourceManager::readAudioMapSCI11(IntMapResourceSource *map) {
}
if (map->_mapNumber == 65535) {
- while (ptr < mapRes->data + mapRes->size) {
- uint16 n = READ_LE_UINT16(ptr);
+ while (ptr != mapRes->cend()) {
+ uint16 n = ptr.getUint16LE();
ptr += 2;
if (n == 0xffff)
break;
if (entrySize == 6) {
- offset = READ_LE_UINT32(ptr);
+ offset = ptr.getUint32LE();
ptr += 4;
} else {
- offset += READ_LE_UINT24(ptr);
+ offset += ptr.getUint24LE();
ptr += 3;
}
+ assert(offset < srcSize);
addResource(ResourceId(kResourceTypeAudio, n), src, offset);
}
} else if (map->_mapNumber == 0 && entrySize == 10 && ptr[3] == 0) {
// QFG3 demo format
// ptr[3] would be 'seq' in the normal format and cannot possibly be 0
- while (ptr < mapRes->data + mapRes->size) {
- uint16 n = READ_BE_UINT16(ptr);
+ while (ptr != mapRes->cend()) {
+ uint16 n = ptr.getUint16BE();
ptr += 2;
if (n == 0xffff)
break;
- offset = READ_LE_UINT32(ptr);
+ offset = ptr.getUint32LE();
ptr += 4;
- uint32 size = READ_LE_UINT32(ptr);
+ uint32 size = ptr.getUint32LE();
ptr += 4;
+ assert(offset + size <= srcSize);
addResource(ResourceId(kResourceTypeAudio, n), src, offset, size);
}
- } else if (map->_mapNumber == 0 && entrySize == 8 && READ_LE_UINT16(ptr + 2) == 0xffff) {
+ } else if (map->_mapNumber == 0 && entrySize == 8 && (ptr + 2).getUint16LE() == 0xffff) {
// LB2 Floppy/Mother Goose SCI1.1 format
Common::SeekableReadStream *stream = getVolumeFile(src);
- while (ptr < mapRes->data + mapRes->size) {
- uint16 n = READ_LE_UINT16(ptr);
+ while (ptr != mapRes->cend()) {
+ uint16 n = ptr.getUint16LE();
ptr += 4;
if (n == 0xffff)
break;
- offset = READ_LE_UINT32(ptr);
+ offset = ptr.getUint32LE();
ptr += 4;
// The size is not stored in the map and the entries have no order.
@@ -369,18 +376,19 @@ int ResourceManager::readAudioMapSCI11(IntMapResourceSource *map) {
stream->skip(5);
uint32 size = stream->readUint32LE() + headerSize + 2;
+ assert(offset + size <= srcSize);
addResource(ResourceId(kResourceTypeAudio, n), src, offset, size);
}
} else {
bool isEarly = (entrySize != 11);
if (!isEarly) {
- offset = READ_LE_UINT32(ptr);
+ offset = ptr.getUint32LE();
ptr += 4;
}
- while (ptr < mapRes->data + mapRes->size) {
- uint32 n = READ_BE_UINT32(ptr);
+ while (ptr != mapRes->cend()) {
+ uint32 n = ptr.getUint32BE();
int syncSize = 0;
ptr += 4;
@@ -388,21 +396,23 @@ int ResourceManager::readAudioMapSCI11(IntMapResourceSource *map) {
break;
if (isEarly) {
- offset = READ_LE_UINT32(ptr);
+ offset = ptr.getUint32LE();
ptr += 4;
} else {
- offset += READ_LE_UINT24(ptr);
+ offset += ptr.getUint24LE();
ptr += 3;
}
if (isEarly || (n & 0x80)) {
- syncSize = READ_LE_UINT16(ptr);
+ syncSize = ptr.getUint16LE();
ptr += 2;
// FIXME: The sync36 resource seems to be two bytes too big in KQ6CD
// (bytes taken from the RAVE resource right after it)
- if (syncSize > 0)
+ if (syncSize > 0) {
+ assert(offset + syncSize <= srcSize);
addResource(ResourceId(kResourceTypeSync36, map->_mapNumber, n & 0xffffff3f), src, offset, syncSize);
+ }
}
// Checking for this 0x40 flag breaks at least Laura Bow 2 CD 1.1
@@ -410,15 +420,17 @@ int ResourceManager::readAudioMapSCI11(IntMapResourceSource *map) {
if (g_sci->getGameId() == GID_KQ6 && (n & 0x40)) {
// This seems to define the size of raw lipsync data (at least
// in KQ6 CD Windows).
- int kq6HiresSyncSize = READ_LE_UINT16(ptr);
+ int kq6HiresSyncSize = ptr.getUint16LE();
ptr += 2;
if (kq6HiresSyncSize > 0) {
+ assert(offset + syncSize + kq6HiresSyncSize <= srcSize);
addResource(ResourceId(kResourceTypeRave, map->_mapNumber, n & 0xffffff3f), src, offset + syncSize, kq6HiresSyncSize);
syncSize += kq6HiresSyncSize;
}
}
+ assert(offset + syncSize < srcSize);
addResource(ResourceId(kResourceTypeAudio36, map->_mapNumber, n & 0xffffff3f), src, offset + syncSize);
}
}
@@ -445,7 +457,10 @@ int ResourceManager::readAudioMapSCI1(ResourceSource *map, bool unload) {
bool oldFormat = (file.readUint16LE() >> 11) == kResourceTypeAudio;
file.seek(0);
- while (1) {
+ uint32 volumeSize;
+ int lastVolumeNo = -1;
+
+ for (;;) {
uint16 n = file.readUint16LE();
uint32 offset = file.readUint32LE();
uint32 size = file.readUint32LE();
@@ -472,10 +487,17 @@ int ResourceManager::readAudioMapSCI1(ResourceSource *map, bool unload) {
ResourceSource *src = findVolume(map, volume_nr);
if (src) {
+ if (volume_nr != lastVolumeNo) {
+ volumeSize = getVolumeFile(src)->size();
+ lastVolumeNo = volume_nr;
+ }
+
if (unload)
removeAudioResource(ResourceId(kResourceTypeAudio, n));
- else
+ else {
+ assert(offset + size <= volumeSize);
addResource(ResourceId(kResourceTypeAudio, n), src, offset, size);
+ }
} else {
warning("Failed to find audio volume %i", volume_nr);
}
@@ -583,8 +605,6 @@ SoundResource::SoundResource(uint32 resourceNr, ResourceManager *resMan, SciVers
_innerResource = resource;
_soundPriority = 0xFF;
- byte *data, *data2;
- byte *dataEnd;
Channel *channel, *sampleChannel;
switch (_soundVersion) {
@@ -597,60 +617,54 @@ SoundResource::SoundResource(uint32 resourceNr, ResourceManager *resMan, SciVers
_tracks->type = 0; // Not used for SCI0
_tracks->channelCount = 1;
// Digital sample data included? -> Add an additional channel
- if (resource->data[0] == 2)
+ if (resource->getUint8At(0) == 2)
_tracks->channelCount++;
_tracks->channels = new Channel[_tracks->channelCount];
- memset(_tracks->channels, 0, sizeof(Channel) * _tracks->channelCount);
channel = &_tracks->channels[0];
channel->flags |= 2; // don't remap (SCI0 doesn't have remapping)
if (_soundVersion == SCI_VERSION_0_EARLY) {
- channel->data = resource->data + 0x11;
- channel->size = resource->size - 0x11;
+ channel->data = resource->subspan(0x11);
} else {
- channel->data = resource->data + 0x21;
- channel->size = resource->size - 0x21;
+ channel->data = resource->subspan(0x21);
}
if (_tracks->channelCount == 2) {
// Digital sample data included
_tracks->digitalChannelNr = 1;
sampleChannel = &_tracks->channels[1];
// we need to find 0xFC (channel terminator) within the data
- data = channel->data;
- dataEnd = channel->data + channel->size;
- while ((data < dataEnd) && (*data != 0xfc))
- data++;
+ SciSpan<const byte>::const_iterator it = channel->data.cbegin();
+ while (it != channel->data.cend() && *it != 0xfc)
+ it++;
// Skip any following 0xFCs as well
- while ((data < dataEnd) && (*data == 0xfc))
- data++;
+ while (it != channel->data.cend() && *it == 0xfc)
+ it++;
// Now adjust channels accordingly
- sampleChannel->data = data;
- sampleChannel->size = channel->size - (data - channel->data);
- channel->size = data - channel->data;
+ sampleChannel->data = channel->data.subspan(it - channel->data.cbegin());
+ channel->data = channel->data.subspan(0, it - channel->data.cbegin());
// Read sample header information
//Offset 14 in the header contains the frequency as a short integer. Offset 32 contains the sample length, also as a short integer.
- _tracks->digitalSampleRate = READ_LE_UINT16(sampleChannel->data + 14);
- _tracks->digitalSampleSize = READ_LE_UINT16(sampleChannel->data + 32);
+ _tracks->digitalSampleRate = sampleChannel->data.getUint16LEAt(14);
+ _tracks->digitalSampleSize = sampleChannel->data.getUint16LEAt(32);
_tracks->digitalSampleStart = 0;
_tracks->digitalSampleEnd = 0;
sampleChannel->data += 44; // Skip over header
- sampleChannel->size -= 44;
}
break;
case SCI_VERSION_1_EARLY:
case SCI_VERSION_1_LATE:
- case SCI_VERSION_2_1_EARLY:
- data = resource->data;
+ case SCI_VERSION_2_1_EARLY: {
+ SciSpan<const byte> data = *resource;
// Count # of tracks
_trackCount = 0;
while ((*data++) != 0xFF) {
_trackCount++;
while (*data != 0xFF)
data += 6;
- data++;
+ ++data;
}
_tracks = new Track[_trackCount];
- data = resource->data;
+ data = *resource;
byte channelCount;
@@ -662,7 +676,7 @@ SoundResource::SoundResource(uint32 resourceNr, ResourceManager *resMan, SciVers
_tracks[trackNr].type = *data++;
// Counting # of channels used
- data2 = data;
+ SciSpan<const byte> data2 = data;
channelCount = 0;
while (*data2 != 0xFF) {
data2 += 6;
@@ -680,38 +694,37 @@ SoundResource::SoundResource(uint32 resourceNr, ResourceManager *resMan, SciVers
channelNr = 0;
while (channelCount--) {
channel = &_tracks[trackNr].channels[channelNr];
- uint dataOffset = READ_LE_UINT16(data + 2);
+ const uint16 dataOffset = data.getUint16LEAt(2);
- if (dataOffset >= resource->size) {
+ if (dataOffset >= resource->size()) {
warning("Invalid offset inside sound resource %d: track %d, channel %d", resourceNr, trackNr, channelNr);
data += 6;
continue;
}
- channel->data = resource->data + dataOffset;
- channel->size = READ_LE_UINT16(data + 4);
+ uint16 size = data.getUint16LEAt(4);
- if (dataOffset + channel->size > resource->size) {
+ if (dataOffset + size > resource->size()) {
warning("Invalid size inside sound resource %d: track %d, channel %d", resourceNr, trackNr, channelNr);
- channel->size = resource->size - dataOffset;
+ size = resource->size() - dataOffset;
}
+ channel->data = resource->subspan(dataOffset, size);
+
channel->curPos = 0;
- channel->number = *channel->data;
+ channel->number = channel->data[0];
- channel->poly = *(channel->data + 1) & 0x0F;
- channel->prio = *(channel->data + 1) >> 4;
+ channel->poly = channel->data[1] & 0x0F;
+ channel->prio = channel->data[1] >> 4;
channel->time = channel->prev = 0;
channel->data += 2; // skip over header
- channel->size -= 2; // remove header size
if (channel->number == 0xFE) { // Digital channel
_tracks[trackNr].digitalChannelNr = channelNr;
- _tracks[trackNr].digitalSampleRate = READ_LE_UINT16(channel->data);
- _tracks[trackNr].digitalSampleSize = READ_LE_UINT16(channel->data + 2);
- _tracks[trackNr].digitalSampleStart = READ_LE_UINT16(channel->data + 4);
- _tracks[trackNr].digitalSampleEnd = READ_LE_UINT16(channel->data + 6);
+ _tracks[trackNr].digitalSampleRate = channel->data.getUint16LEAt(0);
+ _tracks[trackNr].digitalSampleSize = channel->data.getUint16LEAt(2);
+ _tracks[trackNr].digitalSampleStart = channel->data.getUint16LEAt(4);
+ _tracks[trackNr].digitalSampleEnd = channel->data.getUint16LEAt(6);
channel->data += 8; // Skip over header
- channel->size -= 8;
channel->flags = 0;
} else {
channel->flags = channel->number >> 4;
@@ -740,9 +753,10 @@ SoundResource::SoundResource(uint32 resourceNr, ResourceManager *resMan, SciVers
// Skip over digital track
data += 6;
}
- data++; // Skipping 0xFF that closes channels list
+ ++data; // Skipping 0xFF that closes channels list
}
break;
+ }
default:
error("SoundResource: SCI version %d is unsupported", _soundVersion);
@@ -789,13 +803,13 @@ SoundResource::Track *SoundResource::getDigitalTrack() {
// Gets the filter mask for SCI0 sound resources
int SoundResource::getChannelFilterMask(int hardwareMask, bool wantsRhythm) {
- byte *data = _innerResource->data;
+ SciSpan<const byte> data = *_innerResource;
int channelMask = 0;
if (_soundVersion > SCI_VERSION_0_LATE)
return 0;
- data++; // Skip over digital sample flag
+ ++data; // Skip over digital sample flag
for (int channelNr = 0; channelNr < 16; channelNr++) {
channelMask = channelMask >> 1;
@@ -823,7 +837,7 @@ int SoundResource::getChannelFilterMask(int hardwareMask, bool wantsRhythm) {
// by the corresponding hardware
// Skip voice count
- data++;
+ ++data;
flags = *data++;
}
@@ -853,12 +867,11 @@ int SoundResource::getChannelFilterMask(int hardwareMask, bool wantsRhythm) {
}
byte SoundResource::getInitialVoiceCount(byte channel) {
- byte *data = _innerResource->data;
-
if (_soundVersion > SCI_VERSION_0_LATE)
return 0; // TODO
- data++; // Skip over digital sample flag
+ // Skip over digital sample flag
+ SciSpan<const byte> data = _innerResource->subspan(1);
if (_soundVersion == SCI_VERSION_0_EARLY)
return data[channel] >> 4;
@@ -902,7 +915,7 @@ void AudioVolumeResourceSource::loadResource(ResourceManager *resMan, Resource *
break;
default:
mappingTable += 2;
- res->size = *mappingTable - compressedOffset;
+ res->_size = *mappingTable - compressedOffset;
}
break;
}
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index 20547f3601..34930a648e 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -361,7 +361,7 @@ Common::Error SciEngine::run() {
// Refer to bug #3036609.
Resource *buggyScript = _resMan->findResource(ResourceId(kResourceTypeScript, 180), 0);
- if (buggyScript && (buggyScript->size == 12354 || buggyScript->size == 12362)) {
+ if (buggyScript && (buggyScript->size() == 12354 || buggyScript->size() == 12362)) {
showScummVMDialog("A known buggy game script has been detected, which could "
"prevent you from progressing later on in the game, during "
"the sequence with the Green Man's riddles. Please, apply "
@@ -477,10 +477,10 @@ bool SciEngine::gameHasFanMadePatch() {
if (patchInfo[curEntry].gameID == getGameId()) {
Resource *targetScript = _resMan->findResource(ResourceId(kResourceTypeScript, patchInfo[curEntry].targetScript), 0);
- if (targetScript && targetScript->size + 2 == patchInfo[curEntry].targetSize) {
+ if (targetScript && targetScript->size() + 2 == patchInfo[curEntry].targetSize) {
if (patchInfo[curEntry].patchedByteOffset == 0)
return true;
- else if (targetScript->data[patchInfo[curEntry].patchedByteOffset - 2] == patchInfo[curEntry].patchedByte)
+ else if (targetScript->getUint8At(patchInfo[curEntry].patchedByteOffset - 2) == patchInfo[curEntry].patchedByte)
return true;
}
}
diff --git a/engines/sci/sound/audio.cpp b/engines/sci/sound/audio.cpp
index 4fb9a58003..e470b315cc 100644
--- a/engines/sci/sound/audio.cpp
+++ b/engines/sci/sound/audio.cpp
@@ -365,15 +365,15 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
if (audioCompressionType) {
#if (defined(USE_MAD) || defined(USE_VORBIS) || defined(USE_FLAC))
// Compressed audio made by our tool
- byte *compressedData = (byte *)malloc(audioRes->size);
+ byte *compressedData = (byte *)malloc(audioRes->size());
assert(compressedData);
// We copy over the compressed data in our own buffer. We have to do
// this, because ResourceManager may free the original data late. All
// other compression types already decompress completely into an
// additional buffer here. MP3/OGG/FLAC decompression works on-the-fly
// instead.
- memcpy(compressedData, audioRes->data, audioRes->size);
- Common::SeekableReadStream *compressedStream = new Common::MemoryReadStream(compressedData, audioRes->size, DisposeAfterUse::YES);
+ audioRes->unsafeCopyDataTo(compressedData);
+ Common::SeekableReadStream *compressedStream = new Common::MemoryReadStream(compressedData, audioRes->size(), DisposeAfterUse::YES);
switch (audioCompressionType) {
case MKTAG('M','P','3',' '):
@@ -401,13 +401,13 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
// SCI1.1
Common::MemoryReadStream headerStream(audioRes->_header, audioRes->_headerSize, DisposeAfterUse::NO);
- if (readSOLHeader(&headerStream, audioRes->_headerSize, size, _audioRate, audioFlags, audioRes->size)) {
- Common::MemoryReadStream dataStream(audioRes->data, audioRes->size, DisposeAfterUse::NO);
+ if (readSOLHeader(&headerStream, audioRes->_headerSize, size, _audioRate, audioFlags, audioRes->size())) {
+ Common::MemoryReadStream dataStream(audioRes->toStream());
data = readSOLAudio(&dataStream, size, audioFlags, flags);
}
- } else if (audioRes->size > 4 && READ_BE_UINT32(audioRes->data) == MKTAG('R','I','F','F')) {
+ } else if (audioRes->size() > 4 && audioRes->getUint32BEAt(0) == MKTAG('R','I','F','F')) {
// WAVE detected
- Common::SeekableReadStream *waveStream = new Common::MemoryReadStream(audioRes->data, audioRes->size, DisposeAfterUse::NO);
+ Common::SeekableReadStream *waveStream = new Common::MemoryReadStream(audioRes->getUnsafeDataAt(0), audioRes->size(), DisposeAfterUse::NO);
// Calculate samplelen from WAVE header
int waveSize = 0, waveRate = 0;
@@ -420,9 +420,9 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
waveStream->seek(0, SEEK_SET);
audioStream = Audio::makeWAVStream(waveStream, DisposeAfterUse::YES);
- } else if (audioRes->size > 4 && READ_BE_UINT32(audioRes->data) == MKTAG('F','O','R','M')) {
+ } else if (audioRes->size() > 4 && audioRes->getUint32BEAt(0) == MKTAG('F','O','R','M')) {
// AIFF detected
- Common::SeekableReadStream *waveStream = new Common::MemoryReadStream(audioRes->data, audioRes->size, DisposeAfterUse::NO);
+ Common::SeekableReadStream *waveStream = new Common::MemoryReadStream(audioRes->getUnsafeDataAt(0), audioRes->size(), DisposeAfterUse::NO);
Audio::RewindableAudioStream *rewindStream = Audio::makeAIFFStream(waveStream, DisposeAfterUse::YES);
audioSeekStream = dynamic_cast<Audio::SeekableAudioStream *>(rewindStream);
@@ -430,10 +430,14 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
warning("AIFF file is not seekable");
delete rewindStream;
}
- } else if (audioRes->size > 14 && READ_BE_UINT16(audioRes->data) == 1 && READ_BE_UINT16(audioRes->data + 2) == 1
- && READ_BE_UINT16(audioRes->data + 4) == 5 && READ_BE_UINT32(audioRes->data + 10) == 0x00018051) {
+ } else if (audioRes->size() > 14 &&
+ audioRes->getUint16BEAt(0) == 1 &&
+ audioRes->getUint16BEAt(2) == 1 &&
+ audioRes->getUint16BEAt(4) == 5 &&
+ audioRes->getUint32BEAt(10) == 0x00018051) {
+
// Mac snd detected
- Common::SeekableReadStream *sndStream = new Common::MemoryReadStream(audioRes->data, audioRes->size, DisposeAfterUse::NO);
+ Common::SeekableReadStream *sndStream = new Common::MemoryReadStream(audioRes->getUnsafeDataAt(0), audioRes->size(), DisposeAfterUse::NO);
audioSeekStream = Audio::makeMacSndStream(sndStream, DisposeAfterUse::YES);
if (!audioSeekStream)
@@ -441,10 +445,10 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
} else {
// SCI1 raw audio
- size = audioRes->size;
+ size = audioRes->size();
data = (byte *)malloc(size);
assert(data);
- memcpy(data, audioRes->data, size);
+ audioRes->unsafeCopyDataTo(data);
flags = Audio::FLAG_UNSIGNED;
_audioRate = 11025;
}
diff --git a/engines/sci/sound/drivers/adlib.cpp b/engines/sci/sound/drivers/adlib.cpp
index 4f557be95e..b8e90802b2 100644
--- a/engines/sci/sound/drivers/adlib.cpp
+++ b/engines/sci/sound/drivers/adlib.cpp
@@ -31,6 +31,7 @@
#include "sci/resource.h"
#include "sci/sound/drivers/mididriver.h"
+#include "sci/util.h"
namespace Sci {
@@ -50,7 +51,7 @@ public:
kRhythmKeys = 62
};
- MidiDriver_AdLib(Audio::Mixer *mixer) :_playSwitch(true), _masterVolume(15), _rhythmKeyMap(0), _opl(0), _isOpen(false) { }
+ MidiDriver_AdLib(Audio::Mixer *mixer) :_playSwitch(true), _masterVolume(15), _rhythmKeyMap(), _opl(0), _isOpen(false) { }
virtual ~MidiDriver_AdLib() { }
// MidiDriver
@@ -70,10 +71,10 @@ public:
void setVolume(byte volume);
void playSwitch(bool play);
- bool loadResource(const byte *data, uint size);
+ bool loadResource(const SciSpan<const byte> &data);
virtual uint32 property(int prop, uint32 param);
- bool useRhythmChannel() const { return _rhythmKeyMap != NULL; }
+ bool useRhythmChannel() const { return _rhythmKeyMap; }
private:
enum ChannelID {
@@ -139,13 +140,13 @@ private:
int _masterVolume;
Channel _channels[MIDI_CHANNELS];
AdLibVoice _voices[kVoices];
- byte *_rhythmKeyMap;
+ Common::SpanOwner<SciSpan<const byte> > _rhythmKeyMap;
Common::Array<AdLibPatch> _patches;
Common::TimerManager::TimerProc _adlibTimerProc;
void *_adlibTimerParam;
- void loadInstrument(const byte *ins);
+ void loadInstrument(const SciSpan<const byte> &ins);
void voiceOn(int voice, int note, int velocity);
void voiceOff(int voice);
void setPatch(int voice, int patch);
@@ -255,7 +256,7 @@ int MidiDriver_AdLib::openAdLib(bool isSCI0) {
void MidiDriver_AdLib::close() {
delete _opl;
- delete[] _rhythmKeyMap;
+ _rhythmKeyMap.clear();
}
void MidiDriver_AdLib::setVolume(byte volume) {
@@ -346,12 +347,12 @@ void MidiDriver_AdLib::onTimer() {
}
}
-void MidiDriver_AdLib::loadInstrument(const byte *ins) {
+void MidiDriver_AdLib::loadInstrument(const SciSpan<const byte> &ins) {
AdLibPatch patch;
// Set data for the operators
for (int i = 0; i < 2; i++) {
- const byte *op = ins + i * 13;
+ const byte *op = ins.getUnsafeDataAt(i * 13, 13);
patch.op[i].kbScaleLevel = op[0] & 0x3;
patch.op[i].frequencyMult = op[1] & 0xf;
patch.op[i].attackRate = op[3] & 0xf;
@@ -589,7 +590,7 @@ void MidiDriver_AdLib::voiceOn(int voice, int note, int velocity) {
_voices[voice].age = 0;
- if ((channel == 9) && _rhythmKeyMap) {
+ if (channel == 9 && _rhythmKeyMap) {
patch = CLIP(note, 27, 88) + 101;
} else {
patch = _channels[channel].patch;
@@ -616,7 +617,7 @@ void MidiDriver_AdLib::setNote(int voice, int note, bool key) {
float delta;
int bend = _channels[channel].pitchWheel;
- if ((channel == 9) && _rhythmKeyMap) {
+ if (channel == 9 && _rhythmKeyMap) {
note = _rhythmKeyMap[CLIP(note, 27, 88) - 27];
}
@@ -756,30 +757,32 @@ void MidiDriver_AdLib::playSwitch(bool play) {
renewNotes(-1, play);
}
-bool MidiDriver_AdLib::loadResource(const byte *data, uint size) {
- if ((size != 1344) && (size != 2690) && (size != 5382)) {
- error("ADLIB: Unsupported patch format (%i bytes)", size);
+bool MidiDriver_AdLib::loadResource(const SciSpan<const byte> &data) {
+ const uint32 size = data.size();
+ if (size != 1344 && size != 2690 && size != 5382) {
+ error("ADLIB: Unsupported patch format (%u bytes)", size);
return false;
}
for (int i = 0; i < 48; i++)
- loadInstrument(data + (28 * i));
+ loadInstrument(data.subspan(28 * i));
if (size == 1344) {
byte dummy[28] = {0};
// Only 48 instruments, add dummies
for (int i = 0; i < 48; i++)
- loadInstrument(dummy);
+ loadInstrument(SciSpan<const byte>(dummy, sizeof(dummy)));
} else if (size == 2690) {
for (int i = 48; i < 96; i++)
- loadInstrument(data + 2 + (28 * i));
+ loadInstrument(data.subspan(2 + (28 * i)));
} else {
// SCI1.1 and later
- for (int i = 48; i < 190; i++)
- loadInstrument(data + (28 * i));
- _rhythmKeyMap = new byte[kRhythmKeys];
- memcpy(_rhythmKeyMap, data + 5320, kRhythmKeys);
+ for (int i = 48; i < 190; i++) {
+ loadInstrument(data.subspan(28 * i));
+ }
+
+ _rhythmKeyMap->allocateFromSpan(data.subspan(5320, kRhythmKeys));
}
return true;
@@ -802,11 +805,11 @@ int MidiPlayer_AdLib::open(ResourceManager *resMan) {
assert(resMan != NULL);
// Load up the patch.003 file, parse out the instruments
- Resource *res = resMan->findResource(ResourceId(kResourceTypePatch, 3), 0);
+ Resource *res = resMan->findResource(ResourceId(kResourceTypePatch, 3), false);
bool ok = false;
if (res) {
- ok = static_cast<MidiDriver_AdLib *>(_driver)->loadResource(res->data, res->size);
+ ok = static_cast<MidiDriver_AdLib *>(_driver)->loadResource(*res);
} else {
// Early SCI0 games have the sound bank embedded in the AdLib driver
@@ -819,13 +822,13 @@ int MidiPlayer_AdLib::open(ResourceManager *resMan) {
// Note: Funseeker's Guide also has another version of adl.drv, 8803 bytes.
// This isn't supported, but it's not really used anywhere, as that demo
// doesn't have sound anyway.
- if ((size == 5684) || (size == 5720) || (size == 5727)) {
- byte *buf = new byte[patchSize];
-
- if (f.seek(0x45a) && (f.read(buf, patchSize) == patchSize))
- ok = static_cast<MidiDriver_AdLib *>(_driver)->loadResource(buf, patchSize);
-
- delete[] buf;
+ if (size == 5684 || size == 5720 || size == 5727) {
+ ok = f.seek(0x45a);
+ if (ok) {
+ Common::SpanOwner<SciSpan<const byte> > patchData;
+ patchData->allocateFromStream(f, patchSize);
+ ok = static_cast<MidiDriver_AdLib *>(_driver)->loadResource(*patchData);
+ }
}
}
}
diff --git a/engines/sci/sound/drivers/amigamac.cpp b/engines/sci/sound/drivers/amigamac.cpp
index f5daab726e..b8b6a32214 100644
--- a/engines/sci/sound/drivers/amigamac.cpp
+++ b/engines/sci/sound/drivers/amigamac.cpp
@@ -610,7 +610,7 @@ int MidiDriver_AmigaMac::open() {
return Common::kUnknownError;
}
- Common::MemoryReadStream stream(resource->data, resource->size);
+ Common::MemoryReadStream stream(resource->toStream());
if (_isSci1) {
if (!loadInstrumentsSCI1(stream))
diff --git a/engines/sci/sound/drivers/cms.cpp b/engines/sci/sound/drivers/cms.cpp
index a222090fc8..8b92432cb9 100644
--- a/engines/sci/sound/drivers/cms.cpp
+++ b/engines/sci/sound/drivers/cms.cpp
@@ -29,6 +29,7 @@
#include "common/system.h"
#include "sci/resource.h"
+#include "sci/util.h"
namespace Sci {
@@ -72,7 +73,7 @@ private:
bool _playSwitch;
uint16 _masterVolume;
- uint8 *_patchData;
+ Common::SpanOwner<SciSpan<uint8> > _patchData;
struct Channel {
Channel()
@@ -96,7 +97,7 @@ private:
struct Voice {
Voice() : channel(0xFF), note(0xFF), sustained(0xFF), ticks(0),
- turnOffTicks(0), patchDataPtr(0), patchDataIndex(0),
+ turnOffTicks(0), patchDataPtr(), patchDataIndex(0),
amplitudeTimer(0), amplitudeModifier(0), turnOff(false),
velocity(0) {
}
@@ -106,7 +107,7 @@ private:
uint8 sustained;
uint16 ticks;
uint16 turnOffTicks;
- const uint8 *patchDataPtr;
+ SciSpan<uint8> patchDataPtr;
uint8 patchDataIndex;
uint8 amplitudeTimer;
uint8 amplitudeModifier;
@@ -172,12 +173,11 @@ int MidiDriver_CMS::open() {
return MERR_ALREADY_OPEN;
assert(_resMan);
- Resource *res = _resMan->findResource(ResourceId(kResourceTypePatch, 101), 0);
+ Resource *res = _resMan->findResource(ResourceId(kResourceTypePatch, 101), false);
if (!res)
return -1;
- _patchData = new uint8[res->size];
- memcpy(_patchData, res->data, res->size);
+ _patchData->allocateFromSpan(*res);
for (uint i = 0; i < ARRAYSIZE(_channel); ++i)
_channel[i] = Channel();
@@ -218,9 +218,9 @@ int MidiDriver_CMS::open() {
void MidiDriver_CMS::close() {
_mixer->stopHandle(_mixerSoundHandle);
- delete[] _patchData;
+ _patchData.clear();
delete _cms;
- _cms = 0;
+ _cms = nullptr;
}
void MidiDriver_CMS::send(uint32 b) {
@@ -295,7 +295,7 @@ void MidiDriver_CMS::voiceOn(int voiceNr, int note, int velocity) {
voice.amplitudeTimer = 0;
voice.ticks = 0;
voice.turnOffTicks = 0;
- voice.patchDataPtr = _patchData + READ_LE_UINT16(&_patchData[_channel[voice.channel].patch * 2]);
+ voice.patchDataPtr = _patchData->subspan(_patchData->getUint16LEAt(_channel[voice.channel].patch * 2));
if (velocity)
velocity = _velocityTable[(velocity >> 3)];
voice.velocity = velocity;
@@ -798,7 +798,7 @@ public:
_driver->setTimerCallback(0, 0);
_driver->close();
delete _driver;
- _driver = 0;
+ _driver = nullptr;
}
bool hasRhythmChannel() const { return false; }
diff --git a/engines/sci/sound/drivers/fb01.cpp b/engines/sci/sound/drivers/fb01.cpp
index db9f7558e2..3f3f581ee2 100644
--- a/engines/sci/sound/drivers/fb01.cpp
+++ b/engines/sci/sound/drivers/fb01.cpp
@@ -24,6 +24,7 @@
#include "sci/resource.h"
#include "sci/sound/drivers/mididriver.h"
+#include "sci/util.h"
#include "common/file.h"
#include "common/system.h"
@@ -71,8 +72,8 @@ private:
void setVoiceParam(byte voice, byte param, byte value);
void setSystemParam(byte sysChan, byte param, byte value);
- void sendVoiceData(byte instrument, const byte *data);
- void sendBanks(const byte *data, int size);
+ void sendVoiceData(byte instrument, const SciSpan<const byte> &data);
+ void sendBanks(const SciSpan<const byte> &data);
void storeVoiceData(byte instrument, byte bank, byte index);
void initVoices();
@@ -442,22 +443,22 @@ void MidiPlayer_Fb01::setTimerCallback(void *timer_param, Common::TimerManager::
_driver->setTimerCallback(this, midiTimerCallback);
}
-void MidiPlayer_Fb01::sendBanks(const byte *data, int size) {
- if (size < 3072)
+void MidiPlayer_Fb01::sendBanks(const SciSpan<const byte> &data) {
+ if (data.size() < 3072)
error("Failed to read FB-01 patch");
// SSCI sends bank dumps containing 48 instruments at once. We cannot do that
// due to the limited maximum SysEx length. Instead we send the instruments
// one by one and store them in the banks.
for (int i = 0; i < 48; i++) {
- sendVoiceData(0, data + i * 64);
+ sendVoiceData(0, data.subspan(i * 64));
storeVoiceData(0, 0, i);
}
// Send second bank if available
- if ((size >= 6146) && (READ_BE_UINT16(data + 3072) == 0xabcd)) {
+ if (data.size() >= 6146 && data.getUint16BEAt(3072) == 0xabcd) {
for (int i = 0; i < 48; i++) {
- sendVoiceData(0, data + 3074 + i * 64);
+ sendVoiceData(0, data.subspan(3074 + i * 64));
storeVoiceData(0, 1, i);
}
}
@@ -479,10 +480,10 @@ int MidiPlayer_Fb01::open(ResourceManager *resMan) {
// Turn off memory protection
setSystemParam(0, 0x21, 0);
- Resource *res = resMan->findResource(ResourceId(kResourceTypePatch, 2), 0);
+ Resource *res = resMan->findResource(ResourceId(kResourceTypePatch, 2), false);
if (res) {
- sendBanks(res->data, res->size);
+ sendBanks(*res);
} else {
// Early SCI0 games have the sound bank embedded in the IMF driver.
// Note that these games didn't actually support the FB-01 as a device,
@@ -494,27 +495,23 @@ int MidiPlayer_Fb01::open(ResourceManager *resMan) {
Common::File f;
if (f.open("IMF.DRV")) {
- int size = f.size();
- byte *buf = new byte[size];
-
- f.read(buf, size);
+ Common::SpanOwner<SciSpan<const byte> > buf;
+ buf->allocateFromStream(f);
// Search for start of sound bank
- int offset;
- for (offset = 0; offset < size; ++offset) {
- if (!strncmp((char *)buf + offset, "SIERRA ", 7))
+ uint offset;
+ for (offset = 0; offset < buf->size() - 7; ++offset) {
+ if (!strncmp((const char *)buf->getUnsafeDataAt(offset, 7), "SIERRA ", 7))
break;
}
// Skip to voice data
offset += 0x20;
- if (offset >= size)
+ if (offset >= buf->size())
error("Failed to locate start of FB-01 sound bank");
- sendBanks(buf + offset, size - offset);
-
- delete[] buf;
+ sendBanks(buf->subspan(offset));
} else
error("Failed to open IMF.DRV");
}
@@ -553,7 +550,7 @@ void MidiPlayer_Fb01::setSystemParam(byte sysChan, byte param, byte value) {
sysEx(_sysExBuf, 6);
}
-void MidiPlayer_Fb01::sendVoiceData(byte instrument, const byte *data) {
+void MidiPlayer_Fb01::sendVoiceData(byte instrument, const SciSpan<const byte> &data) {
_sysExBuf[2] = 0x00;
_sysExBuf[3] = 0x08 | instrument;
_sysExBuf[4] = 0x00;
diff --git a/engines/sci/sound/drivers/fmtowns.cpp b/engines/sci/sound/drivers/fmtowns.cpp
index f6dbac2a67..270843c396 100644
--- a/engines/sci/sound/drivers/fmtowns.cpp
+++ b/engines/sci/sound/drivers/fmtowns.cpp
@@ -101,7 +101,7 @@ public:
~MidiDriver_FMTowns();
int open();
- void loadInstruments(const uint8 *data);
+ void loadInstruments(const SciSpan<const uint8> &data);
bool isOpen() const { return _isOpen; }
void close();
@@ -461,14 +461,18 @@ int MidiDriver_FMTowns::open() {
return 0;
}
-void MidiDriver_FMTowns::loadInstruments(const uint8 *data) {
- if (data) {
- data += 6;
- for (int i = 0; i < 128; i++) {
- _intf->callback(5, 0, i, data);
- data += 48;
+void MidiDriver_FMTowns::loadInstruments(const SciSpan<const uint8> &data) {
+ enum {
+ fmDataSize = 48
+ };
+
+ if (data.size()) {
+ SciSpan<const uint8> instrumentData = data.subspan(6);
+ for (int i = 0; i < 128; i++, instrumentData += fmDataSize) {
+ _intf->callback(5, 0, i, instrumentData.getUnsafeDataAt(0, fmDataSize));
}
}
+
_intf->callback(70, 3);
property(MIDI_PROP_MASTER_VOLUME, _masterVolume);
}
@@ -622,7 +626,7 @@ int MidiPlayer_FMTowns::open(ResourceManager *resMan) {
if (_townsDriver) {
result = _townsDriver->open();
if (!result && _version == SCI_VERSION_1_LATE)
- _townsDriver->loadInstruments((resMan->findResource(ResourceId(kResourceTypePatch, 8), true))->data);
+ _townsDriver->loadInstruments(*resMan->findResource(ResourceId(kResourceTypePatch, 8), false));
}
return result;
}
diff --git a/engines/sci/sound/drivers/midi.cpp b/engines/sci/sound/drivers/midi.cpp
index 7b2b102284..b9035b07ea 100644
--- a/engines/sci/sound/drivers/midi.cpp
+++ b/engines/sci/sound/drivers/midi.cpp
@@ -70,18 +70,18 @@ public:
void playSwitch(bool play);
private:
- bool isMt32GmPatch(const byte *data, int size);
- void readMt32GmPatch(const byte *data, int size);
- void readMt32Patch(const byte *data, int size);
+ bool isMt32GmPatch(const SciSpan<const byte> &data);
+ void readMt32GmPatch(const SciSpan<const byte> &data);
+ void readMt32Patch(const SciSpan<const byte> &data);
void readMt32DrvData();
- void mapMt32ToGm(byte *data, size_t size);
+ void mapMt32ToGm(const SciSpan<const byte> &data);
uint8 lookupGmInstrument(const char *iname);
uint8 lookupGmRhythmKey(const char *iname);
uint8 getGmInstrument(const Mt32ToGmMap &Mt32Ins);
- void sendMt32SysEx(const uint32 addr, Common::SeekableReadStream *str, int len, bool noDelay);
- void sendMt32SysEx(const uint32 addr, const byte *buf, int len, bool noDelay);
+ void sendMt32SysEx(const uint32 addr, Common::SeekableReadStream &data, const int len, bool noDelay);
+ void sendMt32SysEx(const uint32 addr, const SciSpan<const byte> &data, bool noDelay);
void setMt32Volume(byte volume);
void resetMt32();
@@ -382,8 +382,9 @@ int MidiPlayer_Midi::getVolume() {
void MidiPlayer_Midi::setReverb(int8 reverb) {
assert(reverb < kReverbConfigNr);
- if (_hasReverb && (_reverb != reverb))
- sendMt32SysEx(0x100001, _reverbConfig[reverb], 3, true);
+ if (_hasReverb && _reverb != reverb) {
+ sendMt32SysEx(0x100001, SciSpan<const byte>(_reverbConfig[reverb], 3), true);
+ }
_reverb = reverb;
}
@@ -398,7 +399,9 @@ void MidiPlayer_Midi::playSwitch(bool play) {
}
}
-bool MidiPlayer_Midi::isMt32GmPatch(const byte *data, int size) {
+bool MidiPlayer_Midi::isMt32GmPatch(const SciSpan<const byte> &data) {
+ uint32 size = data.size();
+
// WORKAROUND: Some Mac games (e.g. LSL5) may have an extra byte at the
// end, so compensate for that here - bug #6725.
if (size == 16890)
@@ -419,21 +422,21 @@ bool MidiPlayer_Midi::isMt32GmPatch(const byte *data, int size) {
// First, check for a GM patch. The presence of MIDI data after the
// initial 1153 + 2 bytes indicates a GM patch
- if (READ_LE_UINT16(data + 1153) + 1155 == size)
+ if (data.getUint16LEAt(1153) + 1155U == size)
isMt32Gm = true;
// Now check for a regular MT-32 patch. Check readMt32Patch() below for
// more info.
// 491 = 20 + 20 + 20 + 2 + 1 + 11 + 3 * 11 + 256 + 128
byte timbresNr = data[491];
- int pos = 492 + 246 * timbresNr;
+ uint pos = 492 + 246 * timbresNr;
// Patches 49-96
- if ((size >= (pos + 386)) && (READ_BE_UINT16(data + pos) == 0xabcd))
+ if (size >= pos + 386 && data.getUint16BEAt(pos) == 0xabcd)
pos += 386; // 256 + 128 + 2
// Rhythm key map + partial reserve
- if ((size >= (pos + 267)) && (READ_BE_UINT16(data + pos) == 0xdcba))
+ if (size >= pos + 267 && data.getUint16BEAt(pos) == 0xdcba)
pos += 267; // 256 + 9 + 2
if (size == pos)
@@ -445,7 +448,7 @@ bool MidiPlayer_Midi::isMt32GmPatch(const byte *data, int size) {
return isMt32Gm;
}
-void MidiPlayer_Midi::sendMt32SysEx(const uint32 addr, Common::SeekableReadStream *str, int len, bool noDelay = false) {
+void MidiPlayer_Midi::sendMt32SysEx(const uint32 addr, Common::SeekableReadStream &stream, int len, bool noDelay = false) {
if (len + 8 > kMaxSysExSize) {
warning("SysEx message exceed maximum size; ignoring");
return;
@@ -457,8 +460,7 @@ void MidiPlayer_Midi::sendMt32SysEx(const uint32 addr, Common::SeekableReadStrea
_sysExBuf[5] = (addr >> 8) & 0xff;
_sysExBuf[6] = addr & 0xff;
- for (int i = 0; i < len; i++)
- _sysExBuf[7 + i] = str->readByte();
+ stream.read(_sysExBuf + 7, len);
for (int i = 4; i < 7 + len; i++)
chk -= _sysExBuf[i];
@@ -471,81 +473,82 @@ void MidiPlayer_Midi::sendMt32SysEx(const uint32 addr, Common::SeekableReadStrea
sysEx(_sysExBuf, len + 8);
}
-void MidiPlayer_Midi::sendMt32SysEx(const uint32 addr, const byte *buf, int len, bool noDelay = false) {
- Common::MemoryReadStream *str = new Common::MemoryReadStream(buf, len);
- sendMt32SysEx(addr, str, len, noDelay);
- delete str;
+void MidiPlayer_Midi::sendMt32SysEx(const uint32 addr, const SciSpan<const byte> &buf, bool noDelay = false) {
+ Common::MemoryReadStream stream(buf.toStream());
+ sendMt32SysEx(addr, stream, buf.size(), noDelay);
}
-void MidiPlayer_Midi::readMt32Patch(const byte *data, int size) {
+
+void MidiPlayer_Midi::readMt32Patch(const SciSpan<const byte> &data) {
// MT-32 patch contents:
- // - 20 bytes unkown
- // - 20 bytes before-SysEx message
- // - 20 bytes goodbye SysEx message
- // - 2 bytes volume
- // - 1 byte reverb
- // - 11 bytes reverb Sysex message
- // - 3 * 11 reverb data
- // - 256 + 128 bytes patches 1-48
+ // - 0-19 after-SysEx message
+ // - 20-39 before-SysEx message
+ // - 40-59 goodbye SysEx message
+ // - 60-61 volume
+ // - 62 reverb
+ // - 63-73 reverb Sysex message
+ // - 74-106 [3 * 11] reverb data
+ // - 107-490 [256 + 128] patches 1-48
// --> total: 491 bytes
- // - 1 byte number of timbres (64 max)
- // - 246 * timbres timbre data
- // - 2 bytes flag (0xabcd)
- // - 256 + 128 bytes patches 49-96
- // - 2 bytes flag (0xdcba)
- // - 256 bytes rhythm key map
- // - 9 bytes partial reserve
+ // - 491 number of timbres (64 max)
+ // - 492..n [246 * number of timbres] timbre data
+ // - n-n+1 flag (0xabcd)
+ // - n+2-n+385 [256 + 128] patches 49-96
+ // - n+386-n+387 flag (0xdcba)
+ // - n+388-n+643 rhythm key map
+ // - n+644-n+652 partial reserve
- Common::MemoryReadStream *str = new Common::MemoryReadStream(data, size);
+ Common::MemoryReadStream stream(data.toStream());
// Send before-SysEx text
- str->seek(20);
- sendMt32SysEx(0x200000, str, 20);
+ stream.seek(20);
+ sendMt32SysEx(0x200000, stream, 20);
// Save goodbye message
- str->read(_goodbyeMsg, 20);
+ assert(sizeof(_goodbyeMsg) == 20);
+ stream.read(_goodbyeMsg, 20);
- byte volume = CLIP<uint16>(str->readUint16LE(), 0, 100);
+ const uint8 volume = MIN<uint16>(stream.readUint16LE(), 100);
setMt32Volume(volume);
// Reverb default only used in (roughly) SCI0/SCI01
- byte reverb = str->readByte();
+ byte reverb = stream.readByte();
_hasReverb = true;
// Skip reverb SysEx message
- str->seek(11, SEEK_CUR);
+ stream.seek(11, SEEK_CUR);
// Read reverb data (stored vertically - patch #3117434)
for (int j = 0; j < 3; ++j) {
for (int i = 0; i < kReverbConfigNr; i++) {
- _reverbConfig[i][j] = str->readByte();
+ _reverbConfig[i][j] = stream.readByte();
}
}
// Patches 1-48
- sendMt32SysEx(0x50000, str, 256);
- sendMt32SysEx(0x50200, str, 128);
+ sendMt32SysEx(0x50000, stream, 256);
+ sendMt32SysEx(0x50200, stream, 128);
// Timbres
- byte timbresNr = str->readByte();
+ const uint8 timbresNr = stream.readByte();
for (int i = 0; i < timbresNr; i++)
- sendMt32SysEx(0x80000 + (i << 9), str, 246);
+ sendMt32SysEx(0x80000 + (i << 9), stream, 246);
- uint16 flag = str->readUint16BE();
+ uint16 flag = stream.readUint16BE();
- if (!str->eos() && (flag == 0xabcd)) {
+ if (!stream.eos() && flag == 0xabcd) {
// Patches 49-96
- sendMt32SysEx(0x50300, str, 256);
- sendMt32SysEx(0x50500, str, 128);
- flag = str->readUint16BE();
+ sendMt32SysEx(0x50300, stream, 256);
+ sendMt32SysEx(0x50500, stream, 128);
+ flag = stream.readUint16BE();
}
- if (!str->eos() && (flag == 0xdcba)) {
+ if (!stream.eos() && flag == 0xdcba) {
// Rhythm key map
- sendMt32SysEx(0x30110, str, 256);
+ sendMt32SysEx(0x30110, stream, 256);
// Partial reserve
- sendMt32SysEx(0x100004, str, 9);
+ sendMt32SysEx(0x100004, stream, 9);
}
// Reverb for SCI0
@@ -553,16 +556,15 @@ void MidiPlayer_Midi::readMt32Patch(const byte *data, int size) {
setReverb(reverb);
// Send after-SysEx text
- str->seek(0);
- sendMt32SysEx(0x200000, str, 20);
+ stream.seek(0);
+ sendMt32SysEx(0x200000, stream, 20);
// Send the mystery SysEx
- sendMt32SysEx(0x52000a, (const byte *)"\x16\x16\x16\x16\x16\x16", 6);
-
- delete str;
+ Common::MemoryReadStream mystery((const byte *)"\x16\x16\x16\x16\x16\x16", 6);
+ sendMt32SysEx(0x52000a, mystery, 6);
}
-void MidiPlayer_Midi::readMt32GmPatch(const byte *data, int size) {
+void MidiPlayer_Midi::readMt32GmPatch(const SciSpan<const byte> &data) {
// GM patch contents:
// - 128 bytes patch map
// - 128 bytes key shift
@@ -573,21 +575,21 @@ void MidiPlayer_Midi::readMt32GmPatch(const byte *data, int size) {
// - 512 bytes velocity map
// --> total: 1153 bytes
- memcpy(_patchMap, data, 128);
- memcpy(_keyShift, data + 128, 128);
- memcpy(_volAdjust, data + 256, 128);
- memcpy(_percussionMap, data + 384, 128);
+ data.subspan(0, sizeof(_patchMap)).unsafeCopyDataTo(_patchMap);
+ data.subspan(128, sizeof(_keyShift)).unsafeCopyDataTo(_keyShift);
+ data.subspan(256, sizeof(_volAdjust)).unsafeCopyDataTo(_volAdjust);
+ data.subspan(384, sizeof(_percussionMap)).unsafeCopyDataTo(_percussionMap);
_channels[MIDI_RHYTHM_CHANNEL].volAdjust = data[512];
- memcpy(_velocityMapIdx, data + 513, 128);
- memcpy(_velocityMap, data + 641, 512);
+ data.subspan(513, sizeof(_velocityMapIdx)).unsafeCopyDataTo(_velocityMapIdx);
+ data.subspan(641, sizeof(_velocityMap)).unsafeCopyDataTo(_velocityMap);
- uint16 midiSize = READ_LE_UINT16(data + 1153);
+ uint16 midiSize = data.getUint16LEAt(1153);
if (midiSize > 0) {
- if (size < midiSize + 1155)
+ if (data.size() < midiSize + 1155U)
error("Failed to read MIDI data");
- const byte *midi = data + 1155;
+ const SciSpan<const byte> midi = data.subspan(1155, midiSize);
byte command = 0;
uint i = 0;
@@ -599,15 +601,16 @@ void MidiPlayer_Midi::readMt32GmPatch(const byte *data, int size) {
switch (command & 0xf0) {
case 0xf0: {
- const byte *sysExEnd = (const byte *)memchr(midi + i, 0xf7, midiSize - i);
+ const byte *sysExStart = midi.getUnsafeDataAt(i, midiSize - i);
+ const byte *sysExEnd = (const byte *)memchr(sysExStart, 0xf7, midiSize - i);
if (!sysExEnd)
error("Failed to find end of sysEx");
- int len = sysExEnd - (midi + i);
- sysEx(midi + i, len);
+ int len = sysExEnd - sysExStart;
+ sysEx(sysExStart, len);
- i += len + 1; // One more for the 0x7f
+ i += len + 1; // One more for the 0xf7
break;
}
case 0x80:
@@ -656,13 +659,13 @@ void MidiPlayer_Midi::readMt32DrvData() {
f.seek(-2, SEEK_CUR);
// Send before-SysEx text
- sendMt32SysEx(0x200000, &f, 20);
+ sendMt32SysEx(0x200000, f, 20);
if (size != 2271) {
// Send after-SysEx text (SSCI sends this before every song).
// There aren't any SysEx calls in old drivers, so this can
// be sent right after the before-SysEx text.
- sendMt32SysEx(0x200000, &f, 20);
+ sendMt32SysEx(0x200000, f, 20);
} else {
// Skip the after-SysEx text in the newer patch version, we'll send
// it after the SysEx messages are sent.
@@ -696,14 +699,14 @@ void MidiPlayer_Midi::readMt32DrvData() {
f.skip(2235); // skip driver code
// Patches 1-48
- sendMt32SysEx(0x50000, &f, 256);
- sendMt32SysEx(0x50200, &f, 128);
+ sendMt32SysEx(0x50000, f, 256);
+ sendMt32SysEx(0x50200, f, 128);
setReverb(reverb);
// Send the after-SysEx text
f.seek(0x3d);
- sendMt32SysEx(0x200000, &f, 20);
+ sendMt32SysEx(0x200000, f, 20);
} else {
byte reverbSysEx[13];
// This old driver should have a full reverb SysEx
@@ -775,11 +778,11 @@ uint8 MidiPlayer_Midi::getGmInstrument(const Mt32ToGmMap &Mt32Ins) {
return Mt32Ins.gmInstr;
}
-void MidiPlayer_Midi::mapMt32ToGm(byte *data, size_t size) {
+void MidiPlayer_Midi::mapMt32ToGm(const SciSpan<const byte> &data) {
// FIXME: Clean this up
int memtimbres, patches;
uint8 group, number, keyshift, /*finetune,*/ bender_range;
- uint8 *patchpointer;
+ SciSpan<const byte> patchpointer;
uint32 pos;
int i;
@@ -791,10 +794,10 @@ void MidiPlayer_Midi::mapMt32ToGm(byte *data, size_t size) {
for (i = 0; i < 128; i++)
_percussionMap[i] = Mt32PresetRhythmKeymap[i];
- memtimbres = *(data + 0x1eb);
+ memtimbres = data[0x1eb];
pos = 0x1ec + memtimbres * 0xf6;
- if (size > pos && ((0x100 * *(data + pos) + *(data + pos + 1)) == 0xabcd)) {
+ if (data.size() > pos && data.getUint16BEAt(pos) == 0xabcd) {
patches = 96;
pos += 2 + 8 * 48;
} else {
@@ -807,18 +810,18 @@ void MidiPlayer_Midi::mapMt32ToGm(byte *data, size_t size) {
debugC(kDebugLevelSound, "\n[MT32-to-GM] Mapping patches..");
for (i = 0; i < patches; i++) {
- char name[11];
+ Common::String name;
if (i < 48)
- patchpointer = data + 0x6b + 8 * i;
+ patchpointer = data.subspan(0x6b + 8 * i);
else
- patchpointer = data + 0x1ec + 8 * (i - 48) + memtimbres * 0xf6 + 2;
+ patchpointer = data.subspan(0x1ec + 8 * (i - 48) + memtimbres * 0xf6 + 2);
- group = *patchpointer;
- number = *(patchpointer + 1);
- keyshift = *(patchpointer + 2);
- //finetune = *(patchpointer + 3);
- bender_range = *(patchpointer + 4);
+ group = patchpointer[0];
+ number = patchpointer[1];
+ keyshift = patchpointer[2];
+ //finetune = patchpointer[3];
+ bender_range = patchpointer[4];
debugCN(kDebugLevelSound, " [%03d] ", i);
@@ -832,10 +835,9 @@ void MidiPlayer_Midi::mapMt32ToGm(byte *data, size_t size) {
break;
case 2:
if (number < memtimbres) {
- strncpy(name, (const char *)data + 0x1ec + number * 0xf6, 10);
- name[10] = 0;
- _patchMap[i] = lookupGmInstrument(name);
- debugCN(kDebugLevelSound, "%s -> ", name);
+ name = data.getStringAt(0x1ec + number * 0xf6, 10);
+ _patchMap[i] = lookupGmInstrument(name.c_str());
+ debugCN(kDebugLevelSound, "%s -> ", name.c_str());
} else {
_patchMap[i] = 0xff;
debugCN(kDebugLevelSound, "[Invalid] -> ");
@@ -865,21 +867,19 @@ void MidiPlayer_Midi::mapMt32ToGm(byte *data, size_t size) {
_pitchBendRange[i] = CLIP<uint8>(bender_range, 0, 24);
}
- if (size > pos && ((0x100 * *(data + pos) + *(data + pos + 1)) == 0xdcba)) {
+ if (data.size() > pos && data.getUint16BEAt(pos) == 0xdcba) {
debugC(kDebugLevelSound, "\n[MT32-to-GM] Mapping percussion..");
for (i = 0; i < 64; i++) {
- number = *(data + pos + 4 * i + 2);
+ number = data[pos + 4 * i + 2];
byte ins = i + 24;
debugCN(kDebugLevelSound, " [%03d] ", ins);
if (number < 64) {
- char name[11];
- strncpy(name, (const char *)data + 0x1ec + number * 0xf6, 10);
- name[10] = 0;
- debugCN(kDebugLevelSound, "%s -> ", name);
- _percussionMap[ins] = lookupGmRhythmKey(name);
+ Common::String name = data.getStringAt(0x1ec + number * 0xf6, 10);
+ debugCN(kDebugLevelSound, "%s -> ", name.c_str());
+ _percussionMap[ins] = lookupGmRhythmKey(name.c_str());
} else {
if (number < 94) {
debugCN(kDebugLevelSound, "%s -> ", Mt32RhythmTimbreMaps[number - 64].name);
@@ -897,17 +897,19 @@ void MidiPlayer_Midi::mapMt32ToGm(byte *data, size_t size) {
debugC(kDebugLevelSound, "%s", GmPercussionNames[_percussionMap[ins]]);
#endif
- _percussionVelocityScale[ins] = *(data + pos + 4 * i + 3) * 127 / 100;
+ _percussionVelocityScale[ins] = data[pos + 4 * i + 3] * 127 / 100;
}
}
}
void MidiPlayer_Midi::setMt32Volume(byte volume) {
- sendMt32SysEx(0x100016, &volume, 1);
+ Common::MemoryReadStream s(&volume, 1);
+ sendMt32SysEx(0x100016, s, 1);
}
void MidiPlayer_Midi::resetMt32() {
- sendMt32SysEx(0x7f0000, (const byte *)"\x01\x00", 2, true);
+ Common::MemoryReadStream s((const byte *)"\x01\x00", 2);
+ sendMt32SysEx(0x7f0000, s, 2, true);
// This seems to require a longer delay than usual
g_system->delayMillis(150);
@@ -937,11 +939,11 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {
_percussionVelocityScale[i] = 127;
}
- Resource *res = NULL;
+ Resource *res = nullptr;
if (g_sci && g_sci->_features->useAltWinGMSound()) {
- res = resMan->findResource(ResourceId(kResourceTypePatch, 4), 0);
- if (!(res && isMt32GmPatch(res->data, res->size))) {
+ res = resMan->findResource(ResourceId(kResourceTypePatch, 4), false);
+ if (!res || !isMt32GmPatch(*res)) {
// Don't do any mapping when a Windows alternative track is selected
// and no MIDI patch is available
_useMT32Track = false;
@@ -953,15 +955,15 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {
// MT-32
resetMt32();
- res = resMan->findResource(ResourceId(kResourceTypePatch, 1), 0);
+ res = resMan->findResource(ResourceId(kResourceTypePatch, 1), false);
if (res) {
- if (isMt32GmPatch(res->data, res->size)) {
- readMt32GmPatch(res->data, res->size);
+ if (isMt32GmPatch(*res)) {
+ readMt32GmPatch(*res);
// Note that _goodbyeMsg is not zero-terminated
memcpy(_goodbyeMsg, " ScummVM ", 20);
} else {
- readMt32Patch(res->data, res->size);
+ readMt32Patch(*res);
}
} else {
// Early SCI0 games have the sound bank embedded in the MT-32 driver
@@ -969,22 +971,22 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {
}
} else {
// General MIDI
- res = resMan->findResource(ResourceId(kResourceTypePatch, 4), 0);
+ res = resMan->findResource(ResourceId(kResourceTypePatch, 4), false);
- if (res && isMt32GmPatch(res->data, res->size)) {
+ if (res && isMt32GmPatch(*res)) {
// There is a GM patch
- readMt32GmPatch(res->data, res->size);
+ readMt32GmPatch(*res);
if (g_sci && g_sci->_features->useAltWinGMSound()) {
// Always use the GM track if an alternative GM Windows soundtrack is selected
_useMT32Track = false;
} else {
// Detect the format of patch 1, so that we know what play mask to use
- res = resMan->findResource(ResourceId(kResourceTypePatch, 1), 0);
+ res = resMan->findResource(ResourceId(kResourceTypePatch, 1), false);
if (!res)
_useMT32Track = false;
else
- _useMT32Track = !isMt32GmPatch(res->data, res->size);
+ _useMT32Track = !isMt32GmPatch(*res);
// Check if the songs themselves have a GM track
if (!_useMT32Track) {
@@ -1013,17 +1015,17 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {
_velocityMap[3][i] = 0x20 + (i - 1) / 2;
}
- res = resMan->findResource(ResourceId(kResourceTypePatch, 1), 0);
+ res = resMan->findResource(ResourceId(kResourceTypePatch, 1), false);
if (res) {
- if (!isMt32GmPatch(res->data, res->size)) {
- mapMt32ToGm(res->data, res->size);
+ if (!isMt32GmPatch(*res)) {
+ mapMt32ToGm(*res);
} else {
if (getSciVersion() < SCI_VERSION_3) {
error("MT-32 patch has wrong type");
} else {
// Happens in the SCI3 interactive demo of Lighthouse
- warning("TODO: Ignoring new SCI3 type of MT-32 patch for now (size = %d)", res->size);
+ warning("TODO: Ignoring new SCI3 type of MT-32 patch for now (size = %lu)", res->size());
}
}
} else {
@@ -1053,7 +1055,7 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {
void MidiPlayer_Midi::close() {
if (_isMt32) {
// Send goodbye message
- sendMt32SysEx(0x200000, _goodbyeMsg, 20, true);
+ sendMt32SysEx(0x200000, SciSpan<const byte>(_goodbyeMsg, 20), true);
}
_driver->close();
diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp
index 21f95f17e0..20688ca351 100644
--- a/engines/sci/sound/midiparser_sci.cpp
+++ b/engines/sci/sound/midiparser_sci.cpp
@@ -129,7 +129,7 @@ byte MidiParser_SCI::midiGetNextChannel(long ticker) {
if (_track->channels[i].time == -1) // channel ended
continue;
SoundResource::Channel *curChannel = &_track->channels[i];
- if (curChannel->curPos >= curChannel->size)
+ if (curChannel->curPos >= curChannel->data.size())
continue;
next = curChannel->data[curChannel->curPos]; // when the next event should occur
if (next == 0xF8) // 0xF8 means 240 ticks delay
@@ -151,7 +151,7 @@ byte *MidiParser_SCI::midiMixChannels() {
_track->channels[i].time = 0;
_track->channels[i].prev = 0;
_track->channels[i].curPos = 0;
- totalSize += _track->channels[i].size;
+ totalSize += _track->channels[i].data.size();
}
byte *outData = new byte[totalSize * 2]; // FIXME: creates overhead and still may be not enough to hold all data
@@ -228,9 +228,9 @@ byte *MidiParser_SCI::midiMixChannels() {
// certain channels from that data.
byte *MidiParser_SCI::midiFilterChannels(int channelMask) {
SoundResource::Channel *channel = &_track->channels[0];
- byte *channelData = channel->data;
- byte *channelDataEnd = channel->data + channel->size;
- byte *outData = new byte[channel->size + 5];
+ SciSpan<const byte>::const_iterator channelData = channel->data.cbegin();
+ SciSpan<const byte>::const_iterator channelDataEnd = channel->data.cend();
+ byte *outData = new byte[channel->data.size() + 5];
byte curChannel = 15, curByte, curDelta;
byte command = 0, lastCommand = 0;
int delta = 0;
@@ -239,7 +239,7 @@ byte *MidiParser_SCI::midiFilterChannels(int channelMask) {
_mixedData = outData;
- while (channelData < channelDataEnd) {
+ while (channelData != channelDataEnd) {
curDelta = *channelData++;
if (curDelta == 0xF8) {
delta += 240;
@@ -804,7 +804,7 @@ byte MidiParser_SCI::getSongReverb() {
for (int i = 0; i < _track->channelCount; i++) {
SoundResource::Channel &channel = _track->channels[i];
// Peek ahead in the control channel to get the default reverb setting
- if (channel.number == 15 && channel.size >= 7)
+ if (channel.number == 15 && channel.data.size() >= 7)
return channel.data[6];
}
}
diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index 488bd0360c..f78f1466af 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -345,16 +345,16 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) {
if (track) {
// Play digital sample
if (track->digitalChannelNr != -1) {
- byte *channelData = track->channels[track->digitalChannelNr].data;
+ const SciSpan<const byte> &channelData = track->channels[track->digitalChannelNr].data;
delete pSnd->pStreamAud;
byte flags = Audio::FLAG_UNSIGNED;
// Amiga SCI1 games had signed sound data
if (_soundVersion >= SCI_VERSION_1_EARLY && g_sci->getPlatform() == Common::kPlatformAmiga)
flags = 0;
int endPart = track->digitalSampleEnd > 0 ? (track->digitalSampleSize - track->digitalSampleEnd) : 0;
- pSnd->pStreamAud = Audio::makeRawStream(channelData + track->digitalSampleStart,
- track->digitalSampleSize - track->digitalSampleStart - endPart,
- track->digitalSampleRate, flags, DisposeAfterUse::NO);
+ const uint size = track->digitalSampleSize - track->digitalSampleStart - endPart;
+ pSnd->pStreamAud = Audio::makeRawStream(channelData.getUnsafeDataAt(track->digitalSampleStart),
+ size, track->digitalSampleRate, flags, DisposeAfterUse::NO);
assert(pSnd->pStreamAud);
delete pSnd->pLoopStream;
pSnd->pLoopStream = 0;
diff --git a/engines/sci/sound/sync.cpp b/engines/sci/sound/sync.cpp
index 4e75dab725..90567e8c90 100644
--- a/engines/sci/sound/sync.cpp
+++ b/engines/sci/sound/sync.cpp
@@ -50,14 +50,14 @@ void Sync::start(const ResourceId id, const reg_t syncObjAddr) {
}
void Sync::next(const reg_t syncObjAddr) {
- if (_resource && (_offset < _resource->size - 1)) {
+ if (_resource && (_offset < _resource->size() - 1)) {
int16 syncCue = -1;
- int16 syncTime = (int16)READ_SCI11ENDIAN_UINT16(_resource->data + _offset);
+ int16 syncTime = _resource->getInt16SEAt(_offset);
_offset += 2;
- if ((syncTime != -1) && (_offset < _resource->size - 1)) {
- syncCue = (int16)READ_SCI11ENDIAN_UINT16(_resource->data + _offset);
+ if ((syncTime != -1) && (_offset < _resource->size() - 1)) {
+ syncCue = _resource->getInt16SEAt(_offset);
_offset += 2;
}
diff --git a/engines/sci/util.cpp b/engines/sci/util.cpp
index ccec41a1ab..095c46281a 100644
--- a/engines/sci/util.cpp
+++ b/engines/sci/util.cpp
@@ -20,8 +20,6 @@
*
*/
-#include "common/endian.h"
-
#include "sci/util.h"
#include "sci/sci.h"
diff --git a/engines/sci/util.h b/engines/sci/util.h
index b0fee5151e..e8b60adf9c 100644
--- a/engines/sci/util.h
+++ b/engines/sci/util.h
@@ -23,7 +23,13 @@
#ifndef SCI_UTIL_H
#define SCI_UTIL_H
+#include "common/span.h"
+#include "common/endian.h"
+#include "common/file.h"
+#include "common/memstream.h"
#include "common/scummsys.h"
+#include "common/str.h"
+#include "common/textconsole.h"
namespace Sci {
@@ -40,11 +46,260 @@ void WRITE_SCI11ENDIAN_UINT16(void *ptr, uint16 val);
#ifdef ENABLE_SCI32
void WRITE_SCI11ENDIAN_UINT32(void *ptr, uint32 val);
#endif
-
// Wrappers for reading integer values in resources that are
// LE in SCI1.1 Mac, but BE in SCI32 Mac
uint16 READ_SCI32ENDIAN_UINT16(const void *ptr);
+#pragma mark -
+#pragma mark SciSpanImpl - SciSpanIterator
+
+namespace SciSpanInternal {
+ template <typename Span, bool IsConst>
+ class SciSpanIterator : public Common::SpanInternal::SpanIterator<Span, IsConst> {
+ typedef typename Common::SpanInternal::SpanIterator<Span, IsConst> super_type;
+ typedef typename Span::value_type span_value_type;
+ typedef typename Common::Conditional<IsConst, const Span, Span>::type span_type;
+
+ public:
+ typedef typename Span::difference_type difference_type;
+ typedef typename Common::RemoveConst<span_value_type>::type value_type;
+ typedef typename Common::Conditional<IsConst, const span_value_type, span_value_type>::type *pointer;
+ typedef typename Common::Conditional<IsConst, const span_value_type, span_value_type>::type &reference;
+
+ inline SciSpanIterator() : super_type() {}
+
+ inline SciSpanIterator(span_type *span, const difference_type index) : super_type(span, index) {}
+
+ inline SciSpanIterator(const SciSpanIterator &other) : super_type(other) {}
+
+ inline SciSpanIterator &operator=(const SciSpanIterator &other) {
+ super_type::operator=(other);
+ return *this;
+ }
+
+ inline SciSpanIterator operator+(const difference_type delta) const {
+ SciSpanIterator it(*this);
+ it += delta;
+ return it;
+ }
+
+ inline SciSpanIterator operator-(const difference_type delta) const {
+ return operator+(-delta);
+ }
+
+ inline difference_type operator-(const SciSpanIterator &other) const {
+ assert(this->_span == other._span);
+ return this->_index - other._index;
+ }
+
+ inline int16 getInt16SE() const {
+ return this->_span->getInt16SEAt(this->_index);
+ }
+
+ inline uint16 getUint16SE() const {
+ return this->_span->getUint16SEAt(this->_index);
+ }
+
+ inline uint16 getUint16SE32() const {
+ return this->_span->getUint16SE32At(this->_index);
+ }
+
+ inline int32 getInt32SE() const {
+ return this->_span->getInt32SEAt(this->_index);
+ }
+
+ inline uint32 getUint32SE() const {
+ return this->_span->getUint32SEAt(this->_index);
+ }
+
+ inline void setUint16SE(uint16 value) const {
+ this->_span->setUint16SEAt(this->_index, value);
+ }
+
+#ifdef ENABLE_SCI32
+ inline void setUint32SE(uint32 value) const {
+ this->_span->setUint32SEAt(this->_index, value);
+ }
+#endif
+ };
+} // End of namespace SciSpanInternal
+
+/**
+ * Bounds-checked random access into a contiguous block of memory, with
+ * extra methods that automatically read and write using the correct endianness
+ * for the currently loaded game.
+ */
+template <typename ValueType, template <typename> class Derived>
+class SciSpanImpl : public Common::NamedSpanImpl<ValueType, Derived> {
+ typedef Common::NamedSpanImpl<ValueType, Derived> super_type;
+ typedef Derived<ValueType> derived_type;
+ typedef typename Common::AddConst<Derived<ValueType> >::type const_derived_type;
+ typedef typename Common::RemoveConst<Derived<ValueType> >::type mutable_derived_type;
+
+#if !defined(__GNUC__) || GCC_ATLEAST(3, 0)
+ template <typename T, template <typename> class U> friend class SciSpanImpl;
+#endif
+#if CXXTEST_RUNNING
+ friend class ::SpanTestSuite;
+#endif
+
+public:
+ typedef typename super_type::value_type value_type;
+ typedef typename super_type::difference_type difference_type;
+ typedef typename super_type::index_type index_type;
+ typedef typename super_type::size_type size_type;
+ typedef SciSpanInternal::SciSpanIterator<derived_type, true> const_iterator;
+ typedef SciSpanInternal::SciSpanIterator<derived_type, false> iterator;
+ typedef typename super_type::pointer pointer;
+ typedef typename super_type::const_pointer const_pointer;
+ typedef typename super_type::reference reference;
+ typedef typename super_type::const_reference const_reference;
+
+ inline SciSpanImpl() : super_type() {}
+
+ inline SciSpanImpl(const pointer data_,
+ const size_type size_,
+ const Common::String &name = Common::String(),
+ const size_type sourceByteOffset = 0) :
+ super_type(data_, size_, name, sourceByteOffset) {}
+
+ template <typename Other>
+ inline SciSpanImpl(const Other &other) :
+ super_type(other) {}
+
+ template <typename Other>
+ inline mutable_derived_type &operator=(const Other &other) {
+ super_type::operator=(other);
+ return this->impl();
+ }
+
+ inline ~SciSpanImpl() {}
+
+ inline const_iterator cbegin() const { return const_iterator(&this->impl(), 0); }
+ inline const_iterator cend() const { return const_iterator(&this->impl(), this->size()); }
+ inline const_iterator begin() const { return const_iterator(&this->impl(), 0); }
+ inline const_iterator end() const { return const_iterator(&this->impl(), this->size()); }
+ inline iterator begin() { return iterator(&this->impl(), 0); }
+ inline iterator end() { return iterator(&this->impl(), this->size()); }
+
+#pragma mark -
+#pragma mark SciSpan - Data access
+
+public:
+ inline int16 getInt16SEAt(const size_type index) const {
+ return (int16)getUint16SEAt(index);
+ }
+
+ inline uint16 getUint16SEAt(const size_type index) const {
+ this->validate(index, sizeof(uint16));
+ return READ_SCI11ENDIAN_UINT16(this->data() + index);
+ }
+
+ inline uint16 getUint16SE32At(const size_type index) const {
+ this->validate(index, sizeof(uint16));
+ return READ_SCI32ENDIAN_UINT16(this->data() + index);
+ }
+
+ inline int32 getInt32SEAt(const size_type index) const {
+ return (int32)getUint32SEAt(index);
+ }
+
+ inline uint32 getUint32SEAt(const size_type index) const {
+ this->validate(index, sizeof(uint32));
+ return READ_SCI11ENDIAN_UINT32(this->data() + index);
+ }
+
+ inline void setUint16SEAt(const size_type index, uint16 value) {
+ this->validate(index, sizeof(uint16), Common::kValidateWrite);
+ WRITE_SCI11ENDIAN_UINT16(this->data() + index, value);
+ }
+
+#ifdef ENABLE_SCI32
+ inline void setUint32SEAt(const size_type index, uint32 value) {
+ this->validate(index, sizeof(uint32), Common::kValidateWrite);
+ WRITE_SCI11ENDIAN_UINT32(this->data() + index, value);
+ }
+#endif
+
+#pragma mark -
+#pragma mark SciSpanImpl - ForwardIterator
+
+// Spans that are used as ForwardIterators must not be allowed inside of
+// SpanOwner, since this will result in the wrong pointer to memory to be
+// deleted
+public:
+ inline const_reference operator*() const {
+ this->validate(0, sizeof(value_type));
+ return *this->_data;
+ }
+
+ inline reference operator*() {
+ this->validate(0, sizeof(value_type));
+ return *this->_data;
+ }
+
+ inline mutable_derived_type &operator+=(const difference_type delta) {
+ this->validate(0, delta * sizeof(value_type), Common::kValidateSeek);
+ this->_data += delta;
+ this->_size -= delta;
+ return this->impl();
+ }
+
+ inline mutable_derived_type &operator++() {
+ return operator+=(1);
+ }
+
+ inline mutable_derived_type operator++(int) {
+ mutable_derived_type span(this->impl());
+ operator+=(1);
+ return span;
+ }
+
+ inline mutable_derived_type operator+(const difference_type delta) const {
+ mutable_derived_type span(this->impl());
+ span += delta;
+ return span;
+ }
+};
+
+template <typename ValueType>
+class SciSpan : public SciSpanImpl<ValueType, SciSpan> {
+ typedef SciSpanImpl<ValueType, ::Sci::SciSpan> super_type;
+ typedef typename Common::AddConst<SciSpan<ValueType> >::type const_derived_type;
+ typedef typename Common::RemoveConst<SciSpan<ValueType> >::type mutable_derived_type;
+
+public:
+ typedef typename super_type::value_type value_type;
+ typedef typename super_type::difference_type difference_type;
+ typedef typename super_type::index_type index_type;
+ typedef typename super_type::size_type size_type;
+ typedef typename super_type::const_iterator const_iterator;
+ typedef typename super_type::iterator iterator;
+ typedef typename super_type::pointer pointer;
+ typedef typename super_type::const_pointer const_pointer;
+ typedef typename super_type::reference reference;
+ typedef typename super_type::const_reference const_reference;
+
+ inline SciSpan() : super_type() {}
+
+ inline SciSpan(const pointer data_,
+ const size_type size_,
+ const Common::String &name = Common::String(),
+ const size_type sourceByteOffset = 0) :
+ super_type(data_, size_, name, sourceByteOffset) {}
+
+ template <typename Other>
+ inline SciSpan(const Other &other) : super_type(other) {}
+
+ template <typename Other>
+ inline mutable_derived_type &operator=(const Other &other) {
+ super_type::operator=(other);
+ return this->impl();
+ }
+
+ ~SciSpan() {}
+};
+
} // End of namespace Sci
#endif