scummvm/engines/ags/shared/script/cc_script.cpp
2021-03-06 20:07:09 -08:00

370 lines
8.9 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "ags/shared/script/cc_error.h"
#include "ags/shared/script/cc_script.h"
#include "ags/shared/script/script_common.h"
#include "ags/shared/util/stream.h"
#include "ags/shared/util/string_compat.h"
#include "ags/globals.h"
namespace AGS3 {
using AGS::Shared::Stream;
// [IKM] I reckon this function is almost identical to fgetstring in string_utils
void freadstring(char **strptr, Stream *in) {
static char ibuffer[300];
int idxx = 0;
while ((ibuffer[idxx] = in->ReadInt8()) != 0)
idxx++;
if (ibuffer[0] == 0) {
strptr[0] = nullptr;
return;
}
strptr[0] = (char *)malloc(strlen(ibuffer) + 1);
strcpy(strptr[0], ibuffer);
}
void fwritestring(const char *strptr, Stream *out) {
if (strptr == nullptr) {
out->WriteByte(0);
} else {
out->Write(strptr, strlen(strptr) + 1);
}
}
ccScript *ccScript::CreateFromStream(Shared::Stream *in) {
ccScript *scri = new ccScript();
if (!scri->Read(in)) {
delete scri;
return nullptr;
}
return scri;
}
ccScript::ccScript() {
globaldata = nullptr;
globaldatasize = 0;
code = nullptr;
codesize = 0;
strings = nullptr;
stringssize = 0;
fixuptypes = nullptr;
fixups = nullptr;
numfixups = 0;
importsCapacity = 0;
imports = nullptr;
numimports = 0;
exportsCapacity = 0;
exports = nullptr;
export_addr = nullptr;
numexports = 0;
instances = 0;
sectionNames = nullptr;
sectionOffsets = nullptr;
numSections = 0;
capacitySections = 0;
}
ccScript::ccScript(const ccScript &src) {
globaldatasize = src.globaldatasize;
if (globaldatasize > 0) {
globaldata = (char *)malloc(globaldatasize);
memcpy(globaldata, src.globaldata, globaldatasize);
} else {
globaldata = nullptr;
}
codesize = src.codesize;
if (codesize > 0) {
code = (int32_t *)malloc(codesize * sizeof(int32_t));
memcpy(code, src.code, sizeof(int32_t) * codesize);
} else {
code = nullptr;
}
stringssize = src.stringssize;
if (stringssize > 0) {
strings = (char *)malloc(stringssize);
memcpy(strings, src.strings, stringssize);
} else {
strings = nullptr;
}
numfixups = src.numfixups;
if (numfixups > 0) {
fixuptypes = (char *)malloc(numfixups);
fixups = (int32_t *)malloc(numfixups * sizeof(int32_t));
memcpy(fixuptypes, src.fixuptypes, numfixups);
memcpy(fixups, src.fixups, numfixups * sizeof(int32_t));
} else {
fixups = nullptr;
fixuptypes = nullptr;
}
importsCapacity = src.numimports;
numimports = src.numimports;
if (numimports > 0) {
imports = (char **)malloc(sizeof(char *) * numimports);
for (int i = 0; i < numimports; ++i)
imports[i] = ags_strdup(src.imports[i]);
} else {
imports = nullptr;
}
exportsCapacity = src.numexports;
numexports = src.numexports;
if (numexports > 0) {
exports = (char **)malloc(sizeof(char *) * numexports);
export_addr = (int32_t *)malloc(sizeof(int32_t) * numexports);
for (int i = 0; i < numexports; ++i) {
exports[i] = ags_strdup(src.exports[i]);
export_addr[i] = src.export_addr[i];
}
} else {
exports = nullptr;
export_addr = nullptr;
}
capacitySections = src.numSections;
numSections = src.numSections;
if (numSections > 0) {
sectionNames = (char **)malloc(numSections * sizeof(char *));
sectionOffsets = (int32_t *)malloc(numSections * sizeof(int32_t));
for (int i = 0; i < numSections; ++i) {
sectionNames[i] = ags_strdup(src.sectionNames[i]);
sectionOffsets[i] = src.sectionOffsets[i];
}
} else {
numSections = 0;
sectionNames = nullptr;
sectionOffsets = nullptr;
}
instances = 0;
}
ccScript::~ccScript() {
Free();
}
void ccScript::Write(Shared::Stream *out) {
int n;
out->Write(_G(scfilesig), 4);
out->WriteInt32(SCOM_VERSION);
out->WriteInt32(globaldatasize);
out->WriteInt32(codesize);
out->WriteInt32(stringssize);
if (globaldatasize > 0)
out->WriteArray(globaldata, globaldatasize, 1);
if (codesize > 0)
out->WriteArrayOfInt32(code, codesize);
if (stringssize > 0)
out->WriteArray(strings, stringssize, 1);
out->WriteInt32(numfixups);
if (numfixups > 0) {
out->WriteArray(fixuptypes, numfixups, 1);
out->WriteArrayOfInt32(fixups, numfixups);
}
out->WriteInt32(numimports);
for (n = 0; n < numimports; n++)
fwritestring(imports[n], out);
out->WriteInt32(numexports);
for (n = 0; n < numexports; n++) {
fwritestring(exports[n], out);
out->WriteInt32(export_addr[n]);
}
out->WriteInt32(numSections);
for (n = 0; n < numSections; n++) {
fwritestring(sectionNames[n], out);
out->WriteInt32(sectionOffsets[n]);
}
out->WriteInt32(ENDFILESIG);
}
bool ccScript::Read(Shared::Stream *in) {
instances = 0;
int n;
char gotsig[5];
_G(currentline) = -1;
// MACPORT FIX: swap 'size' and 'nmemb'
in->Read(gotsig, 4);
gotsig[4] = 0;
int fileVer = in->ReadInt32();
if ((strcmp(gotsig, _G(scfilesig)) != 0) || (fileVer > SCOM_VERSION)) {
cc_error("file was not written by ccScript::Write or seek position is incorrect");
return false;
}
globaldatasize = in->ReadInt32();
codesize = in->ReadInt32();
stringssize = in->ReadInt32();
if (globaldatasize > 0) {
globaldata = (char *)malloc(globaldatasize);
// MACPORT FIX: swap
in->Read(globaldata, globaldatasize);
} else
globaldata = nullptr;
if (codesize > 0) {
code = (int32_t *)malloc(codesize * sizeof(int32_t));
// MACPORT FIX: swap
// 64 bit: Read code into 8 byte array, necessary for being able to perform
// relocations on the references.
in->ReadArrayOfInt32(code, codesize);
} else
code = nullptr;
if (stringssize > 0) {
strings = (char *)malloc(stringssize);
// MACPORT FIX: swap
in->Read(strings, stringssize);
} else
strings = nullptr;
numfixups = in->ReadInt32();
if (numfixups > 0) {
fixuptypes = (char *)malloc(numfixups);
fixups = (int32_t *)malloc(numfixups * sizeof(int32_t));
// MACPORT FIX: swap 'size' and 'nmemb'
in->Read(fixuptypes, numfixups);
in->ReadArrayOfInt32(fixups, numfixups);
} else {
fixups = nullptr;
fixuptypes = nullptr;
}
numimports = in->ReadInt32();
imports = (char **)malloc(sizeof(char *) * numimports);
for (n = 0; n < numimports; n++)
freadstring(&imports[n], in);
numexports = in->ReadInt32();
exports = (char **)malloc(sizeof(char *) * numexports);
export_addr = (int32_t *)malloc(sizeof(int32_t) * numexports);
for (n = 0; n < numexports; n++) {
freadstring(&exports[n], in);
export_addr[n] = in->ReadInt32();
}
if (fileVer >= 83) {
// read in the Sections
numSections = in->ReadInt32();
sectionNames = (char **)malloc(numSections * sizeof(char *));
sectionOffsets = (int32_t *)malloc(numSections * sizeof(int32_t));
for (n = 0; n < numSections; n++) {
freadstring(&sectionNames[n], in);
sectionOffsets[n] = in->ReadInt32();
}
} else {
numSections = 0;
sectionNames = nullptr;
sectionOffsets = nullptr;
}
if (in->ReadInt32() != (int32)ENDFILESIG) {
cc_error("internal error rebuilding script");
return false;
}
return true;
}
void ccScript::Free() {
if (globaldata != nullptr)
free(globaldata);
if (code != nullptr)
free(code);
if (strings != nullptr)
free(strings);
if (fixups != nullptr && numfixups > 0)
free(fixups);
if (fixuptypes != nullptr && numfixups > 0)
free(fixuptypes);
globaldata = nullptr;
code = nullptr;
strings = nullptr;
fixups = nullptr;
fixuptypes = nullptr;
int aa;
for (aa = 0; aa < numimports; aa++) {
if (imports[aa] != nullptr)
free(imports[aa]);
}
for (aa = 0; aa < numexports; aa++)
free(exports[aa]);
for (aa = 0; aa < numSections; aa++)
free(sectionNames[aa]);
if (sectionNames != nullptr) {
free(sectionNames);
free(sectionOffsets);
sectionNames = nullptr;
sectionOffsets = nullptr;
}
if (imports != nullptr) {
free(imports);
free(exports);
free(export_addr);
imports = nullptr;
exports = nullptr;
export_addr = nullptr;
}
numimports = 0;
numexports = 0;
numSections = 0;
}
const char *ccScript::GetSectionName(int32_t offs) {
int i;
for (i = 0; i < numSections; i++) {
if (sectionOffsets[i] < offs)
continue;
break;
}
// if no sections in script, return unknown
if (i == 0)
return "(unknown section)";
return sectionNames[i - 1];
}
} // namespace AGS3