scummvm/engines/glk/alan3/reverse.cpp
2019-07-06 15:27:08 -07:00

657 lines
16 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 "glk/alan3/types.h"
#include "glk/alan3/lists.h"
#include "glk/alan3/checkentry.h"
#include "glk/alan3/rules.h"
#include "glk/alan3/msg.h"
#include "glk/alan3/utils.h"
#include "glk/alan3/compatibility.h"
#include "glk/alan3/syserr.h"
#include "glk/alan3/memory.h"
namespace Glk {
namespace Alan3 {
extern Aword *memory;
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static Aaddr memorySize = 0;
static Aword *addressesDone = NULL;
static int numberDone = 0;
static int doneSize = 0;
static bool alreadyDone(Aaddr address) {
int i;
if (address == 0) return TRUE;
/* Have we already done it? */
for (i = 0; i < numberDone; i++)
if (addressesDone[i] == address)
return TRUE;
if (doneSize == numberDone) {
doneSize += 100;
addressesDone = (Aword *)realloc(addressesDone, doneSize * sizeof(Aword));
}
addressesDone[numberDone] = address;
numberDone++;
return FALSE;
}
#define NATIVE(w) \
( (((Aword)((w)[3]) ) & 0x000000ff) \
| (((Aword)((w)[2]) << 8) & 0x0000ff00) \
| (((Aword)((w)[1]) << 16) & 0x00ff0000) \
| (((Aword)((w)[0]) << 24) & 0xff000000))
/*----------------------------------------------------------------------*/
Aword reversed(Aword w) { /* IN - The ACODE word to swap bytes of */
#ifdef TRYNATIVE
return NATIVE(&w);
#else
Aword s; /* The swapped ACODE word */
char *wp, *sp;
uint i;
wp = (char *) &w;
sp = (char *) &s;
for (i = 0; i < sizeof(Aword); i++)
sp[sizeof(Aword) - 1 - i] = wp[i];
return s;
#endif
}
void reverseWord(Aword *w) { /* IN - The ACODE word to reverse bytes in */
*w = reversed(*w);
}
void reverse(Aword *w) { /* IN - The ACODE word to reverse bytes in */
if (w < &memory[0] || w > &memory[memorySize])
syserr("Reversing address outside of memory");
reverseWord(w);
}
static void reverseTable(Aword adr, int elementSize) {
Aword *e = &memory[adr];
uint i;
if (elementSize < (int)sizeof(Aword) || elementSize % (int)sizeof(Aword) != 0)
syserr("***Wrong size in 'reverseTable()' ***");
if (adr == 0) return;
while (!isEndOfArray(e)) {
for (i = 0; i < elementSize / sizeof(Aword); i++) {
reverse(e);
e++;
}
}
}
static void reverseStms(Aword adr) {
Aword *e = &memory[adr];
if (!adr || alreadyDone(adr)) return;
while (TRUE) {
reverse(e);
if (*e == ((Aword)C_STMOP << 28 | (Aword)I_RETURN)) break;
e++;
}
}
static void reverseMsgs(Aword adr) {
MessageEntry *e = (MessageEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(MessageEntry));
while (!isEndOfArray(e)) {
reverseStms(e->stms);
e++;
}
}
}
static void reverseDictionary(Aword adr) {
DictionaryEntry *e = (DictionaryEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(DictionaryEntry));
while (!isEndOfArray(e)) {
if ((e->classBits & SYNONYM_BIT) == 0) { /* Do not do this for synonyms */
reverseTable(e->adjectiveRefs, sizeof(Aword));
reverseTable(e->nounRefs, sizeof(Aword));
reverseTable(e->pronounRefs, sizeof(Aword));
}
e++;
}
}
}
static void reverseChks(Aword adr) {
CheckEntry *e = (CheckEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(CheckEntry));
while (!isEndOfArray(e)) {
reverseStms(e->exp);
reverseStms(e->stms);
e++;
}
}
}
static void reverseAlts(Aword adr) {
AltEntry *e = (AltEntry *)&memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(AltEntry));
while (!isEndOfArray(e)) {
reverseChks(e->checks);
reverseStms(e->action);
e++;
}
}
}
static void reverseVerbs(Aword adr) {
VerbEntry *e = (VerbEntry *)&memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(VerbEntry));
while (!isEndOfArray(e)) {
reverseAlts(e->alts);
e++;
}
}
}
static void reverseSteps(Aword adr) {
StepEntry *e = (StepEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(StepEntry));
while (!isEndOfArray(e)) {
reverseStms(e->after);
reverseStms(e->exp);
reverseStms(e->stms);
e++;
}
}
}
static void reverseScrs(Aword adr) {
ScriptEntry *e = (ScriptEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(ScriptEntry));
while (!isEndOfArray(e)) {
reverseStms(e->description);
reverseSteps(e->steps);
e++;
}
}
}
static void reverseExits(Aword adr) {
ExitEntry *e = (ExitEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(ExitEntry));
while (!isEndOfArray(e)) {
reverseChks(e->checks);
reverseStms(e->action);
e++;
}
}
}
static void reverseClasses(Aword adr) {
ClassEntry *e = (ClassEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(ClassEntry));
while (!isEndOfArray(e)) {
reverseStms(e->name);
reverseStms(e->initialize);
reverseChks(e->descriptionChecks);
reverseStms(e->description);
reverseStms(e->entered);
reverseStms(e->definite.address);
reverseStms(e->indefinite.address);
reverseStms(e->negative.address);
reverseStms(e->mentioned);
reverseVerbs(e->verbs);
e++;
}
}
}
static void reverseInstances(Aword adr) {
InstanceEntry *e = (InstanceEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(InstanceEntry));
while (!isEndOfArray(e)) {
reverseStms(e->name);
reverseTable(e->initialAttributes, sizeof(AttributeHeaderEntry));
reverseStms(e->initialize);
reverseStms(e->definite.address);
reverseStms(e->indefinite.address);
reverseStms(e->negative.address);
reverseStms(e->mentioned);
reverseChks(e->checks);
reverseStms(e->description);
reverseVerbs(e->verbs);
reverseStms(e->entered);
reverseExits(e->exits);
e++;
}
}
}
static void reverseRestrictions(Aword adr) {
RestrictionEntry *e = (RestrictionEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(RestrictionEntry));
while (!isEndOfArray(e)) {
reverseStms(e->stms);
e++;
}
}
}
static void reverseElms(Aword adr) {
ElementEntry *e = (ElementEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(ElementEntry));
while (!isEndOfArray(e)) {
if ((uint)e->code == EOS) reverseRestrictions(e->next);
else reverseElms(e->next);
e++;
}
}
}
static void reverseSyntaxTableCurrent(Aword adr) {
SyntaxEntry *e = (SyntaxEntry *) &memory[adr];
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(SyntaxEntry));
while (!isEndOfArray(e)) {
reverseElms(e->elms);
reverseTable(e->parameterNameTable, sizeof(Aaddr));
e++;
}
}
}
static void reverseSyntaxTablePreBeta2(Aword adr) {
SyntaxEntryPreBeta2 *e = (SyntaxEntryPreBeta2 *) &memory[adr];
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(SyntaxEntryPreBeta2));
while (!isEndOfArray(e)) {
reverseElms(e->elms);
e++;
}
}
}
static void reverseSyntaxTable(Aword adr, byte version[]) {
if (!adr || alreadyDone(adr)) return;
if (isPreBeta2(version))
reverseSyntaxTablePreBeta2(adr);
else
reverseSyntaxTableCurrent(adr);
}
static void reverseParameterNames(Aaddr parameterMapAddress) {
Aaddr *e;
Aaddr adr;
adr = addressAfterTable(parameterMapAddress, sizeof(ParameterMapEntry));
reverse(&memory[adr]);
adr = memory[adr];
reverseTable(adr, sizeof(Aaddr));
e = (Aaddr *) &memory[adr];
while (!isEndOfArray(e)) {
reverseTable(*e, sizeof(Aaddr));
e++;
}
}
static void reverseParameterTable(Aword adr) {
ParameterMapEntry *e = (ParameterMapEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(ParameterMapEntry));
while (!isEndOfArray(e)) {
reverseTable(e->parameterMapping, sizeof(Aword));
e++;
}
}
}
static void reverseEvts(Aword adr) {
EventEntry *e = (EventEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(EventEntry));
while (!isEndOfArray(e)) {
reverseStms(e->code);
e++;
}
}
}
static void reverseLims(Aword adr) {
LimitEntry *e = (LimitEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(LimitEntry));
while (!isEndOfArray(e)) {
reverseStms(e->stms);
e++;
}
}
}
static void reverseContainers(Aword adr) {
ContainerEntry *e = (ContainerEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(ContainerEntry));
while (!isEndOfArray(e)) {
reverseLims(e->limits);
reverseStms(e->header);
reverseStms(e->empty);
reverseChks(e->extractChecks);
reverseStms(e->extractStatements);
e++;
}
}
}
static void reverseRuls(Aword adr) {
RuleEntry *e = (RuleEntry *) &memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(RuleEntry));
while (!isEndOfArray(e)) {
reverseStms(e->exp);
reverseStms(e->stms);
e++;
}
}
}
static void reverseSetInitTable(Aaddr adr) {
SetInitEntry *e = (SetInitEntry *)&memory[adr];
if (!adr || alreadyDone(adr)) return;
if (!isEndOfArray(e)) {
reverseTable(adr, sizeof(SetInitEntry));
while (!isEndOfArray(e)) {
reverseTable(e->setAddress, sizeof(Aword));
e++;
}
}
}
/*----------------------------------------------------------------------*/
static void reversePreAlpha5Header(Pre3_0alpha5Header *hdr) {
uint i;
/* Reverse all words in the header except the tag */
for (i = 1; i < sizeof(*hdr) / sizeof(Aword); i++)
reverseWord(&((Aword *)hdr)[i]);
}
/*----------------------------------------------------------------------*/
static void reversePreAlpha5() {
/* NOTE that the reversePreXXX() have different header definitions */
Pre3_0alpha5Header *hdr = (Pre3_0alpha5Header *)memory;
reversePreAlpha5Header(hdr);
memorySize = hdr->size;
reverseDictionary(hdr->dictionary);
reverseSyntaxTable(hdr->syntaxTableAddress, hdr->version);
reverseParameterTable(hdr->parameterMapAddress);
reverseVerbs(hdr->verbTableAddress);
reverseClasses(hdr->classTableAddress);
reverseInstances(hdr->instanceTableAddress);
reverseScrs(hdr->scriptTableAddress);
reverseContainers(hdr->containerTableAddress);
reverseEvts(hdr->eventTableAddress);
reverseRuls(hdr->ruleTableAddress);
reverseTable(hdr->stringInitTable, sizeof(StringInitEntry));
reverseSetInitTable(hdr->setInitTable);
reverseTable(hdr->sourceFileTable, sizeof(SourceFileEntry));
reverseTable(hdr->sourceLineTable, sizeof(SourceLineEntry));
reverseStms(hdr->start);
reverseMsgs(hdr->messageTableAddress);
reverseTable(hdr->scores, sizeof(Aword));
reverseTable(hdr->freq, sizeof(Aword));
}
/*----------------------------------------------------------------------*/
static void reversePreBeta2Header(Pre3_0beta2Header *hdr) {
uint i;
/* Reverse all words in the header except the tag */
for (i = 1; i < sizeof(*hdr) / sizeof(Aword); i++)
reverseWord(&((Aword *)hdr)[i]);
}
/*----------------------------------------------------------------------*/
static void reversePreBeta2() {
/* NOTE that the reversePreXXX() have different header definitions */
Pre3_0beta2Header *hdr = (Pre3_0beta2Header *)memory;
reversePreBeta2Header(hdr);
memorySize = hdr->size;
reverseDictionary(hdr->dictionary);
reverseSyntaxTable(hdr->syntaxTableAddress, hdr->version);
reverseParameterTable(hdr->parameterMapAddress);
reverseVerbs(hdr->verbTableAddress);
reverseClasses(hdr->classTableAddress);
reverseInstances(hdr->instanceTableAddress);
reverseScrs(hdr->scriptTableAddress);
reverseContainers(hdr->containerTableAddress);
reverseEvts(hdr->eventTableAddress);
reverseRuls(hdr->ruleTableAddress);
reverseTable(hdr->stringInitTable, sizeof(StringInitEntry));
reverseSetInitTable(hdr->setInitTable);
reverseTable(hdr->sourceFileTable, sizeof(SourceFileEntry));
reverseTable(hdr->sourceLineTable, sizeof(SourceLineEntry));
reverseStms(hdr->start);
reverseMsgs(hdr->messageTableAddress);
reverseTable(hdr->scores, sizeof(Aword));
reverseTable(hdr->freq, sizeof(Aword));
}
/*======================================================================*/
void reverseHdr(ACodeHeader *hdr) {
uint i;
/* Reverse all words in the header except the tag and the version marking */
for (i = 1; i < sizeof(*hdr) / sizeof(Aword); i++)
reverseWord(&((Aword *)hdr)[i]);
}
/*----------------------------------------------------------------------*/
static void reverseInstanceIdTable(ACodeHeader *hdr) {
reverseTable(hdr->instanceTableAddress + hdr->instanceMax * sizeof(InstanceEntry) / sizeof(Aword) + 1, sizeof(Aword));
}
/*----------------------------------------------------------------------*/
static void reverseNative() {
/* NOTE that the reversePreXXX() have different hdr definitions */
ACodeHeader *hdr = (ACodeHeader *)memory;
reverseHdr(hdr);
memorySize = hdr->size;
reverseDictionary(hdr->dictionary);
reverseSyntaxTable(hdr->syntaxTableAddress, hdr->version);
if (hdr->debug && !isPreBeta3(hdr->version))
reverseParameterNames(hdr->parameterMapAddress);
reverseParameterTable(hdr->parameterMapAddress);
reverseVerbs(hdr->verbTableAddress);
reverseClasses(hdr->classTableAddress);
reverseInstances(hdr->instanceTableAddress);
if (hdr->debug && !isPreBeta3(hdr->version))
reverseInstanceIdTable(hdr);
reverseScrs(hdr->scriptTableAddress);
reverseContainers(hdr->containerTableAddress);
reverseEvts(hdr->eventTableAddress);
reverseRuls(hdr->ruleTableAddress);
reverseTable(hdr->stringInitTable, sizeof(StringInitEntry));
reverseSetInitTable(hdr->setInitTable);
reverseTable(hdr->sourceFileTable, sizeof(SourceFileEntry));
reverseTable(hdr->sourceLineTable, sizeof(SourceLineEntry));
reverseStms(hdr->prompt);
reverseStms(hdr->start);
reverseMsgs(hdr->messageTableAddress);
reverseTable(hdr->scores, sizeof(Aword));
reverseTable(hdr->freq, sizeof(Aword));
}
/*======================================================================
reverseACD()
Traverse all the data structures and reverse all integers.
Only performed in architectures with reversed byte ordering, which
makes the .ACD files fully compatible across architectures
*/
void reverseACD(void) {
ACodeHeader *hdr = (ACodeHeader *)memory;
byte version[4];
int i;
/* Make a copy of the version marking to reverse */
for (i = 0; i <= 3; i++)
version[i] = hdr->version[i];
reverseWord((Aword *)&version);
if (isPreAlpha5(version))
reversePreAlpha5();
else if (isPreBeta2(version))
reversePreBeta2();
else
reverseNative();
free(addressesDone);
}
} // End of namespace Alan3
} // End of namespace Glk