Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.
Layout:
engine/ MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
models) + image codec; the minimal rp/ headers the audio HAL needs
game/ reconstructed BT logic + surviving-original BT source + fwd shims
+ WinMain launcher
content/ full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
docs/ format specs + reconstruction ledgers
reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
tools/ MP console emulator + map/resource scanners
One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1204 lines
29 KiB
C++
1204 lines
29 KiB
C++
#include "munga.h"
|
|
#pragma hdrstop
|
|
|
|
#include "objstrm.h"
|
|
#include "fileutil.h"
|
|
#include "resource.h"
|
|
#include "cstr.h"
|
|
#include "namelist.h"
|
|
#include "notation.h"
|
|
|
|
//#############################################################################
|
|
//########################## ObjectStream ###############################
|
|
//#############################################################################
|
|
|
|
ObjectID ObjectStream::lastObjectID = NullObjectID;
|
|
|
|
//
|
|
//#############################################################################
|
|
// ObjectStream
|
|
//#############################################################################
|
|
//
|
|
ObjectStream::ObjectStream()
|
|
{
|
|
resourceFile = NULL;
|
|
macroSocket = NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// ObjectStream
|
|
//#############################################################################
|
|
//
|
|
ObjectStream::ObjectStream(
|
|
void *stream_start,
|
|
size_t stream_size
|
|
):
|
|
DynamicMemoryStream(stream_start, stream_size)
|
|
{
|
|
resourceFile = NULL;
|
|
macroSocket = NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// ObjectStream
|
|
//#############################################################################
|
|
//
|
|
ObjectStream::ObjectStream(ResourceDescription *resource_description):
|
|
DynamicMemoryStream(
|
|
resource_description->resourceAddress,
|
|
resource_description->resourceSize
|
|
)
|
|
{
|
|
resourceFile = NULL;
|
|
macroSocket = NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// ~ObjectStream
|
|
//#############################################################################
|
|
//
|
|
ObjectStream::~ObjectStream()
|
|
{
|
|
Verify(resourceFile == NULL);
|
|
Verify(macroSocket == NULL);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// TestInstance
|
|
//#############################################################################
|
|
//
|
|
Logical
|
|
ObjectStream::TestInstance() const
|
|
{
|
|
DynamicMemoryStream::TestInstance();
|
|
if (resourceFile != NULL)
|
|
{
|
|
Check(resourceFile);
|
|
}
|
|
if (macroSocket != NULL)
|
|
{
|
|
Check(macroSocket);
|
|
}
|
|
return True;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// MakeUniqueObjectID
|
|
//#############################################################################
|
|
//
|
|
ObjectID
|
|
ObjectStream::MakeUniqueObjectID()
|
|
{
|
|
lastObjectID++;
|
|
Verify(lastObjectID < ULONG_MAX);
|
|
return lastObjectID;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// CreateObjects
|
|
//#############################################################################
|
|
//
|
|
void
|
|
ObjectStream::CreateObjects()
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// While the stream is not empty, read objects...
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
while (GetBytesRemaining() > 0L)
|
|
{
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Read the class ID and object ID
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
Enumeration class_ID;
|
|
ObjectID object_ID;
|
|
|
|
MemoryStream_Read(this, &class_ID);
|
|
MemoryStream_Read(this, &object_ID);
|
|
RewindPointer(sizeof(object_ID));
|
|
RewindPointer(sizeof(class_ID));
|
|
|
|
Verify(class_ID != RegisteredClass::NullClassID);
|
|
Verify(object_ID != NullObjectID);
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Read the object
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
RegisteredClass *object = MakeObjectImplementation(class_ID);
|
|
Register_Object(object);
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Perform post creation processing
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
CreatedObjectImplementation(object, object_ID);
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// MakeObject
|
|
//#############################################################################
|
|
//
|
|
RegisteredClass*
|
|
ObjectStream::MakeObjectImplementation(Enumeration class_ID)
|
|
{
|
|
Check(this);
|
|
Verify(class_ID != RegisteredClass::NullClassID);
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// HACK - Constructors should be referenced through registration, for
|
|
// now just use a switch statement
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
RegisteredClass *object = NULL;
|
|
|
|
switch (class_ID)
|
|
{
|
|
default:
|
|
Dump(class_ID);
|
|
Fail("ObjectStream::MakeObject - Unknown class ID");
|
|
break;
|
|
}
|
|
return object;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// CreatedObject
|
|
//#############################################################################
|
|
//
|
|
void
|
|
ObjectStream::CreatedObjectImplementation(
|
|
RegisteredClass*,
|
|
ObjectID
|
|
)
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
// Default behavior is to do nothing
|
|
//
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// BuildFromNotationFile
|
|
//#############################################################################
|
|
//
|
|
void
|
|
ObjectStream::BuildFromNotationFile(
|
|
NotationFile *notation_file,
|
|
ResourceFile *resource_file
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(notation_file);
|
|
Check(resource_file);
|
|
|
|
//
|
|
// Remember resource file
|
|
//
|
|
Verify(resourceFile == NULL);
|
|
resourceFile = resource_file;
|
|
|
|
//
|
|
// Make the macro socket
|
|
//
|
|
macroSocket = new MacroSocket(NULL, True);
|
|
Register_Object(macroSocket);
|
|
|
|
//
|
|
// Parse...
|
|
//
|
|
ParseNotationFile(notation_file);
|
|
|
|
//
|
|
// Delete macros
|
|
//
|
|
{
|
|
MacroIterator iterator(macroSocket);
|
|
iterator.DeletePlugs();
|
|
}
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
Unregister_Object(macroSocket);
|
|
delete macroSocket;
|
|
macroSocket = NULL;
|
|
resourceFile = NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// ParseNotationFile
|
|
//#############################################################################
|
|
//
|
|
void
|
|
ObjectStream::ParseNotationFile(NotationFile *notation_file)
|
|
{
|
|
Check(this);
|
|
Check(notation_file);
|
|
Verify(DoesNotationFileExist(notation_file));
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Parse pages
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
NameList *page_name_list;
|
|
NameList::Entry *page_entry;
|
|
|
|
page_name_list = notation_file->MakePageList();
|
|
Register_Object(page_name_list);
|
|
page_entry = page_name_list->GetFirstEntry();
|
|
while (page_entry != NULL)
|
|
{
|
|
Check(page_entry);
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Read the page name
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
CString inculde_name_string("include");
|
|
CString macro_name_string("macro");
|
|
CString page_name_string;
|
|
|
|
Check_Pointer(page_entry->GetName());
|
|
page_name_string = page_entry->GetName();
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Skip "no-ops"
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
if (page_name_string.operator [](0) == '!')
|
|
{
|
|
page_entry = page_entry->GetNextEntry();
|
|
continue;
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Make the entry list
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
NameList *entry_list =
|
|
notation_file->MakeEntryList(
|
|
(NotationFile::NotePage*)page_entry->GetData()
|
|
);
|
|
Register_Object(entry_list);
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Read "included" files
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
if (page_name_string == inculde_name_string)
|
|
{
|
|
ReadIncludedFiles(entry_list);
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Read "macros"
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
else if (page_name_string == macro_name_string)
|
|
{
|
|
ReadMacros(entry_list);
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Read the class ID and object name
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
else
|
|
{
|
|
Tell(" Class " << page_name_string << "\n");
|
|
|
|
//
|
|
// Get class ID and object ID
|
|
//
|
|
Enumeration class_ID;
|
|
ObjectID object_ID;
|
|
|
|
class_ID = RegisteredClass::GetClassID(page_name_string);
|
|
if (class_ID == RegisteredClass::NullClassID)
|
|
{
|
|
Dump(page_name_string);
|
|
Dump(class_ID);
|
|
}
|
|
Verify(class_ID != RegisteredClass::NullClassID);
|
|
object_ID = MakeUniqueObjectID();
|
|
Verify(object_ID != NullObjectID);
|
|
|
|
//
|
|
// Get object name
|
|
//
|
|
const char *object_name;
|
|
CString object_name_string;
|
|
|
|
PerformMacroReplacement(entry_list);
|
|
if (
|
|
(object_name = (const char *)entry_list->FindData("name")) != NULL
|
|
)
|
|
{
|
|
object_name_string = object_name;
|
|
}
|
|
Check(&object_name_string);
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// Build the object stream from the page
|
|
//--------------------------------------------------------------------
|
|
//
|
|
BuildFromPageImplementation(entry_list, class_ID, object_ID);
|
|
CleanupMacroReplacement(entry_list);
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// Perform post build processing
|
|
//--------------------------------------------------------------------
|
|
//
|
|
BuiltFromPageImplementation(class_ID, object_ID, object_name_string);
|
|
}
|
|
|
|
Unregister_Object(entry_list);
|
|
delete entry_list;
|
|
page_entry = page_entry->GetNextEntry();
|
|
}
|
|
|
|
Unregister_Object(page_name_list);
|
|
delete page_name_list;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// ReadIncludedFiles
|
|
//#############################################################################
|
|
//
|
|
void
|
|
ObjectStream::ReadIncludedFiles(NameList *entry_list)
|
|
{
|
|
Check(this);
|
|
NameList::Entry *entry;
|
|
|
|
Check(entry_list);
|
|
entry = entry_list->GetFirstEntry();
|
|
while (entry != NULL)
|
|
{
|
|
Check(entry);
|
|
if (entry->IsName("file"))
|
|
{
|
|
Check_Pointer(entry->GetChar());
|
|
|
|
CString included_file_name_string;
|
|
included_file_name_string = entry->GetChar();
|
|
Tell(" File " << included_file_name_string << "\n");
|
|
|
|
NotationFile included_notation_file(included_file_name_string);
|
|
Check(&included_notation_file);
|
|
ParseNotationFile(&included_notation_file);
|
|
}
|
|
entry = entry->GetNextEntry();
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// ReadMacros
|
|
//#############################################################################
|
|
//
|
|
void
|
|
ObjectStream::ReadMacros(NameList *entry_list)
|
|
{
|
|
Check(this);
|
|
NameList::Entry *entry;
|
|
|
|
Check(entry_list);
|
|
entry = entry_list->GetFirstEntry();
|
|
while (entry != NULL)
|
|
{
|
|
Check(entry);
|
|
if (entry->GetData() != NULL)
|
|
{
|
|
Check_Pointer(entry->GetName());
|
|
Check_Pointer(entry->GetChar());
|
|
|
|
CString macro_name;
|
|
MacroValue *macro_value;
|
|
MacroValue *current_macro_value;
|
|
|
|
macro_name = entry->GetName();
|
|
macro_value = new MacroValue(entry->GetChar());
|
|
Register_Object(macro_value);
|
|
|
|
Check(macroSocket);
|
|
if ((current_macro_value = macroSocket->Find(macro_name)) != NULL)
|
|
{
|
|
Unregister_Object(current_macro_value);
|
|
delete current_macro_value;
|
|
}
|
|
macroSocket->AddValue(macro_value, macro_name);
|
|
}
|
|
entry = entry->GetNextEntry();
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// PerformMacroReplacement
|
|
//#############################################################################
|
|
//
|
|
void
|
|
ObjectStream::PerformMacroReplacement(NameList *entry_list)
|
|
{
|
|
Check(this);
|
|
NameList::Entry *entry;
|
|
|
|
Check(entry_list);
|
|
entry = entry_list->GetFirstEntry();
|
|
while (entry != NULL)
|
|
{
|
|
Check(entry);
|
|
if (entry->GetData() != NULL)
|
|
{
|
|
CString value_string(entry->GetChar());
|
|
|
|
//
|
|
// Create a replacement string by matching each token in the
|
|
// value against the tokens in the macro table
|
|
//
|
|
CString replacement_string;
|
|
CString token_string;
|
|
CString delimiter_string(",");
|
|
CString empty_string;
|
|
int i = 0;
|
|
|
|
Check(&value_string);
|
|
Check(&empty_string);
|
|
while ((token_string = value_string.GetNthToken(i)) != empty_string)
|
|
{
|
|
Check(&token_string);
|
|
|
|
//
|
|
// Append delimter
|
|
//
|
|
if (replacement_string != empty_string)
|
|
{
|
|
replacement_string += delimiter_string;
|
|
}
|
|
|
|
//
|
|
// Does a macro exist for this token? If so, use it, otherwise
|
|
// use the original token
|
|
//
|
|
#if 0
|
|
MacroValue *macro_value;
|
|
|
|
Check(macroSocket);
|
|
if ((macro_value = macroSocket->Find(token_string)) != NULL)
|
|
{
|
|
Check(macro_value);
|
|
Check(&replacement_string);
|
|
replacement_string += macro_value->GetItem();
|
|
}
|
|
else
|
|
{
|
|
replacement_string += token_string;
|
|
}
|
|
#else
|
|
replacement_string += DeriveMacroValue(token_string);
|
|
#endif
|
|
i++;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for the string and assign it to the entry
|
|
//
|
|
size_t size;
|
|
char *pointer;
|
|
|
|
size = replacement_string.Length() + 1;
|
|
#if 0
|
|
pointer = (char*)malloc(size);
|
|
#else
|
|
pointer = new char[size];
|
|
#endif
|
|
Register_Pointer(pointer);
|
|
Str_Copy(pointer, ((const char*)replacement_string), size);
|
|
entry->dataReference = pointer;
|
|
}
|
|
entry = entry->GetNextEntry();
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
CString
|
|
ObjectStream::DeriveMacroValue(const CString &token_string)
|
|
{
|
|
Check(this);
|
|
Check(&token_string);
|
|
|
|
MacroValue *macro_value;
|
|
CString replacement_string = token_string;
|
|
|
|
Check(macroSocket);
|
|
while ((macro_value = macroSocket->Find(replacement_string)) != NULL)
|
|
{
|
|
Check(macro_value);
|
|
replacement_string = macro_value->GetItem();
|
|
}
|
|
return replacement_string;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// CleanupMacroReplacement
|
|
//#############################################################################
|
|
//
|
|
void
|
|
ObjectStream::CleanupMacroReplacement(NameList *entry_list)
|
|
{
|
|
Check(this);
|
|
NameList::Entry *entry;
|
|
|
|
Check(entry_list);
|
|
entry = entry_list->GetFirstEntry();
|
|
while (entry != NULL)
|
|
{
|
|
Check(entry);
|
|
if (entry->GetData() != NULL)
|
|
{
|
|
char *replacement_string = entry->GetChar();
|
|
|
|
Unregister_Pointer(replacement_string);
|
|
#if 0
|
|
free(replacement_string);
|
|
#else
|
|
delete[] replacement_string;
|
|
#endif
|
|
}
|
|
entry = entry->GetNextEntry();
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// BuildFromPage
|
|
//#############################################################################
|
|
//
|
|
void
|
|
ObjectStream::BuildFromPageImplementation(
|
|
NameList*,
|
|
Enumeration class_ID,
|
|
ObjectID
|
|
)
|
|
{
|
|
Check(this);
|
|
Verify(class_ID != RegisteredClass::NullClassID);
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// HACK - Page interpreters should be referenced through registration,
|
|
// for now just use a switch statement
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
switch (class_ID)
|
|
{
|
|
default:
|
|
Dump(class_ID);
|
|
Fail("ObjectStream::BuildFromPage - Unknown class ID");
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// BuiltFromPage
|
|
//#############################################################################
|
|
//
|
|
void
|
|
ObjectStream::BuiltFromPageImplementation(
|
|
Enumeration,
|
|
ObjectID,
|
|
const CString&
|
|
)
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
// Default behavior is to do nothing
|
|
//
|
|
}
|
|
|
|
//#############################################################################
|
|
//####################### PlugStreamManager #############################
|
|
//#############################################################################
|
|
|
|
PlugStreamManager PlugStreamManager::plugStreamManager;
|
|
|
|
#define PLUGSTREAMMANAGER_HASHSIZE (500)
|
|
|
|
//
|
|
//#############################################################################
|
|
// PlugStreamManager
|
|
//#############################################################################
|
|
//
|
|
PlugStreamManager::PlugStreamManager():
|
|
plugIndex(PLUGSTREAMMANAGER_HASHSIZE, NULL, True),
|
|
objectIDIndex(NULL, True)
|
|
{
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// ~PlugStreamManager
|
|
//#############################################################################
|
|
//
|
|
PlugStreamManager::~PlugStreamManager()
|
|
{
|
|
Cleanup();
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// TestInstance
|
|
//#############################################################################
|
|
//
|
|
Logical
|
|
PlugStreamManager::TestInstance() const
|
|
{
|
|
Node::TestInstance();
|
|
Check(&plugIndex);
|
|
Check(&objectIDIndex);
|
|
return True;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// Cleanup
|
|
//#############################################################################
|
|
//
|
|
void
|
|
PlugStreamManager::Cleanup()
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
// Delete static objects
|
|
//
|
|
{
|
|
TreeIteratorOf<ObjectIDPlug*, CString> iterator(&objectIDIndex);
|
|
|
|
Check(&iterator);
|
|
iterator.DeletePlugs();
|
|
}
|
|
{
|
|
HashIteratorOf<Plug*, ObjectID> iterator(&plugIndex);
|
|
|
|
Check(&iterator);
|
|
iterator.DeletePlugs();
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// AddPlug
|
|
//#############################################################################
|
|
//
|
|
void
|
|
PlugStreamManager::AddPlug(
|
|
Plug *plug,
|
|
ObjectID object_ID
|
|
)
|
|
{
|
|
Check(plug);
|
|
Check(&plugStreamManager);
|
|
plugStreamManager.plugIndex.AddValue(plug, object_ID);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// FindPlug
|
|
//#############################################################################
|
|
//
|
|
Plug*
|
|
PlugStreamManager::FindPlug(ObjectID object_ID)
|
|
{
|
|
Check(&plugStreamManager);
|
|
return plugStreamManager.plugIndex.Find(object_ID);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// AddPlugName
|
|
//#############################################################################
|
|
//
|
|
void
|
|
PlugStreamManager::AddPlugName(
|
|
ObjectID object_ID,
|
|
const CString &object_name_string
|
|
)
|
|
{
|
|
Check(&object_name_string);
|
|
|
|
ObjectIDPlug *object_ID_plug =
|
|
new ObjectIDPlug(object_ID);
|
|
Register_Object(object_ID_plug);
|
|
|
|
Check(&plugStreamManager.objectIDIndex);
|
|
#if DEBUG_LEVEL>0
|
|
if (plugStreamManager.objectIDIndex.Find(object_name_string) != NULL)
|
|
{
|
|
Dump(object_name_string);
|
|
}
|
|
#endif
|
|
plugStreamManager.objectIDIndex.AddValue(
|
|
object_ID_plug,
|
|
object_name_string
|
|
);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// FindPlugName
|
|
//#############################################################################
|
|
//
|
|
ObjectID
|
|
PlugStreamManager::FindPlugName(const CString &object_name_string)
|
|
{
|
|
Check(&object_name_string);
|
|
Check(&plugStreamManager.objectIDIndex);
|
|
ObjectIDPlug *plug = plugStreamManager.objectIDIndex.Find(object_name_string);
|
|
if (plug != NULL)
|
|
{
|
|
Check(plug);
|
|
return plug->GetItem();
|
|
}
|
|
return NullObjectID;
|
|
}
|
|
|
|
//#############################################################################
|
|
//########################### PlugStream ################################
|
|
//#############################################################################
|
|
|
|
//
|
|
//#############################################################################
|
|
// PlugStream
|
|
//#############################################################################
|
|
//
|
|
PlugStream::PlugStream()
|
|
{
|
|
localPlugIndex = NULL;
|
|
localObjectIDIndex = NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// PlugStream
|
|
//#############################################################################
|
|
//
|
|
PlugStream::PlugStream(
|
|
void *stream_start,
|
|
size_t stream_size
|
|
):
|
|
ObjectStream(stream_start, stream_size)
|
|
{
|
|
localPlugIndex = NULL;
|
|
localObjectIDIndex = NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// PlugStream
|
|
//#############################################################################
|
|
//
|
|
PlugStream::PlugStream(ResourceDescription *resource_description):
|
|
ObjectStream(resource_description)
|
|
{
|
|
localPlugIndex = NULL;
|
|
localObjectIDIndex = NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// ~PlugStream
|
|
//#############################################################################
|
|
//
|
|
PlugStream::~PlugStream()
|
|
{
|
|
Verify(localPlugIndex == NULL);
|
|
Verify(localObjectIDIndex == NULL);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// TestInstance
|
|
//#############################################################################
|
|
//
|
|
Logical
|
|
PlugStream::TestInstance() const
|
|
{
|
|
ObjectStream::TestInstance();
|
|
if (localPlugIndex != NULL)
|
|
{
|
|
Check(localPlugIndex);
|
|
}
|
|
if (localObjectIDIndex != NULL)
|
|
{
|
|
Check(localObjectIDIndex);
|
|
}
|
|
return True;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// CreateObjects
|
|
//#############################################################################
|
|
//
|
|
void
|
|
PlugStream::CreateObjects()
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Keep local object address index
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
LocalPlugIndex
|
|
local_index(NULL, True);
|
|
|
|
Check(&local_index);
|
|
localPlugIndex = &local_index;
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Parse object stream
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
ObjectStream::CreateObjects();
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Forget local object address index
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
localPlugIndex = NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// CreatedObject
|
|
//#############################################################################
|
|
//
|
|
void
|
|
PlugStream::CreatedObjectImplementation(
|
|
RegisteredClass *object,
|
|
ObjectID object_ID
|
|
)
|
|
{
|
|
Check(this);
|
|
AddLocalPlug(Cast_Object(Plug*, object), object_ID);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// AddLocalPlugAddress
|
|
//#############################################################################
|
|
//
|
|
void
|
|
PlugStream::AddLocalPlug(
|
|
Plug *plug,
|
|
ObjectID object_ID
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(localPlugIndex);
|
|
localPlugIndex->AddValue(plug, object_ID);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// AddGlobalPlugAddress
|
|
//#############################################################################
|
|
//
|
|
void
|
|
PlugStream::AddGlobalPlug(
|
|
Plug *plug,
|
|
ObjectID object_ID
|
|
)
|
|
{
|
|
Check(this);
|
|
#if 0
|
|
Check(&plugStreamManager);
|
|
plugStreamManager.globalPlugIndex.AddValue(plug, object_ID);
|
|
#else
|
|
PlugStreamManager::AddPlug(plug, object_ID);
|
|
#endif
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// FindPlug
|
|
//#############################################################################
|
|
//
|
|
Plug*
|
|
PlugStream::FindPlug(ObjectID object_ID)
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Search the local address index
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
Plug *plug;
|
|
|
|
Check(localPlugIndex);
|
|
if ((plug = localPlugIndex->Find(object_ID)) != NULL)
|
|
{
|
|
Check(plug);
|
|
return plug;
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Search the global address index
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
#if 0
|
|
Check(&plugStreamManager);
|
|
if ((plug = plugStreamManager.globalPlugIndex.Find(object_ID)) != NULL)
|
|
{
|
|
Check(plug);
|
|
return plug;
|
|
}
|
|
return NULL;
|
|
#else
|
|
if ((plug = PlugStreamManager::FindPlug(object_ID)) != NULL)
|
|
{
|
|
Check(plug);
|
|
return plug;
|
|
}
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// BuildFromNotationFile
|
|
//#############################################################################
|
|
//
|
|
void
|
|
PlugStream::BuildFromNotationFile(
|
|
NotationFile *notation_file,
|
|
ResourceFile *resource_file
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(notation_file);
|
|
Check(resource_file);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Keep local object ID index
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
LocalObjectIDIndex
|
|
local_index(NULL, True);
|
|
|
|
Check(&local_index);
|
|
localObjectIDIndex = &local_index;
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Parse notation file
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
ObjectStream::BuildFromNotationFile(notation_file, resource_file);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Forget local object ID index
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
{
|
|
VChainIteratorOf<ObjectIDPlug*, CString> iterator(&local_index);
|
|
Check(&iterator);
|
|
iterator.DeletePlugs();
|
|
}
|
|
localObjectIDIndex = NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// BuiltFromPage
|
|
//#############################################################################
|
|
//
|
|
void
|
|
PlugStream::BuiltFromPageImplementation(
|
|
Enumeration,
|
|
ObjectID object_ID,
|
|
const CString &object_name_string
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(&object_name_string);
|
|
AddLocalObjectID(object_ID, object_name_string);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// AddLocalObjectID
|
|
//#############################################################################
|
|
//
|
|
void
|
|
PlugStream::AddLocalObjectID(
|
|
ObjectID object_ID,
|
|
const CString &object_name_string
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(&object_name_string);
|
|
|
|
ObjectIDPlug *object_ID_plug =
|
|
new ObjectIDPlug(object_ID);
|
|
Register_Object(object_ID_plug);
|
|
|
|
Check(localObjectIDIndex);
|
|
#if DEBUG_LEVEL>0
|
|
if (localObjectIDIndex->Find(object_name_string) != NULL)
|
|
{
|
|
Dump(object_name_string);
|
|
}
|
|
#endif
|
|
localObjectIDIndex->AddValue(object_ID_plug, object_name_string);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// AddGlobalObjectID
|
|
//#############################################################################
|
|
//
|
|
void
|
|
PlugStream::AddGlobalObjectID(
|
|
ObjectID object_ID,
|
|
const CString &object_name_string
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(&object_name_string);
|
|
|
|
PlugStreamManager::AddPlugName(object_ID, object_name_string);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// FindObjectID
|
|
//#############################################################################
|
|
//
|
|
ObjectID
|
|
PlugStream::FindObjectID(const CString &object_name_string)
|
|
{
|
|
Check(this);
|
|
Check(&object_name_string);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Search the local object ID index
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
ObjectIDPlug *plug;
|
|
|
|
Check(localObjectIDIndex);
|
|
if ((plug = localObjectIDIndex->Find(object_name_string)) != NULL)
|
|
{
|
|
Check(plug);
|
|
return plug->GetItem();
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Search the global address index
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
#if 0
|
|
Check(&plugStreamManager);
|
|
plug = plugStreamManager.globalObjectIDIndex.Find(object_name_string);
|
|
if (plug != NULL)
|
|
{
|
|
Check(plug);
|
|
return plug->GetItem();
|
|
}
|
|
return NULL;
|
|
#else
|
|
return PlugStreamManager::FindPlugName(object_name_string);
|
|
#endif
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// PlugStream_FindEntryAndWriteObjectID
|
|
//#############################################################################
|
|
//
|
|
void
|
|
PlugStream_FindEntryAndWriteObjectID(
|
|
PlugStream *stream,
|
|
NameList *name_list,
|
|
const CString &entry_name
|
|
)
|
|
{
|
|
Check(stream);
|
|
Check(name_list);
|
|
Check(&entry_name);
|
|
|
|
void *entry_data;
|
|
CString object_name;
|
|
ObjectID object_ID;
|
|
|
|
entry_data = name_list->FindData(entry_name);
|
|
if (entry_data == NULL)
|
|
{
|
|
std::cout << "PlugStream_FindEntryAndWriteObjectID - entry_name == ";
|
|
std::cout << entry_name << "\n";
|
|
Fail("PlugStream_FindEntryAndWriteObjectID - entry_data == NULL");
|
|
}
|
|
Check_Pointer(entry_data);
|
|
object_name = (const char *)entry_data;
|
|
|
|
Check(stream);
|
|
object_ID = stream->FindObjectID(object_name);
|
|
if (object_ID == NullObjectID)
|
|
{
|
|
std::cout << "PlugStream_FindEntryAndWriteObjectID - object_name == ";
|
|
std::cout << object_name << "\n";
|
|
Fail("PlugStream_FindEntryAndWriteObjectID - object_ID == NullObjectID");
|
|
}
|
|
Verify(object_ID != NullObjectID);
|
|
MemoryStream_Write(stream, &object_ID);
|
|
}
|