mirror of
https://github.com/kevinbentley/Descent3.git
synced 2026-04-05 14:00:03 -04:00
1261 lines
36 KiB
C++
1261 lines
36 KiB
C++
/*
|
|
AngelCode Scripting Library
|
|
Copyright (c) 2003-2009 Andreas Jonsson
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any
|
|
damages arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any
|
|
purpose, including commercial applications, and to alter it and
|
|
redistribute it freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you
|
|
must not claim that you wrote the original software. If you use
|
|
this software in a product, an acknowledgment in the product
|
|
documentation would be appreciated but is not required.
|
|
|
|
2. Altered source versions must be plainly marked as such, and
|
|
must not be misrepresented as being the original software.
|
|
|
|
3. This notice may not be removed or altered from any source
|
|
distribution.
|
|
|
|
The original version of this library can be located at:
|
|
http://www.angelcode.com/angelscript/
|
|
|
|
Andreas Jonsson
|
|
andreas@angelcode.com
|
|
*/
|
|
|
|
//
|
|
// as_restore.cpp
|
|
//
|
|
// Functions for saving and restoring module bytecode
|
|
// asCRestore was originally written by Dennis Bollyn, dennis@gyrbo.be
|
|
|
|
#include "as_config.h"
|
|
#include "as_restore.h"
|
|
#include "as_bytecode.h"
|
|
#include "as_arrayobject.h"
|
|
|
|
BEGIN_AS_NAMESPACE
|
|
|
|
#define WRITE_NUM(N) stream->Write(&(N), sizeof(N))
|
|
#define READ_NUM(N) stream->Read(&(N), sizeof(N))
|
|
|
|
asCRestore::asCRestore(asCModule *_module, asIBinaryStream *_stream, asCScriptEngine *_engine)
|
|
: module(_module), stream(_stream), engine(_engine) {}
|
|
|
|
int asCRestore::Save() {
|
|
unsigned long i, count;
|
|
|
|
// Store everything in the same order that the builder parses scripts
|
|
|
|
// Store enums
|
|
count = (asUINT)module->enumTypes.GetLength();
|
|
WRITE_NUM(count);
|
|
for (i = 0; i < count; i++) {
|
|
WriteObjectTypeDeclaration(module->enumTypes[i], false);
|
|
WriteObjectTypeDeclaration(module->enumTypes[i], true);
|
|
}
|
|
|
|
// Store type declarations first
|
|
count = (asUINT)module->classTypes.GetLength();
|
|
WRITE_NUM(count);
|
|
for (i = 0; i < count; i++) {
|
|
// Store only the name of the class/interface types
|
|
WriteObjectTypeDeclaration(module->classTypes[i], false);
|
|
}
|
|
|
|
// Now store all interface methods
|
|
for (i = 0; i < count; i++) {
|
|
if (module->classTypes[i]->IsInterface())
|
|
WriteObjectTypeDeclaration(module->classTypes[i], true);
|
|
}
|
|
|
|
// Then store the class methods, properties, and behaviours
|
|
for (i = 0; i < count; ++i) {
|
|
if (!module->classTypes[i]->IsInterface())
|
|
WriteObjectTypeDeclaration(module->classTypes[i], true);
|
|
}
|
|
|
|
// Store typedefs
|
|
count = (asUINT)module->typeDefs.GetLength();
|
|
WRITE_NUM(count);
|
|
for (i = 0; i < count; i++) {
|
|
WriteObjectTypeDeclaration(module->typeDefs[i], false);
|
|
WriteObjectTypeDeclaration(module->typeDefs[i], true);
|
|
}
|
|
|
|
// scriptGlobals[]
|
|
count = (asUINT)module->scriptGlobals.GetLength();
|
|
WRITE_NUM(count);
|
|
for (i = 0; i < count; ++i)
|
|
WriteGlobalProperty(module->scriptGlobals[i]);
|
|
|
|
// scriptFunctions[]
|
|
count = 0;
|
|
for (i = 0; i < module->scriptFunctions.GetLength(); i++)
|
|
if (module->scriptFunctions[i]->objectType == 0)
|
|
count++;
|
|
WRITE_NUM(count);
|
|
for (i = 0; i < module->scriptFunctions.GetLength(); ++i)
|
|
if (module->scriptFunctions[i]->objectType == 0)
|
|
WriteFunction(module->scriptFunctions[i]);
|
|
|
|
// globalFunctions[]
|
|
count = (int)module->globalFunctions.GetLength();
|
|
WRITE_NUM(count);
|
|
for (i = 0; i < count; i++) {
|
|
WriteFunction(module->globalFunctions[i]);
|
|
}
|
|
|
|
// bindInformations[]
|
|
count = (asUINT)module->bindInformations.GetLength();
|
|
WRITE_NUM(count);
|
|
for (i = 0; i < count; ++i) {
|
|
WriteFunction(module->bindInformations[i]->importedFunctionSignature);
|
|
WriteString(&module->bindInformations[i]->importFromModule);
|
|
}
|
|
|
|
// usedTypes[]
|
|
count = (asUINT)usedTypes.GetLength();
|
|
WRITE_NUM(count);
|
|
for (i = 0; i < count; ++i) {
|
|
WriteObjectType(usedTypes[i]);
|
|
}
|
|
|
|
// usedTypeIds[]
|
|
WriteUsedTypeIds();
|
|
|
|
// usedFunctions[]
|
|
WriteUsedFunctions();
|
|
|
|
// usedGlobalProperties[]
|
|
WriteUsedGlobalProps();
|
|
|
|
// usedStringConstants[]
|
|
WriteUsedStringConstants();
|
|
|
|
// TODO: Store script section names
|
|
|
|
return asSUCCESS;
|
|
}
|
|
|
|
int asCRestore::Restore() {
|
|
// Before starting the load, make sure that
|
|
// any existing resources have been freed
|
|
module->InternalReset();
|
|
|
|
unsigned long i, count;
|
|
|
|
asCScriptFunction *func;
|
|
|
|
// Read enums
|
|
READ_NUM(count);
|
|
module->enumTypes.Allocate(count, 0);
|
|
for (i = 0; i < count; i++) {
|
|
asCObjectType *ot = asNEW(asCObjectType)(engine);
|
|
ReadObjectTypeDeclaration(ot, false);
|
|
engine->classTypes.PushLast(ot);
|
|
module->enumTypes.PushLast(ot);
|
|
ot->AddRef();
|
|
ReadObjectTypeDeclaration(ot, true);
|
|
}
|
|
|
|
// structTypes[]
|
|
// First restore the structure names, then the properties
|
|
READ_NUM(count);
|
|
module->classTypes.Allocate(count, 0);
|
|
for (i = 0; i < count; ++i) {
|
|
asCObjectType *ot = asNEW(asCObjectType)(engine);
|
|
ReadObjectTypeDeclaration(ot, false);
|
|
engine->classTypes.PushLast(ot);
|
|
module->classTypes.PushLast(ot);
|
|
ot->AddRef();
|
|
|
|
// Add script classes to the GC
|
|
if ((ot->GetFlags() & asOBJ_SCRIPT_OBJECT) && ot->GetSize() > 0)
|
|
engine->gc.AddScriptObjectToGC(ot, &engine->objectTypeBehaviours);
|
|
}
|
|
|
|
// Read interface methods
|
|
for (i = 0; i < module->classTypes.GetLength(); i++) {
|
|
if (module->classTypes[i]->IsInterface())
|
|
ReadObjectTypeDeclaration(module->classTypes[i], true);
|
|
}
|
|
|
|
module->ResolveInterfaceIds();
|
|
|
|
// Read class methods, properties, and behaviours
|
|
for (i = 0; i < module->classTypes.GetLength(); ++i) {
|
|
if (!module->classTypes[i]->IsInterface())
|
|
ReadObjectTypeDeclaration(module->classTypes[i], true);
|
|
}
|
|
|
|
// Read typedefs
|
|
READ_NUM(count);
|
|
module->typeDefs.Allocate(count, 0);
|
|
for (i = 0; i < count; i++) {
|
|
asCObjectType *ot = asNEW(asCObjectType)(engine);
|
|
ReadObjectTypeDeclaration(ot, false);
|
|
engine->classTypes.PushLast(ot);
|
|
module->typeDefs.PushLast(ot);
|
|
ot->AddRef();
|
|
ReadObjectTypeDeclaration(ot, true);
|
|
}
|
|
|
|
// scriptGlobals[]
|
|
READ_NUM(count);
|
|
module->scriptGlobals.Allocate(count, 0);
|
|
for (i = 0; i < count; ++i) {
|
|
ReadGlobalProperty();
|
|
}
|
|
|
|
// scriptFunctions[]
|
|
READ_NUM(count);
|
|
for (i = 0; i < count; ++i) {
|
|
func = ReadFunction();
|
|
}
|
|
|
|
// globalFunctions[]
|
|
READ_NUM(count);
|
|
for (i = 0; i < count; ++i) {
|
|
func = ReadFunction(false, false);
|
|
|
|
module->globalFunctions.PushLast(func);
|
|
func->AddRef();
|
|
}
|
|
|
|
// bindInformations[]
|
|
READ_NUM(count);
|
|
module->bindInformations.SetLength(count);
|
|
for (i = 0; i < count; ++i) {
|
|
sBindInfo *info = asNEW(sBindInfo);
|
|
info->importedFunctionSignature = ReadFunction(false, false);
|
|
info->importedFunctionSignature->id = int(FUNC_IMPORTED + engine->importedFunctions.GetLength());
|
|
engine->importedFunctions.PushLast(info);
|
|
ReadString(&info->importFromModule);
|
|
info->boundFunctionId = -1;
|
|
module->bindInformations[i] = info;
|
|
}
|
|
|
|
// usedTypes[]
|
|
READ_NUM(count);
|
|
usedTypes.Allocate(count, 0);
|
|
for (i = 0; i < count; ++i) {
|
|
asCObjectType *ot = ReadObjectType();
|
|
usedTypes.PushLast(ot);
|
|
}
|
|
|
|
// usedTypeIds[]
|
|
ReadUsedTypeIds();
|
|
|
|
// usedFunctions[]
|
|
ReadUsedFunctions();
|
|
|
|
// usedGlobalProperties[]
|
|
ReadUsedGlobalProps();
|
|
|
|
// usedStringConstants[]
|
|
ReadUsedStringConstants();
|
|
|
|
for (i = 0; i < module->scriptFunctions.GetLength(); i++)
|
|
TranslateFunction(module->scriptFunctions[i]);
|
|
for (i = 0; i < module->scriptGlobals.GetLength(); i++)
|
|
if (module->scriptGlobals[i]->initFunc)
|
|
TranslateFunction(module->scriptGlobals[i]->initFunc);
|
|
|
|
// Init system functions properly
|
|
engine->PrepareEngine();
|
|
|
|
// Add references for all functions
|
|
for (i = 0; i < module->scriptFunctions.GetLength(); i++)
|
|
module->scriptFunctions[i]->AddReferences();
|
|
for (i = 0; i < module->scriptGlobals.GetLength(); i++)
|
|
if (module->scriptGlobals[i]->initFunc)
|
|
module->scriptGlobals[i]->initFunc->AddReferences();
|
|
|
|
module->CallInit();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int asCRestore::FindStringConstantIndex(int id) {
|
|
for (asUINT i = 0; i < usedStringConstants.GetLength(); i++)
|
|
if (usedStringConstants[i] == id)
|
|
return i;
|
|
|
|
usedStringConstants.PushLast(id);
|
|
return int(usedStringConstants.GetLength() - 1);
|
|
}
|
|
|
|
void asCRestore::WriteUsedStringConstants() {
|
|
asUINT count = (asUINT)usedStringConstants.GetLength();
|
|
WRITE_NUM(count);
|
|
for (asUINT i = 0; i < count; ++i)
|
|
WriteString(engine->stringConstants[i]);
|
|
}
|
|
|
|
void asCRestore::ReadUsedStringConstants() {
|
|
asCString str;
|
|
|
|
asUINT count;
|
|
READ_NUM(count);
|
|
usedStringConstants.SetLength(count);
|
|
for (asUINT i = 0; i < count; ++i) {
|
|
ReadString(&str);
|
|
usedStringConstants[i] = engine->AddConstantString(str.AddressOf(), str.GetLength());
|
|
}
|
|
}
|
|
|
|
void asCRestore::WriteUsedFunctions() {
|
|
asUINT count = (asUINT)usedFunctions.GetLength();
|
|
WRITE_NUM(count);
|
|
|
|
for (asUINT n = 0; n < usedFunctions.GetLength(); n++) {
|
|
char c;
|
|
|
|
// Write enough data to be able to uniquely identify the function upon load
|
|
|
|
// Is the function from the module or the application?
|
|
c = usedFunctions[n]->module ? 'm' : 'a';
|
|
WRITE_NUM(c);
|
|
|
|
WriteFunctionSignature(usedFunctions[n]);
|
|
}
|
|
}
|
|
|
|
void asCRestore::ReadUsedFunctions() {
|
|
asUINT count;
|
|
READ_NUM(count);
|
|
usedFunctions.SetLength(count);
|
|
|
|
for (asUINT n = 0; n < usedFunctions.GetLength(); n++) {
|
|
char c;
|
|
|
|
// Read the data to be able to uniquely identify the function
|
|
|
|
// Is the function from the module or the application?
|
|
READ_NUM(c);
|
|
|
|
asCScriptFunction func(engine, c == 'm' ? module : 0, -1);
|
|
ReadFunctionSignature(&func);
|
|
|
|
// Find the correct function
|
|
if (c == 'm') {
|
|
for (asUINT i = 0; i < module->scriptFunctions.GetLength(); i++) {
|
|
asCScriptFunction *f = module->scriptFunctions[i];
|
|
if (!func.IsSignatureEqual(f) || func.objectType != f->objectType || func.funcType != f->funcType)
|
|
continue;
|
|
|
|
usedFunctions[n] = f;
|
|
break;
|
|
}
|
|
} else {
|
|
for (asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++) {
|
|
asCScriptFunction *f = engine->scriptFunctions[i];
|
|
if (f == 0 || !func.IsSignatureEqual(f) || func.objectType != f->objectType)
|
|
continue;
|
|
|
|
usedFunctions[n] = f;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Set the type to dummy so it won't try to release the id
|
|
func.funcType = -1;
|
|
}
|
|
}
|
|
|
|
void asCRestore::WriteFunctionSignature(asCScriptFunction *func) {
|
|
asUINT i, count;
|
|
|
|
WriteString(&func->name);
|
|
WriteDataType(&func->returnType);
|
|
count = (asUINT)func->parameterTypes.GetLength();
|
|
WRITE_NUM(count);
|
|
for (i = 0; i < count; ++i)
|
|
WriteDataType(&func->parameterTypes[i]);
|
|
|
|
count = (asUINT)func->inOutFlags.GetLength();
|
|
WRITE_NUM(count);
|
|
for (i = 0; i < count; ++i)
|
|
WRITE_NUM(func->inOutFlags[i]);
|
|
|
|
WRITE_NUM(func->funcType);
|
|
|
|
WriteObjectType(func->objectType);
|
|
|
|
WRITE_NUM(func->isReadOnly);
|
|
}
|
|
|
|
void asCRestore::ReadFunctionSignature(asCScriptFunction *func) {
|
|
int i, count;
|
|
asCDataType dt;
|
|
int num;
|
|
|
|
ReadString(&func->name);
|
|
ReadDataType(&func->returnType);
|
|
READ_NUM(count);
|
|
func->parameterTypes.Allocate(count, 0);
|
|
for (i = 0; i < count; ++i) {
|
|
ReadDataType(&dt);
|
|
func->parameterTypes.PushLast(dt);
|
|
}
|
|
|
|
READ_NUM(count);
|
|
func->inOutFlags.Allocate(count, 0);
|
|
for (i = 0; i < count; ++i) {
|
|
READ_NUM(num);
|
|
func->inOutFlags.PushLast(static_cast<asETypeModifiers>(num));
|
|
}
|
|
|
|
READ_NUM(func->funcType);
|
|
|
|
func->objectType = ReadObjectType();
|
|
|
|
READ_NUM(func->isReadOnly);
|
|
}
|
|
|
|
void asCRestore::WriteFunction(asCScriptFunction *func) {
|
|
char c;
|
|
|
|
// If there is no function, then store a null char
|
|
if (func == 0) {
|
|
c = '\0';
|
|
WRITE_NUM(c);
|
|
return;
|
|
}
|
|
|
|
// First check if the function has been saved already
|
|
for (asUINT f = 0; f < savedFunctions.GetLength(); f++) {
|
|
if (savedFunctions[f] == func) {
|
|
c = 'r';
|
|
WRITE_NUM(c);
|
|
WRITE_NUM(f);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Keep a reference to the function in the list
|
|
savedFunctions.PushLast(func);
|
|
|
|
c = 'f';
|
|
WRITE_NUM(c);
|
|
|
|
asUINT i, count;
|
|
|
|
WriteFunctionSignature(func);
|
|
|
|
count = (asUINT)func->byteCode.GetLength();
|
|
WRITE_NUM(count);
|
|
WriteByteCode(func->byteCode.AddressOf(), count);
|
|
|
|
count = (asUINT)func->objVariablePos.GetLength();
|
|
WRITE_NUM(count);
|
|
for (i = 0; i < count; ++i) {
|
|
WriteObjectType(func->objVariableTypes[i]);
|
|
WRITE_NUM(func->objVariablePos[i]);
|
|
}
|
|
|
|
WRITE_NUM(func->stackNeeded);
|
|
|
|
asUINT length = (asUINT)func->lineNumbers.GetLength();
|
|
WRITE_NUM(length);
|
|
for (i = 0; i < length; ++i)
|
|
WRITE_NUM(func->lineNumbers[i]);
|
|
|
|
WRITE_NUM(func->vfTableIdx);
|
|
|
|
// TODO: Write variables
|
|
|
|
// TODO: Store script section index
|
|
}
|
|
|
|
asCScriptFunction *asCRestore::ReadFunction(bool addToModule, bool addToEngine) {
|
|
char c;
|
|
READ_NUM(c);
|
|
|
|
if (c == '\0') {
|
|
// There is no function, so return a null pointer
|
|
return 0;
|
|
}
|
|
|
|
if (c == 'r') {
|
|
// This is a reference to a previously saved function
|
|
int index;
|
|
READ_NUM(index);
|
|
|
|
return savedFunctions[index];
|
|
}
|
|
|
|
// Load the new function
|
|
asCScriptFunction *func = asNEW(asCScriptFunction)(engine, module, -1);
|
|
savedFunctions.PushLast(func);
|
|
|
|
int i, count;
|
|
asCDataType dt;
|
|
int num;
|
|
|
|
ReadFunctionSignature(func);
|
|
|
|
if (func->funcType == asFUNC_SCRIPT)
|
|
engine->gc.AddScriptObjectToGC(func, &engine->functionBehaviours);
|
|
|
|
func->id = engine->GetNextScriptFunctionId();
|
|
|
|
READ_NUM(count);
|
|
func->byteCode.Allocate(count, 0);
|
|
ReadByteCode(func->byteCode.AddressOf(), count);
|
|
func->byteCode.SetLength(count);
|
|
|
|
READ_NUM(count);
|
|
func->objVariablePos.Allocate(count, 0);
|
|
func->objVariableTypes.Allocate(count, 0);
|
|
for (i = 0; i < count; ++i) {
|
|
func->objVariableTypes.PushLast(ReadObjectType());
|
|
READ_NUM(num);
|
|
func->objVariablePos.PushLast(num);
|
|
}
|
|
|
|
READ_NUM(func->stackNeeded);
|
|
|
|
int length;
|
|
READ_NUM(length);
|
|
func->lineNumbers.SetLength(length);
|
|
for (i = 0; i < length; ++i)
|
|
READ_NUM(func->lineNumbers[i]);
|
|
|
|
READ_NUM(func->vfTableIdx);
|
|
|
|
if (addToModule) {
|
|
// The refCount is already 1
|
|
module->scriptFunctions.PushLast(func);
|
|
}
|
|
if (addToEngine)
|
|
engine->SetScriptFunction(func);
|
|
if (func->objectType)
|
|
func->ComputeSignatureId();
|
|
|
|
return func;
|
|
}
|
|
|
|
void asCRestore::WriteObjectTypeDeclaration(asCObjectType *ot, bool writeProperties) {
|
|
if (!writeProperties) {
|
|
// name
|
|
WriteString(&ot->name);
|
|
// size
|
|
int size = ot->size;
|
|
WRITE_NUM(size);
|
|
// flags
|
|
asDWORD flags = ot->flags;
|
|
WRITE_NUM(flags);
|
|
} else {
|
|
if (ot->flags & asOBJ_ENUM) {
|
|
// enumValues[]
|
|
int size = (int)ot->enumValues.GetLength();
|
|
WRITE_NUM(size);
|
|
|
|
for (int n = 0; n < size; n++) {
|
|
WriteString(&ot->enumValues[n]->name);
|
|
WRITE_NUM(ot->enumValues[n]->value);
|
|
}
|
|
} else if (ot->flags & asOBJ_TYPEDEF) {
|
|
eTokenType t = ot->templateSubType.GetTokenType();
|
|
WRITE_NUM(t);
|
|
} else {
|
|
WriteObjectType(ot->derivedFrom);
|
|
|
|
// interfaces[]
|
|
int size = (asUINT)ot->interfaces.GetLength();
|
|
WRITE_NUM(size);
|
|
asUINT n;
|
|
for (n = 0; n < ot->interfaces.GetLength(); n++) {
|
|
WriteObjectType(ot->interfaces[n]);
|
|
}
|
|
|
|
// properties[]
|
|
size = (asUINT)ot->properties.GetLength();
|
|
WRITE_NUM(size);
|
|
for (n = 0; n < ot->properties.GetLength(); n++) {
|
|
WriteObjectProperty(ot->properties[n]);
|
|
}
|
|
|
|
// behaviours
|
|
if (!ot->IsInterface() && ot->flags != asOBJ_TYPEDEF && ot->flags != asOBJ_ENUM) {
|
|
WriteFunction(engine->scriptFunctions[ot->beh.construct]);
|
|
WriteFunction(engine->scriptFunctions[ot->beh.destruct]);
|
|
WriteFunction(engine->scriptFunctions[ot->beh.factory]);
|
|
size = (int)ot->beh.constructors.GetLength() - 1;
|
|
WRITE_NUM(size);
|
|
for (n = 1; n < ot->beh.constructors.GetLength(); n++) {
|
|
WriteFunction(engine->scriptFunctions[ot->beh.constructors[n]]);
|
|
WriteFunction(engine->scriptFunctions[ot->beh.factories[n]]);
|
|
}
|
|
}
|
|
|
|
// methods[]
|
|
size = (int)ot->methods.GetLength();
|
|
WRITE_NUM(size);
|
|
for (n = 0; n < ot->methods.GetLength(); n++) {
|
|
WriteFunction(engine->scriptFunctions[ot->methods[n]]);
|
|
}
|
|
|
|
// virtualFunctionTable[]
|
|
size = (int)ot->virtualFunctionTable.GetLength();
|
|
WRITE_NUM(size);
|
|
for (n = 0; n < (asUINT)size; n++) {
|
|
WriteFunction(ot->virtualFunctionTable[n]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void asCRestore::ReadObjectTypeDeclaration(asCObjectType *ot, bool readProperties) {
|
|
if (!readProperties) {
|
|
// name
|
|
ReadString(&ot->name);
|
|
// size
|
|
int size;
|
|
READ_NUM(size);
|
|
ot->size = size;
|
|
// flags
|
|
asDWORD flags;
|
|
READ_NUM(flags);
|
|
ot->flags = flags;
|
|
|
|
// Use the default script class behaviours
|
|
ot->beh = engine->scriptTypeBehaviours.beh;
|
|
engine->scriptFunctions[ot->beh.addref]->AddRef();
|
|
engine->scriptFunctions[ot->beh.release]->AddRef();
|
|
engine->scriptFunctions[ot->beh.gcEnumReferences]->AddRef();
|
|
engine->scriptFunctions[ot->beh.gcGetFlag]->AddRef();
|
|
engine->scriptFunctions[ot->beh.gcGetRefCount]->AddRef();
|
|
engine->scriptFunctions[ot->beh.gcReleaseAllReferences]->AddRef();
|
|
engine->scriptFunctions[ot->beh.gcSetFlag]->AddRef();
|
|
engine->scriptFunctions[ot->beh.copy]->AddRef();
|
|
engine->scriptFunctions[ot->beh.factory]->AddRef();
|
|
engine->scriptFunctions[ot->beh.construct]->AddRef();
|
|
for (asUINT i = 1; i < ot->beh.operators.GetLength(); i += 2)
|
|
engine->scriptFunctions[ot->beh.operators[i]]->AddRef();
|
|
} else {
|
|
if (ot->flags & asOBJ_ENUM) {
|
|
int count;
|
|
READ_NUM(count);
|
|
ot->enumValues.Allocate(count, 0);
|
|
for (int n = 0; n < count; n++) {
|
|
asSEnumValue *e = asNEW(asSEnumValue);
|
|
ReadString(&e->name);
|
|
READ_NUM(e->value);
|
|
ot->enumValues.PushLast(e);
|
|
}
|
|
} else if (ot->flags & asOBJ_TYPEDEF) {
|
|
eTokenType t;
|
|
READ_NUM(t);
|
|
ot->templateSubType = asCDataType::CreatePrimitive(t, false);
|
|
} else {
|
|
ot->derivedFrom = ReadObjectType();
|
|
if (ot->derivedFrom)
|
|
ot->derivedFrom->AddRef();
|
|
|
|
// interfaces[]
|
|
int size;
|
|
READ_NUM(size);
|
|
ot->interfaces.Allocate(size, 0);
|
|
int n;
|
|
for (n = 0; n < size; n++) {
|
|
asCObjectType *intf = ReadObjectType();
|
|
ot->interfaces.PushLast(intf);
|
|
}
|
|
|
|
// properties[]
|
|
READ_NUM(size);
|
|
ot->properties.Allocate(size, 0);
|
|
for (n = 0; n < size; n++) {
|
|
asCObjectProperty *prop = asNEW(asCObjectProperty);
|
|
ReadObjectProperty(prop);
|
|
ot->properties.PushLast(prop);
|
|
}
|
|
|
|
// behaviours
|
|
if (!ot->IsInterface() && ot->flags != asOBJ_TYPEDEF && ot->flags != asOBJ_ENUM) {
|
|
asCScriptFunction *func = ReadFunction();
|
|
engine->scriptFunctions[ot->beh.construct]->Release();
|
|
ot->beh.construct = func->id;
|
|
ot->beh.constructors[0] = func->id;
|
|
func->AddRef();
|
|
|
|
func = ReadFunction();
|
|
if (func) {
|
|
ot->beh.destruct = func->id;
|
|
func->AddRef();
|
|
}
|
|
|
|
func = ReadFunction();
|
|
engine->scriptFunctions[ot->beh.factory]->Release();
|
|
ot->beh.factory = func->id;
|
|
ot->beh.factories[0] = func->id;
|
|
func->AddRef();
|
|
|
|
READ_NUM(size);
|
|
for (n = 0; n < size; n++) {
|
|
asCScriptFunction *func = ReadFunction();
|
|
ot->beh.constructors.PushLast(func->id);
|
|
func->AddRef();
|
|
|
|
func = ReadFunction();
|
|
ot->beh.factories.PushLast(func->id);
|
|
func->AddRef();
|
|
}
|
|
}
|
|
|
|
// methods[]
|
|
READ_NUM(size);
|
|
for (n = 0; n < size; n++) {
|
|
asCScriptFunction *func = ReadFunction();
|
|
ot->methods.PushLast(func->id);
|
|
func->AddRef();
|
|
}
|
|
|
|
// virtualFunctionTable[]
|
|
READ_NUM(size);
|
|
for (n = 0; n < size; n++) {
|
|
asCScriptFunction *func = ReadFunction();
|
|
ot->virtualFunctionTable.PushLast(func);
|
|
func->AddRef();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void asCRestore::WriteString(asCString *str) {
|
|
asUINT len = (asUINT)str->GetLength();
|
|
WRITE_NUM(len);
|
|
stream->Write(str->AddressOf(), (asUINT)len);
|
|
}
|
|
|
|
void asCRestore::ReadString(asCString *str) {
|
|
asUINT len;
|
|
READ_NUM(len);
|
|
str->SetLength(len);
|
|
stream->Read(str->AddressOf(), len);
|
|
}
|
|
|
|
void asCRestore::WriteGlobalProperty(asCGlobalProperty *prop) {
|
|
// TODO: We might be able to avoid storing the name and type of the global
|
|
// properties twice if we merge this with the WriteUsedGlobalProperties.
|
|
WriteString(&prop->name);
|
|
WriteDataType(&prop->type);
|
|
|
|
// Store the initialization function
|
|
if (prop->initFunc) {
|
|
bool f = true;
|
|
WRITE_NUM(f);
|
|
|
|
WriteFunction(prop->initFunc);
|
|
} else {
|
|
bool f = false;
|
|
WRITE_NUM(f);
|
|
}
|
|
}
|
|
|
|
void asCRestore::ReadGlobalProperty() {
|
|
asCString name;
|
|
asCDataType type;
|
|
|
|
ReadString(&name);
|
|
ReadDataType(&type);
|
|
|
|
asCGlobalProperty *prop = module->AllocateGlobalProperty(name.AddressOf(), type);
|
|
|
|
// Read the initialization function
|
|
bool f;
|
|
READ_NUM(f);
|
|
if (f) {
|
|
asCScriptFunction *func = ReadFunction(false, true);
|
|
|
|
// refCount was already set to 1
|
|
prop->initFunc = func;
|
|
}
|
|
}
|
|
|
|
void asCRestore::WriteObjectProperty(asCObjectProperty *prop) {
|
|
WriteString(&prop->name);
|
|
WriteDataType(&prop->type);
|
|
WRITE_NUM(prop->byteOffset);
|
|
}
|
|
|
|
void asCRestore::ReadObjectProperty(asCObjectProperty *prop) {
|
|
ReadString(&prop->name);
|
|
ReadDataType(&prop->type);
|
|
READ_NUM(prop->byteOffset);
|
|
}
|
|
|
|
void asCRestore::WriteDataType(const asCDataType *dt) {
|
|
bool b;
|
|
int t = dt->GetTokenType();
|
|
WRITE_NUM(t);
|
|
WriteObjectType(dt->GetObjectType());
|
|
b = dt->IsObjectHandle();
|
|
WRITE_NUM(b);
|
|
b = dt->IsReadOnly();
|
|
WRITE_NUM(b);
|
|
b = dt->IsHandleToConst();
|
|
WRITE_NUM(b);
|
|
b = dt->IsReference();
|
|
WRITE_NUM(b);
|
|
}
|
|
|
|
void asCRestore::ReadDataType(asCDataType *dt) {
|
|
eTokenType tokenType;
|
|
READ_NUM(tokenType);
|
|
asCObjectType *objType = ReadObjectType();
|
|
bool isObjectHandle;
|
|
READ_NUM(isObjectHandle);
|
|
bool isReadOnly;
|
|
READ_NUM(isReadOnly);
|
|
bool isHandleToConst;
|
|
READ_NUM(isHandleToConst);
|
|
bool isReference;
|
|
READ_NUM(isReference);
|
|
|
|
if (tokenType == ttIdentifier)
|
|
*dt = asCDataType::CreateObject(objType, false);
|
|
else
|
|
*dt = asCDataType::CreatePrimitive(tokenType, false);
|
|
if (isObjectHandle) {
|
|
dt->MakeReadOnly(isHandleToConst);
|
|
dt->MakeHandle(true);
|
|
}
|
|
dt->MakeReadOnly(isReadOnly);
|
|
dt->MakeReference(isReference);
|
|
}
|
|
|
|
void asCRestore::WriteObjectType(asCObjectType *ot) {
|
|
char ch;
|
|
|
|
// Only write the object type name
|
|
if (ot) {
|
|
// Check for template instances/specializations
|
|
if (ot->templateSubType.GetTokenType() != ttUnrecognizedToken && ot != engine->defaultArrayObjectType) {
|
|
ch = 'a';
|
|
WRITE_NUM(ch);
|
|
|
|
if (ot->templateSubType.IsObject()) {
|
|
ch = 's';
|
|
WRITE_NUM(ch);
|
|
WriteObjectType(ot->templateSubType.GetObjectType());
|
|
|
|
if (ot->templateSubType.IsObjectHandle())
|
|
ch = 'h';
|
|
else
|
|
ch = 'o';
|
|
WRITE_NUM(ch);
|
|
} else {
|
|
ch = 't';
|
|
WRITE_NUM(ch);
|
|
eTokenType t = ot->templateSubType.GetTokenType();
|
|
WRITE_NUM(t);
|
|
}
|
|
} else if (ot->flags & asOBJ_TEMPLATE_SUBTYPE) {
|
|
ch = 's';
|
|
WRITE_NUM(ch);
|
|
WriteString(&ot->name);
|
|
} else {
|
|
ch = 'o';
|
|
WRITE_NUM(ch);
|
|
WriteString(&ot->name);
|
|
}
|
|
} else {
|
|
ch = '\0';
|
|
WRITE_NUM(ch);
|
|
// Write a null string
|
|
asDWORD null = 0;
|
|
WRITE_NUM(null);
|
|
}
|
|
}
|
|
|
|
asCObjectType *asCRestore::ReadObjectType() {
|
|
asCObjectType *ot;
|
|
char ch;
|
|
READ_NUM(ch);
|
|
if (ch == 'a') {
|
|
READ_NUM(ch);
|
|
if (ch == 's') {
|
|
ot = ReadObjectType();
|
|
asCDataType dt = asCDataType::CreateObject(ot, false);
|
|
|
|
READ_NUM(ch);
|
|
if (ch == 'h')
|
|
dt.MakeHandle(true);
|
|
|
|
dt.MakeArray(engine);
|
|
ot = dt.GetObjectType();
|
|
|
|
asASSERT(ot);
|
|
} else {
|
|
eTokenType tokenType;
|
|
READ_NUM(tokenType);
|
|
asCDataType dt = asCDataType::CreatePrimitive(tokenType, false);
|
|
dt.MakeArray(engine);
|
|
ot = dt.GetObjectType();
|
|
|
|
asASSERT(ot);
|
|
}
|
|
} else if (ch == 's') {
|
|
// Read the name of the template subtype
|
|
asCString typeName;
|
|
ReadString(&typeName);
|
|
|
|
// Find the template subtype
|
|
for (asUINT n = 0; n < engine->templateSubTypes.GetLength(); n++) {
|
|
if (engine->templateSubTypes[n] && engine->templateSubTypes[n]->name == typeName) {
|
|
ot = engine->templateSubTypes[n];
|
|
break;
|
|
}
|
|
}
|
|
|
|
// TODO: Should give a friendly error in case the template type isn't found
|
|
asASSERT(ot);
|
|
} else {
|
|
// Read the object type name
|
|
asCString typeName;
|
|
ReadString(&typeName);
|
|
|
|
if (typeName.GetLength() && typeName != "_builtin_object_") {
|
|
// Find the object type
|
|
ot = module->GetObjectType(typeName.AddressOf());
|
|
if (!ot)
|
|
ot = engine->GetObjectType(typeName.AddressOf());
|
|
|
|
asASSERT(ot);
|
|
} else if (typeName == "_builtin_object_") {
|
|
ot = &engine->scriptTypeBehaviours;
|
|
} else
|
|
ot = 0;
|
|
}
|
|
|
|
return ot;
|
|
}
|
|
|
|
void asCRestore::WriteByteCode(asDWORD *bc, int length) {
|
|
while (length) {
|
|
asDWORD c = *(asBYTE *)bc;
|
|
|
|
if (c == asBC_ALLOC) {
|
|
WRITE_NUM(*bc++);
|
|
asDWORD tmp[MAX_DATA_SIZE];
|
|
int n;
|
|
for (n = 0; n < asBCTypeSize[asBCInfo[c].type] - 1; n++)
|
|
tmp[n] = *bc++;
|
|
|
|
// Translate the object type
|
|
asCObjectType *ot = *(asCObjectType **)tmp;
|
|
*(int *)tmp = FindObjectTypeIdx(ot);
|
|
|
|
// Translate the constructor func id, if it is a script class
|
|
if (ot->flags & asOBJ_SCRIPT_OBJECT)
|
|
*(int *)&tmp[AS_PTR_SIZE] = FindFunctionIndex(engine->scriptFunctions[*(int *)&tmp[AS_PTR_SIZE]]);
|
|
|
|
for (n = 0; n < asBCTypeSize[asBCInfo[c].type] - 1; n++)
|
|
WRITE_NUM(tmp[n]);
|
|
} else if (c == asBC_FREE || c == asBC_REFCPY || c == asBC_OBJTYPE) {
|
|
WRITE_NUM(*bc++);
|
|
// Translate object type pointers into indices
|
|
asDWORD tmp[MAX_DATA_SIZE];
|
|
int n;
|
|
for (n = 0; n < asBCTypeSize[asBCInfo[c].type] - 1; n++)
|
|
tmp[n] = *bc++;
|
|
|
|
*(int *)tmp = FindObjectTypeIdx(*(asCObjectType **)tmp);
|
|
|
|
for (n = 0; n < asBCTypeSize[asBCInfo[c].type] - 1; n++)
|
|
WRITE_NUM(tmp[n]);
|
|
} else if (c == asBC_TYPEID) {
|
|
WRITE_NUM(*bc++);
|
|
|
|
// Translate type ids into indices
|
|
asDWORD tmp[MAX_DATA_SIZE];
|
|
int n;
|
|
for (n = 0; n < asBCTypeSize[asBCInfo[c].type] - 1; n++)
|
|
tmp[n] = *bc++;
|
|
|
|
*(int *)tmp = FindTypeIdIdx(*(int *)tmp);
|
|
|
|
for (n = 0; n < asBCTypeSize[asBCInfo[c].type] - 1; n++)
|
|
WRITE_NUM(tmp[n]);
|
|
} else if (c == asBC_CALL || c == asBC_CALLINTF || c == asBC_CALLSYS) {
|
|
WRITE_NUM(*bc++);
|
|
|
|
// Translate the function id
|
|
asDWORD tmp[MAX_DATA_SIZE];
|
|
int n;
|
|
for (n = 0; n < asBCTypeSize[asBCInfo[c].type] - 1; n++)
|
|
tmp[n] = *bc++;
|
|
|
|
*(int *)tmp = FindFunctionIndex(engine->scriptFunctions[*(int *)tmp]);
|
|
|
|
for (n = 0; n < asBCTypeSize[asBCInfo[c].type] - 1; n++)
|
|
WRITE_NUM(tmp[n]);
|
|
} else if (c == asBC_STR) {
|
|
asDWORD tmp = *bc++;
|
|
|
|
// Translate the string constant id
|
|
asWORD *arg = ((asWORD *)&tmp) + 1;
|
|
*arg = FindStringConstantIndex(*arg);
|
|
WRITE_NUM(tmp);
|
|
} else if (c == asBC_CALLBND) {
|
|
WRITE_NUM(*bc++);
|
|
|
|
// Translate the function id
|
|
int funcId = *bc++;
|
|
for (asUINT n = 0; n < module->bindInformations.GetLength(); n++)
|
|
if (module->bindInformations[n]->importedFunctionSignature->id == funcId) {
|
|
funcId = n;
|
|
break;
|
|
}
|
|
|
|
WRITE_NUM(funcId);
|
|
} else if (c == asBC_PGA || c == asBC_LDG || c == asBC_PshG4 || c == asBC_LdGRdR4 || c == asBC_CpyGtoV4 ||
|
|
c == asBC_CpyVtoG4 || c == asBC_SetG4) {
|
|
WRITE_NUM(*bc++);
|
|
|
|
// Translate global variable pointers into indices
|
|
asDWORD tmp[MAX_DATA_SIZE];
|
|
int n;
|
|
for (n = 0; n < asBCTypeSize[asBCInfo[c].type] - 1; n++)
|
|
tmp[n] = *bc++;
|
|
|
|
*(int *)tmp = FindGlobalPropPtrIndex(*(void **)tmp);
|
|
|
|
for (n = 0; n < asBCTypeSize[asBCInfo[c].type] - 1; n++)
|
|
WRITE_NUM(tmp[n]);
|
|
} else {
|
|
// Store the bc as is
|
|
for (int n = 0; n < asBCTypeSize[asBCInfo[c].type]; n++)
|
|
WRITE_NUM(*bc++);
|
|
}
|
|
|
|
length -= asBCTypeSize[asBCInfo[c].type];
|
|
}
|
|
}
|
|
|
|
void asCRestore::ReadByteCode(asDWORD *bc, int length) {
|
|
while (length) {
|
|
asDWORD c;
|
|
READ_NUM(c);
|
|
*bc = c;
|
|
bc += 1;
|
|
c = *(asBYTE *)&c;
|
|
|
|
// Read the bc as is
|
|
for (int n = 1; n < asBCTypeSize[asBCInfo[c].type]; n++)
|
|
READ_NUM(*bc++);
|
|
|
|
length -= asBCTypeSize[asBCInfo[c].type];
|
|
}
|
|
}
|
|
|
|
void asCRestore::WriteUsedTypeIds() {
|
|
asUINT count = (asUINT)usedTypeIds.GetLength();
|
|
WRITE_NUM(count);
|
|
for (asUINT n = 0; n < count; n++)
|
|
WriteDataType(engine->GetDataTypeFromTypeId(usedTypeIds[n]));
|
|
}
|
|
|
|
void asCRestore::ReadUsedTypeIds() {
|
|
asUINT n;
|
|
asUINT count;
|
|
READ_NUM(count);
|
|
usedTypeIds.SetLength(count);
|
|
for (n = 0; n < count; n++) {
|
|
asCDataType dt;
|
|
ReadDataType(&dt);
|
|
usedTypeIds[n] = engine->GetTypeIdFromDataType(dt);
|
|
}
|
|
}
|
|
|
|
int asCRestore::FindGlobalPropPtrIndex(void *ptr) {
|
|
int i = usedGlobalProperties.IndexOf(ptr);
|
|
if (i >= 0)
|
|
return i;
|
|
|
|
usedGlobalProperties.PushLast(ptr);
|
|
return (int)usedGlobalProperties.GetLength() - 1;
|
|
}
|
|
|
|
void asCRestore::WriteUsedGlobalProps() {
|
|
int c = (int)usedGlobalProperties.GetLength();
|
|
WRITE_NUM(c);
|
|
|
|
for (int n = 0; n < c; n++) {
|
|
size_t *p = (size_t *)usedGlobalProperties[n];
|
|
|
|
// First search for the global in the module
|
|
char moduleProp = 0;
|
|
asCGlobalProperty *prop = 0;
|
|
for (int i = 0; i < (signed)module->scriptGlobals.GetLength(); i++) {
|
|
if (p == module->scriptGlobals[i]->GetAddressOfValue()) {
|
|
prop = module->scriptGlobals[i];
|
|
moduleProp = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If it is not in the module, it must be an application registered property
|
|
if (!prop) {
|
|
for (int i = 0; i < (signed)engine->registeredGlobalProps.GetLength(); i++) {
|
|
if (engine->registeredGlobalProps[i]->GetAddressOfValue() == p) {
|
|
prop = engine->registeredGlobalProps[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
asASSERT(prop);
|
|
|
|
// Store the name and type of the property so we can find it again on loading
|
|
WriteString(&prop->name);
|
|
WriteDataType(&prop->type);
|
|
|
|
// Also store whether the property is a module property or a registered property
|
|
WRITE_NUM(moduleProp);
|
|
}
|
|
}
|
|
|
|
void asCRestore::ReadUsedGlobalProps() {
|
|
int c;
|
|
READ_NUM(c);
|
|
|
|
usedGlobalProperties.SetLength(c);
|
|
|
|
for (int n = 0; n < c; n++) {
|
|
asCString name;
|
|
asCDataType type;
|
|
char moduleProp;
|
|
|
|
ReadString(&name);
|
|
ReadDataType(&type);
|
|
READ_NUM(moduleProp);
|
|
|
|
// Find the real property
|
|
void *prop = 0;
|
|
if (moduleProp) {
|
|
for (asUINT p = 0; p < module->scriptGlobals.GetLength(); p++) {
|
|
if (module->scriptGlobals[p]->name == name && module->scriptGlobals[p]->type == type) {
|
|
prop = module->scriptGlobals[p]->GetAddressOfValue();
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
for (asUINT p = 0; p < engine->registeredGlobalProps.GetLength(); p++) {
|
|
if (engine->registeredGlobalProps[p] && engine->registeredGlobalProps[p]->name == name &&
|
|
engine->registeredGlobalProps[p]->type == type) {
|
|
prop = engine->registeredGlobalProps[p]->GetAddressOfValue();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: If the property isn't found, we must give an error
|
|
asASSERT(prop);
|
|
|
|
usedGlobalProperties[n] = prop;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------
|
|
// Miscellaneous
|
|
//---------------------------------------------------------------------------------------------------
|
|
|
|
int asCRestore::FindFunctionIndex(asCScriptFunction *func) {
|
|
asUINT n;
|
|
for (n = 0; n < usedFunctions.GetLength(); n++) {
|
|
if (usedFunctions[n] == func)
|
|
return n;
|
|
}
|
|
|
|
usedFunctions.PushLast(func);
|
|
return (int)usedFunctions.GetLength() - 1;
|
|
}
|
|
|
|
asCScriptFunction *asCRestore::FindFunction(int idx) { return usedFunctions[idx]; }
|
|
|
|
void asCRestore::TranslateFunction(asCScriptFunction *func) {
|
|
asUINT n;
|
|
asDWORD *bc = func->byteCode.AddressOf();
|
|
for (n = 0; n < func->byteCode.GetLength();) {
|
|
int c = *(asBYTE *)&bc[n];
|
|
if (c == asBC_FREE || c == asBC_REFCPY || c == asBC_OBJTYPE) {
|
|
// Translate the index to the true object type
|
|
asPTRWORD *ot = (asPTRWORD *)&bc[n + 1];
|
|
*(asCObjectType **)ot = FindObjectType(*(int *)ot);
|
|
} else if (c == asBC_TYPEID) {
|
|
// Translate the index to the type id
|
|
int *tid = (int *)&bc[n + 1];
|
|
*tid = FindTypeId(*tid);
|
|
} else if (c == asBC_CALL || c == asBC_CALLINTF || c == asBC_CALLSYS) {
|
|
// Translate the index to the func id
|
|
int *fid = (int *)&bc[n + 1];
|
|
*fid = FindFunction(*fid)->id;
|
|
} else if (c == asBC_ALLOC) {
|
|
// Translate the index to the true object type
|
|
asPTRWORD *arg = (asPTRWORD *)&bc[n + 1];
|
|
*(asCObjectType **)arg = FindObjectType(*(int *)arg);
|
|
|
|
// If the object type is a script class then the constructor id must be translated
|
|
asCObjectType *ot = *(asCObjectType **)arg;
|
|
if (ot->flags & asOBJ_SCRIPT_OBJECT) {
|
|
int *fid = (int *)&bc[n + 1 + AS_PTR_SIZE];
|
|
*fid = FindFunction(*fid)->id;
|
|
}
|
|
} else if (c == asBC_STR) {
|
|
// Translate the index to the true string id
|
|
asWORD *arg = ((asWORD *)&bc[n]) + 1;
|
|
|
|
*arg = usedStringConstants[*arg];
|
|
} else if (c == asBC_CALLBND) {
|
|
// Translate the function id
|
|
int *fid = (int *)&bc[n + 1];
|
|
*fid = module->bindInformations[*fid]->importedFunctionSignature->id;
|
|
} else if (c == asBC_PGA || c == asBC_LDG || c == asBC_PshG4 || c == asBC_LdGRdR4 || c == asBC_CpyGtoV4 ||
|
|
c == asBC_CpyVtoG4 || c == asBC_SetG4) {
|
|
// Translate the global var index to pointer
|
|
asPTRWORD *index = (asPTRWORD *)&bc[n + 1];
|
|
*(void **)index = usedGlobalProperties[*(int *)index];
|
|
}
|
|
|
|
n += asBCTypeSize[asBCInfo[c].type];
|
|
}
|
|
}
|
|
|
|
int asCRestore::FindTypeIdIdx(int typeId) {
|
|
asUINT n;
|
|
for (n = 0; n < usedTypeIds.GetLength(); n++) {
|
|
if (usedTypeIds[n] == typeId)
|
|
return n;
|
|
}
|
|
|
|
usedTypeIds.PushLast(typeId);
|
|
return (int)usedTypeIds.GetLength() - 1;
|
|
}
|
|
|
|
int asCRestore::FindTypeId(int idx) { return usedTypeIds[idx]; }
|
|
|
|
int asCRestore::FindObjectTypeIdx(asCObjectType *obj) {
|
|
asUINT n;
|
|
for (n = 0; n < usedTypes.GetLength(); n++) {
|
|
if (usedTypes[n] == obj)
|
|
return n;
|
|
}
|
|
|
|
usedTypes.PushLast(obj);
|
|
return (int)usedTypes.GetLength() - 1;
|
|
}
|
|
|
|
asCObjectType *asCRestore::FindObjectType(int idx) { return usedTypes[idx]; }
|
|
|
|
END_AS_NAMESPACE
|