Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,85 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/std/utility.h"
#include "ags/shared/script/cc_common.h"
#include "ags/shared/util/string.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
void ccSetOption(int optbit, int onoroff) {
if (onoroff)
_G(ccCompOptions) |= optbit;
else
_G(ccCompOptions) &= ~optbit;
}
int ccGetOption(int optbit) {
if (_G(ccCompOptions) & optbit)
return 1;
return 0;
}
void cc_clear_error() {
_GP(ccError) = ScriptError();
}
bool cc_has_error() {
return _GP(ccError).HasError;
}
const ScriptError &cc_get_error() {
return _GP(ccError);
}
String cc_get_err_callstack(int max_lines) {
return cc_has_error() ? _GP(ccError).CallStack : cc_get_callstack(max_lines);
}
void cc_error(const char *descr, ...) {
_GP(ccError).IsUserError = false;
if (descr[0] == '!') {
_GP(ccError).IsUserError = true;
descr++;
}
va_list ap;
va_start(ap, descr);
String displbuf = String::FromFormatV(descr, ap);
va_end(ap);
// TODO: because this global ccError is a global shared variable,
// we have to use project-dependent function to format the final message
_GP(ccError).ErrorString = cc_format_error(displbuf);
_GP(ccError).CallStack = cc_get_callstack();
_GP(ccError).HasError = 1;
_GP(ccError).Line = _G(currentline);
}
void cc_error(const ScriptError &err) {
_GP(ccError) = err;
}
} // namespace AGS3

View File

@@ -0,0 +1,67 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
// Script options and error reporting.
#ifndef AGS_SHARED_SCRIPT_CC_COMMON_H
#define AGS_SHARED_SCRIPT_CC_COMMON_H
#include "ags/shared/util/string.h"
namespace AGS3 {
#define SCOPT_EXPORTALL 1 // export all functions automatically
#define SCOPT_SHOWWARNINGS 2 // printf warnings to console
#define SCOPT_LINENUMBERS 4 // include line numbers in compiled code
#define SCOPT_AUTOIMPORT 8 // when creating instance, export funcs to other scripts
#define SCOPT_DEBUGRUN 0x10 // write instructions as they are procssed to log file
#define SCOPT_NOIMPORTOVERRIDE 0x20 // do not allow an import to be re-declared
#define SCOPT_LEFTTORIGHT 0x40 // left-to-right operator precedance
#define SCOPT_OLDSTRINGS 0x80 // allow old-style strings
#define SCOPT_UTF8 0x100 // UTF-8 text mode
extern void ccSetOption(int, int);
extern int ccGetOption(int);
// error reporting
struct ScriptError {
bool HasError = false; // set if error occurs
bool IsUserError = false; // marks script use errors
AGS::Shared::String ErrorString; // description of the error
int Line = 0; // line number of the error
AGS::Shared::String CallStack; // callstack where error happened
};
void cc_clear_error();
bool cc_has_error();
const ScriptError &cc_get_error();
// Returns callstack of the last recorded script error, or a callstack
// of a current execution point, if no script error is currently saved in memory.
AGS::Shared::String cc_get_err_callstack(int max_lines = INT_MAX);
void cc_error(const char *, ...);
void cc_error(const ScriptError &err);
// Project-dependent script error formatting
AGS::Shared::String cc_format_error(const AGS::Shared::String &message);
} // namespace AGS3
#endif

View File

@@ -0,0 +1,134 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef AGS_SHARED_SCRIPT_CC_INTERNAL_H
#define AGS_SHARED_SCRIPT_CC_INTERNAL_H
namespace AGS3 {
#define SCOM_VERSION 90
#define SCOM_VERSIONSTR "0.90"
// virtual CPU registers
#define SREG_SP 1 // stack pointer
#define SREG_MAR 2 // memory address register
#define SREG_AX 3 // general purpose
#define SREG_BX 4
#define SREG_CX 5
#define SREG_OP 6 // object pointer for member func calls
#define SREG_DX 7
#define CC_NUM_REGISTERS 8
// virtual CPU commands
#define SCMD_ADD 1 // reg1 += arg2
#define SCMD_SUB 2 // reg1 -= arg2
#define SCMD_REGTOREG 3 // reg2 = reg1
#define SCMD_WRITELIT 4 // m[MAR] = arg2 (copy arg1 bytes)
#define SCMD_RET 5 // return from subroutine
#define SCMD_LITTOREG 6 // set reg1 to literal value arg2
#define SCMD_MEMREAD 7 // reg1 = m[MAR]
#define SCMD_MEMWRITE 8 // m[MAR] = reg1
#define SCMD_MULREG 9 // reg1 *= reg2
#define SCMD_DIVREG 10 // reg1 /= reg2
#define SCMD_ADDREG 11 // reg1 += reg2
#define SCMD_SUBREG 12 // reg1 -= reg2
#define SCMD_BITAND 13 // bitwise reg1 & reg2
#define SCMD_BITOR 14 // bitwise reg1 | reg2
#define SCMD_ISEQUAL 15 // reg1 == reg2 reg1=1 if true, =0 if not
#define SCMD_NOTEQUAL 16 // reg1 != reg2
#define SCMD_GREATER 17 // reg1 > reg2
#define SCMD_LESSTHAN 18 // reg1 < reg2
#define SCMD_GTE 19 // reg1 >= reg2
#define SCMD_LTE 20 // reg1 <= reg2
#define SCMD_AND 21 // (reg1!=0) && (reg2!=0) -> reg1
#define SCMD_OR 22 // (reg1!=0) || (reg2!=0) -> reg1
#define SCMD_CALL 23 // jump to subroutine at reg1
#define SCMD_MEMREADB 24 // reg1 = m[MAR] (1 byte)
#define SCMD_MEMREADW 25 // reg1 = m[MAR] (2 bytes)
#define SCMD_MEMWRITEB 26 // m[MAR] = reg1 (1 byte)
#define SCMD_MEMWRITEW 27 // m[MAR] = reg1 (2 bytes)
#define SCMD_JZ 28 // jump if ax==0 to arg1
#define SCMD_PUSHREG 29 // m[sp]=reg1; sp++
#define SCMD_POPREG 30 // sp--; reg1=m[sp]
#define SCMD_JMP 31 // jump to arg1
#define SCMD_MUL 32 // reg1 *= arg2
#define SCMD_CALLEXT 33 // call external (imported) function reg1
#define SCMD_PUSHREAL 34 // push reg1 onto real stack
#define SCMD_SUBREALSTACK 35 // decrement stack ptr by literal
#define SCMD_LINENUM 36 // debug info - source code line number
#define SCMD_CALLAS 37 // call external script function
#define SCMD_THISBASE 38 // current relative address
#define SCMD_NUMFUNCARGS 39 // number of arguments for ext func call
#define SCMD_MODREG 40 // reg1 %= reg2
#define SCMD_XORREG 41 // reg1 ^= reg2
#define SCMD_NOTREG 42 // reg1 = !reg1
#define SCMD_SHIFTLEFT 43 // reg1 = reg1 << reg2
#define SCMD_SHIFTRIGHT 44 // reg1 = reg1 >> reg2
#define SCMD_CALLOBJ 45 // next call is member function of reg1
#define SCMD_CHECKBOUNDS 46 // check reg1 is between 0 and arg2
#define SCMD_MEMWRITEPTR 47 // m[MAR] = reg1 (adjust ptr addr)
#define SCMD_MEMREADPTR 48 // reg1 = m[MAR] (adjust ptr addr)
#define SCMD_MEMZEROPTR 49 // m[MAR] = 0 (blank ptr)
#define SCMD_MEMINITPTR 50 // m[MAR] = reg1 (but don't free old one)
#define SCMD_LOADSPOFFS 51 // MAR = SP - arg1 (optimization for local var access)
#define SCMD_CHECKNULL 52 // error if MAR==0
#define SCMD_FADD 53 // reg1 += arg2 (float,int)
#define SCMD_FSUB 54 // reg1 -= arg2 (float,int)
#define SCMD_FMULREG 55 // reg1 *= reg2 (float)
#define SCMD_FDIVREG 56 // reg1 /= reg2 (float)
#define SCMD_FADDREG 57 // reg1 += reg2 (float)
#define SCMD_FSUBREG 58 // reg1 -= reg2 (float)
#define SCMD_FGREATER 59 // reg1 > reg2 (float)
#define SCMD_FLESSTHAN 60 // reg1 < reg2 (float)
#define SCMD_FGTE 61 // reg1 >= reg2 (float)
#define SCMD_FLTE 62 // reg1 <= reg2 (float)
#define SCMD_ZEROMEMORY 63 // m[MAR]..m[MAR+(arg1-1)] = 0
#define SCMD_CREATESTRING 64 // reg1 = new String(reg1)
#define SCMD_STRINGSEQUAL 65 // (char*)reg1 == (char*)reg2 reg1=1 if true, =0 if not
#define SCMD_STRINGSNOTEQ 66 // (char*)reg1 != (char*)reg2
#define SCMD_CHECKNULLREG 67 // error if reg1 == NULL
#define SCMD_LOOPCHECKOFF 68 // no loop checking for this function
#define SCMD_MEMZEROPTRND 69 // m[MAR] = 0 (blank ptr, no dispose if = ax)
#define SCMD_JNZ 70 // jump to arg1 if ax!=0
#define SCMD_DYNAMICBOUNDS 71 // check reg1 is between 0 and m[MAR-4]
#define SCMD_NEWARRAY 72 // reg1 = new array of reg1 elements, each of size arg2 (arg3=managed type?)
#define SCMD_NEWUSEROBJECT 73 // reg1 = new user object of arg1 size
#define CC_NUM_SCCMDS 74
#define MAX_SCMD_ARGS 3 // maximal possible number of arguments
#define EXPORT_FUNCTION 1
#define EXPORT_DATA 2
#define FIXUP_NOFIXUP 0 // no-op
#define FIXUP_GLOBALDATA 1 // code[fixup] += &globaldata[0]
#define FIXUP_FUNCTION 2 // code[fixup] += &code[0]
#define FIXUP_STRING 3 // code[fixup] += &strings[0]
#define FIXUP_IMPORT 4 // code[fixup] = &imported_thing[code[fixup]]
#define FIXUP_DATADATA 5 // globaldata[fixup] += &globaldata[0]
#define FIXUP_STACK 6 // code[fixup] += &stack[0]
// Script file signature
#define ENDFILESIG 0xbeefcafe
} // namespace AGS3
#endif

View File

@@ -0,0 +1,336 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "ags/shared/script/cc_common.h"
#include "ags/shared/script/cc_script.h"
#include "ags/shared/script/cc_internal.h"
#include "ags/shared/util/stream.h"
#include "ags/shared/util/string_compat.h"
#include "ags/shared/util/string_utils.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
ccScript *ccScript::CreateFromStream(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(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++)
StrUtil::WriteCStr(imports[n], out);
out->WriteInt32(numexports);
for (n = 0; n < numexports; n++) {
StrUtil::WriteCStr(exports[n], out);
out->WriteInt32(export_addr[n]);
}
out->WriteInt32(numSections);
for (n = 0; n < numSections; n++) {
StrUtil::WriteCStr(sectionNames[n], out);
out->WriteInt32(sectionOffsets[n]);
}
out->WriteInt32(ENDFILESIG);
}
bool ccScript::Read(Stream *in) {
instances = 0;
int n;
char gotsig[5];
_G(currentline) = -1;
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);
in->Read(globaldata, globaldatasize);
} else
globaldata = nullptr;
if (codesize > 0) {
code = (int32_t *)malloc(codesize * sizeof(int32_t));
in->ReadArrayOfInt32(code, codesize);
} else
code = nullptr;
if (stringssize > 0) {
strings = (char *)malloc(stringssize);
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));
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++)
imports[n] = StrUtil::ReadMallocCStrOrNull(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++) {
exports[n] = StrUtil::ReadMallocCStrOrNull(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++) {
sectionNames[n] = StrUtil::ReadMallocCStrOrNull(in);
sectionOffsets[n] = in->ReadInt32();
}
} else {
numSections = 0;
sectionNames = nullptr;
sectionOffsets = nullptr;
}
if (static_cast<uint32_t>(in->ReadInt32()) != 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) const {
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

View File

@@ -0,0 +1,85 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef AGS_SHARED_SCRIPT_CC_SCRIPT_H
#define AGS_SHARED_SCRIPT_CC_SCRIPT_H
#include "common/std/memory.h"
#include "ags/shared/core/types.h"
namespace AGS3 {
namespace AGS {
namespace Shared {
class Stream;
}
}
using namespace AGS; // FIXME later
struct ccScript {
public:
char *globaldata;
int32_t globaldatasize;
int32_t *code; // executable byte-code, 32-bit per op or arg
int32_t codesize; // TODO: find out if we can make it size_t
char *strings;
int32_t stringssize;
char *fixuptypes; // global data/string area/ etc
int32_t *fixups; // code array index to fixup (in ints)
int numfixups;
int importsCapacity;
char **imports;
int numimports;
int exportsCapacity;
char **exports; // names of exports
int32_t *export_addr; // high byte is type; low 24-bits are offset
int numexports;
int instances;
// 'sections' allow the interpreter to find out which bit
// of the code came from header files, and which from the main file
char **sectionNames;
int32_t *sectionOffsets;
int numSections;
int capacitySections;
static ccScript *CreateFromStream(Shared::Stream *in);
ccScript();
ccScript(const ccScript &src);
virtual ~ccScript(); // there are few derived classes, so dtor should be virtual
// write the script to disk (after compiling)
void Write(Shared::Stream *out);
// read back a script written with Write
bool Read(Shared::Stream *in);
const char *GetSectionName(int32_t offset) const;
protected:
// free the memory occupied by the script - do NOT attempt to run the
// script after calling this function
void Free();
};
typedef std::shared_ptr<ccScript> PScript;
} // namespace AGS3
#endif