diff --git a/Atlas.pdf b/Atlas.pdf new file mode 100644 index 0000000..905a6a9 Binary files /dev/null and b/Atlas.pdf differ diff --git a/Atlas.sln b/Atlas.sln new file mode 100644 index 0000000..255b5da --- /dev/null +++ b/Atlas.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Atlas", "Atlas.vcproj", "{EFF7695B-E1D6-4C95-847C-A37EC2A929B9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EFF7695B-E1D6-4C95-847C-A37EC2A929B9}.Debug|Win32.ActiveCfg = Debug|Win32 + {EFF7695B-E1D6-4C95-847C-A37EC2A929B9}.Debug|Win32.Build.0 = Debug|Win32 + {EFF7695B-E1D6-4C95-847C-A37EC2A929B9}.Release|Win32.ActiveCfg = Release|Win32 + {EFF7695B-E1D6-4C95-847C-A37EC2A929B9}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Atlas.sln.old b/Atlas.sln.old new file mode 100644 index 0000000..3998b62 --- /dev/null +++ b/Atlas.sln.old @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Atlas", "Atlas.vcproj", "{EFF7695B-E1D6-4C95-847C-A37EC2A929B9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EFF7695B-E1D6-4C95-847C-A37EC2A929B9}.Debug|Win32.ActiveCfg = Debug|Win32 + {EFF7695B-E1D6-4C95-847C-A37EC2A929B9}.Debug|Win32.Build.0 = Debug|Win32 + {EFF7695B-E1D6-4C95-847C-A37EC2A929B9}.Release|Win32.ActiveCfg = Release|Win32 + {EFF7695B-E1D6-4C95-847C-A37EC2A929B9}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Atlas.suo b/Atlas.suo new file mode 100644 index 0000000..c4869bd Binary files /dev/null and b/Atlas.suo differ diff --git a/Atlas.suo.old b/Atlas.suo.old new file mode 100644 index 0000000..37483c9 Binary files /dev/null and b/Atlas.suo.old differ diff --git a/Atlas.vcproj b/Atlas.vcproj new file mode 100644 index 0000000..fb7905e --- /dev/null +++ b/Atlas.vcproj @@ -0,0 +1,320 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Atlas.vcproj.8.00.old b/Atlas.vcproj.8.00.old new file mode 100644 index 0000000..33eb3b8 --- /dev/null +++ b/Atlas.vcproj.8.00.old @@ -0,0 +1,315 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Atlas.vcproj.HIKARI.Steve.user b/Atlas.vcproj.HIKARI.Steve.user new file mode 100644 index 0000000..010270d --- /dev/null +++ b/Atlas.vcproj.HIKARI.Steve.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/AtlasCore.cpp b/AtlasCore.cpp new file mode 100644 index 0000000..2500aca --- /dev/null +++ b/AtlasCore.cpp @@ -0,0 +1,1082 @@ +//----------------------------------------------------------------------------- +// AtlasCore - A class to insert Atlas-type scripts +// By Steve Monaco (stevemonaco@hotmail.com) +//----------------------------------------------------------------------------- + +#include "stdafx.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Table.h" +#include "AtlasCore.h" +#include "AtlasTypes.h" +#include "GenericVariable.h" +#include "AtlasFile.h" +#include "Pointer.h" +#include "AtlasLogger.h" +#include "AtlasStats.h" +#include "PointerHandler.h" +#include "AtlasExtension.h" + +using namespace std; + +// Constructor + +AtlasCore Atlas; +unsigned int CurrentLine = 1; +int bSwap = 0; +int StringAlign = 0; +int MaxEmbPtr = 0; + +AtlasCore::AtlasCore() : PtrHandler(&VarMap), Parser(&VarMap), Extensions(&VarMap) +{ + CurrentLine = 1; + HeaderSize = 0; + IsInJmp = false; +} + +// Destructor +AtlasCore::~AtlasCore() +{ +} + +bool AtlasCore::Insert(const char* RomFileName, const char* ScriptFileName) +{ + ifstream script; + script.open(ScriptFileName, ios::in); + if(!script.is_open()) + { + printf("Unable to open script file '%s'\n", ScriptFileName); + return false; + } + + if(!File.OpenFileT(RomFileName)) + { + printf("Unable to open target file '%s'\n", RomFileName); + return false; + } + + // Target and pointer files will initially be the same file + if(!File.OpenFileP(RomFileName)) + { + printf("Unable to open pointer file '%s'\n", RomFileName); + return false; + } + + // Parse file + bool ParseSuccess = false; + clock_t ParseStart = clock(); + ParseSuccess = Parser.ParseFile(script); + clock_t ParseTime = clock() - ParseStart; + + PrintSummary("Parsing", ParseTime); + + if(!ParseSuccess) + return false; + + EmbPtrs.SetListSize(MaxEmbPtr+1); + + // Insert file + clock_t InsertionStart = clock(); + + for(ListBlockIt Block = Parser.Blocks.begin(); Block != Parser.Blocks.end(); Block++) + { + File.FlushText(); + + // Execute list of commands + for(ListCmdIt com = Block->Commands.begin(); com != Block->Commands.end(); com++) + { + CurrentLine = com->Line; + if(!ExecuteCommand(*com)) + goto InsertionSummary; + } + + if(Block->StartLine != -1) + CurrentLine = Block->StartLine; + + // Insert text strings + for(ListStringIt text = Block->TextLines.begin(); text != Block->TextLines.end(); text++) + { + if(!text->empty()) + { + if(!IsInJmp) + { + Logger.ReportError(CurrentLine, "\"You must specify an address using JMP before inserting text\""); + goto InsertionSummary; + } + if(!File.InsertText(*text, CurrentLine)) + goto InsertionSummary; + } + CurrentLine++; + } + } + + File.FlushText(); + +InsertionSummary: + clock_t InsertionTime = clock() - InsertionStart; + + PrintSummary("Insertion", InsertionTime); + + Stats.End(CurrentLine); // Hack for the last line + PrintStatistics(); + if(MaxEmbPtr != 0) + PrintUnwrittenPointers(); + + return true; +} + +unsigned int AtlasCore::GetHeaderSize() +{ + return HeaderSize; +} + +void AtlasCore::SetDebugging(FILE* output) +{ + if(output == NULL) + Logger.SetLogStatus(false); + else + Logger.SetLogStatus(true); + Logger.SetLogSource(output); +} + +void AtlasCore::PrintStatistics() +{ + const char* Frame = "+------------------------------------------------------------------------------"; + + if(Stats.Stats.size() == 0); // Do nothing + else if(Stats.Stats.size() == 1) + { + PrintStatisticsBlock("Total", Stats.Stats.front()); + } + else // Print each block's content + { + unsigned int blocknum = 1; + char buf[127]; + for(ListStatsIt i = Stats.Stats.begin(); i != Stats.Stats.end(); i++) + { + _snprintf(buf, 127, "Block %d", blocknum); + PrintStatisticsBlock(buf, *i); + blocknum++; + } + + Stats.GenerateTotalStats(Total); + + // Print out the total statistics + printf("%s\n", Frame); + printf("| Total Statistics\n"); + printf("| Script Size %u\n", Total.ScriptSize); + printf("| Script Inserted %u\n", Total.ScriptSize - Total.ScriptOverflowed); + if(Total.ScriptOverflowed != 0) + printf("| Script Overflowed %u\n", Total.ScriptOverflowed); + if(Total.MaxBound != -1) + printf("| Space Remaining %u\n", Total.SpaceRemaining); + printf("|\n"); + + if(Total.HasCommands()) + { + printf("| Command Execution Listing\n"); + for(int j = 0; j < CommandCount; j++) + { + if(Total.ExecCount[j] != 0) + printf("| %s: %u\n", CommandStrings[j], Total.ExecCount[j]); + } + } + + if(Total.EmbPointerWrites > 0 || Total.AutoPointerWrites > 0 || + Total.FailedListWrites > 0 || Total.ExtPointerWrites > 0) + printf("| Pointer Listing\n"); + if(Total.PointerWrites != 0) + printf("| General Pointers Written: %u\n", Total.PointerWrites); + if(Total.EmbPointerWrites != 0) + printf("| Embedded Pointers Written: %u\n", Total.EmbPointerWrites); + if(Total.AutoPointerWrites != 0) + printf("| Autowrite Pointers Written: %u\n", Total.AutoPointerWrites); + if(Total.FailedListWrites != 0) + printf("| Failed PointerList Writes: %u\n", Total.FailedListWrites); + if(Total.ExtPointerWrites != 0) + printf("| Extension Pointer Writes: %u\n", Total.ExtPointerWrites); + printf("%s\n\n", Frame); + } +} + +void AtlasCore::PrintStatisticsBlock(const char* Title, InsertionStatistics& Stats) +{ + const char* Frame = "+------------------------------------------------------------------------------"; + + printf("%s\n", Frame); + printf("| %s\n| Start: Line %u File Position $%X", Title, Stats.LineStart, Stats.StartPos); + if(Stats.MaxBound != -1) + printf(" Bound $%X", Stats.MaxBound); + printf("\n"); + printf("| End: Line %u File Position $%X\n", Stats.LineEnd, Stats.StartPos + Stats.ScriptSize - Stats.ScriptOverflowed); + printf("%s\n", Frame); + printf("| Script size %u\n", Stats.ScriptSize); + printf("| Bytes Inserted %u", Stats.ScriptSize - Stats.ScriptOverflowed); + if(Stats.ScriptOverflowed != 0) + printf("\n| Script Overflowed %u", Stats.ScriptOverflowed); + if(Stats.MaxBound != -1) + printf("\n| Space Remaining %u", Stats.SpaceRemaining); + printf("\n|\n"); + + if(Stats.HasCommands()) + { + printf("| Command Execution Listing\n"); + for(int j = 0; j < CommandCount; j++) + { + if(Stats.ExecCount[j] != 0) + printf("| %s: %u\n", CommandStrings[j], Stats.ExecCount[j]); + } + printf("|\n"); + } + + printf("| Pointer Listing\n"); + printf("| General Pointers Written: %u\n", Stats.PointerWrites); + if(Stats.EmbPointerWrites != 0) + printf("| Embedded Pointers Written: %u\n", Stats.EmbPointerWrites); + if(Stats.AutoPointerWrites != 0) + printf("| Autowrite Pointers Written: %u\n", Stats.AutoPointerWrites); + if(Stats.FailedListWrites != 0) + printf("| Failed PointerList Writes: %u\n", Stats.FailedListWrites); + if(Stats.ExtPointerWrites != 0) + printf("| Extension Pointer Writes: %u\n", Stats.ExtPointerWrites); + printf("%s\n\n", Frame); +} + +void AtlasCore::PrintSummary(const char* Title, unsigned int TimeCompleted) +{ + unsigned int SumErrors = 0; + unsigned int SumWarnings = 0; + printf("%s summary: %u msecs\n", Title, TimeCompleted); + + // Print errors and warnings + for(ListErrorIt i = Logger.Errors.begin(); i != Logger.Errors.end(); i++) + { + if(i->Severity == FATALERROR) + { + printf("Error: "); + SumErrors++; + } + else if(i->Severity == WARNING) + { + printf("Warning: "); + SumWarnings++; + } + printf("%s on line %d\n", i->Error.c_str(), i->LineNumber); + } + Logger.Errors.clear(); + printf("%s - %u error(s), %u warning(s)\n\n", Title, SumErrors, SumWarnings); +} + +void AtlasCore::PrintUnwrittenPointers() +{ + const char* Frame = "+------------------------------------------------------------------------------"; + + printf("%s\n", Frame); + printf("Printing Initialized But Unwritten Embedded Pointers Summary\n"); + unsigned int TextPos, PointerPos, count = 0; + + for(int i = 0; i < EmbPtrs.GetListSize(); i++) + { + if(!EmbPtrs.GetPointerState(i, TextPos, PointerPos)) // Pointer is uninit'd or not fully written + { + if(TextPos == -1 && PointerPos == -1) // Uninitialized + continue; + printf("| EmbPtr $%X EMBWRITE $%08X EMBSET $%08X\n", i, TextPos, PointerPos); + count++; + } + } + printf("|\n| %d Pointer(s) Detected\n", count); + printf("%s\n\n", Frame); +} + +bool AtlasCore::ExecuteCommand(Command& Cmd) +{ + static unsigned int PtrValue; + static unsigned int PtrNum; + static unsigned int PtrPos; + static unsigned int Size; + static bool Success; + static unsigned char PtrByte; + static unsigned int StartPos; + static PointerList* List = NULL; + static PointerTable* Tbl = NULL; + static AtlasContext* Context = NULL; + static AtlasExtension* Ext = NULL; + string FuncName; + + if(IsInJmp && Cmd.Function != CMD_JMP1 && Cmd.Function != CMD_JMP2) + Stats.AddCmd(Cmd.Function); + else + Total.AddCmd(Cmd.Function); + + switch(Cmd.Function) + { + case CMD_JMP1: + File.MoveT(StringToUInt(Cmd.Parameters[0].Value), -1); + Stats.NewStatsBlock(File.GetPosT(), -1, Cmd.Line); + Logger.Log("%6u JMP ROM Position is now $%X\n", Cmd.Line, StringToUInt(Cmd.Parameters[0].Value)); + IsInJmp = true; + return true; + case CMD_JMP2: + File.MoveT(StringToUInt(Cmd.Parameters[0].Value), StringToUInt(Cmd.Parameters[1].Value)); + Stats.NewStatsBlock(File.GetPosT(), StringToUInt(Cmd.Parameters[1].Value), Cmd.Line); + Logger.Log("%6u JMP ROM Position is now $%X with max bound of $%X\n", + Cmd.Line, StringToUInt(Cmd.Parameters[0].Value), StringToUInt(Cmd.Parameters[1].Value)); + IsInJmp = true; + return true; + case CMD_SMA: + Success = DefaultPointer.SetAddressType(Cmd.Parameters[0].Value); + if(Success) + Logger.Log("%6u SMA Addressing type is now '%s'\n", Cmd.Line, Cmd.Parameters[0].Value.c_str()); + return Success; + case CMD_HDR: + unsigned int Size; + Size = StringToUInt(Cmd.Parameters[0].Value); + EmbPtrs.SetHeaderSize(Size); + DefaultPointer.SetHeaderSize(Size); + HeaderSize = Size; + Logger.Log("%6u HDR Header size is now $%X\n", Cmd.Line, StringToUInt(Cmd.Parameters[0].Value)); + return true; + case CMD_STRTYPE: + Success = File.SetStringType(Cmd.Parameters[0].Value); + if(Success) + Logger.Log("%6u STRTYPE String type is now '%s'\n", Cmd.Line, Cmd.Parameters[0].Value.c_str()); + return Success; + case CMD_ADDTBL: + Success = AddTable(Cmd); + if(Success) + Logger.Log("%6u ADDTBL Added table '%s' as '%s'\n", Cmd.Line, Cmd.Parameters[0].Value.c_str(), Cmd.Parameters[1].Value.c_str()); + return Success; + case CMD_ACTIVETBL: + Success = ActivateTable(Cmd.Parameters[0].Value); + if(Success) + Logger.Log("%6u ACTIVETBL Active table is now '%s'\n", Cmd.Line, Cmd.Parameters[0].Value.c_str()); + return Success; + case CMD_VAR: // Already handled by AtlasParser to validate types, should never get here + return true; + case CMD_WUB: + PtrValue = DefaultPointer.GetUpperByte(File.GetPosT()); + File.WriteP(&PtrValue, 1, 1, StringToUInt(Cmd.Parameters[0].Value)); + Logger.Log("%6u WUB ScriptPos $%X PointerPos $%X PointerValue $%02X\n", Cmd.Line, + File.GetPosT(), StringToUInt(Cmd.Parameters[0].Value), PtrValue); + return true; + case CMD_WBB: + PtrValue = DefaultPointer.GetBankByte(File.GetPosT()); + File.WriteP(&PtrValue, 1, 1, StringToUInt(Cmd.Parameters[0].Value)); + Logger.Log("%6u WBB ScriptPos $%X PointerPos $%X PointerValue $%02X\n", Cmd.Line, + File.GetPosT(), StringToUInt(Cmd.Parameters[0].Value), PtrValue); + return true; + case CMD_WHB: + PtrValue = DefaultPointer.GetHighByte(File.GetPosT()); + File.WriteP(&PtrValue, 1, 1, StringToUInt(Cmd.Parameters[0].Value)); + Logger.Log("%6u WHB ScriptPos $%X PointerPos $%X PointerValue $%02X\n", Cmd.Line, + File.GetPosT(), StringToUInt(Cmd.Parameters[0].Value), PtrValue); + return true; + case CMD_WLB: + PtrValue = DefaultPointer.GetLowByte(File.GetPosT()); + File.WriteP(&PtrValue, 1, 1, StringToUInt(Cmd.Parameters[0].Value)); + Logger.Log("%6u WLB ScriptPos $%X PointerPos $%X PointerValue $%02X\n", Cmd.Line, + File.GetPosT(), StringToUInt(Cmd.Parameters[0].Value), PtrValue); + return true; + case CMD_W16: + PtrValue = DefaultPointer.Get16BitPointer(File.GetPosT()); + if(bSwap) + PtrValue = EndianSwap(PtrValue, 2); + File.WriteP(&PtrValue, 2, 1, StringToUInt(Cmd.Parameters[0].Value)); + Logger.Log("%6u W16 ScriptPos $%X PointerPos $%X PointerValue $%04X\n", Cmd.Line, + File.GetPosT(), StringToUInt(Cmd.Parameters[0].Value), PtrValue); + return true; + case CMD_W24: + PtrValue = DefaultPointer.Get24BitPointer(File.GetPosT()); + if(bSwap) + PtrValue = EndianSwap(PtrValue, 3); + File.WriteP(&PtrValue, 3, 1, StringToUInt(Cmd.Parameters[0].Value)); + Logger.Log("%6u W24 ScriptPos $%X PointerPos $%X PointerValue $%06X\n", Cmd.Line, + File.GetPosT(), StringToUInt(Cmd.Parameters[0].Value), PtrValue); + return true; + case CMD_W32: + PtrValue = DefaultPointer.Get32BitPointer(File.GetPosT()); + if(bSwap) + PtrValue = EndianSwap(PtrValue, 4); + File.WriteP(&PtrValue, 4, 1, StringToUInt(Cmd.Parameters[0].Value)); + Logger.Log("%6u W32 ScriptPos $%X PointerPos $%X PointerValue $%08\n", Cmd.Line, + File.GetPosT(), StringToUInt(Cmd.Parameters[0].Value), PtrValue); + return true; + case CMD_EMBSET: + PtrNum = StringToUInt(Cmd.Parameters[0].Value); + Success = EmbPtrs.SetPointerPosition(PtrNum, File.GetPosT()); + Size = EmbPtrs.GetSize(PtrNum); + if(Size == -1) + return false; + Logger.Log("%6u EMBSET Pointer Position %u set to $%X\n", Cmd.Line, PtrNum, File.GetPosT()); + if(Success) // Write out embedded pointer + { + PtrValue = EmbPtrs.GetPointerValue(PtrNum); + if(File.GetMaxWritableBytes() > Size / 8) + { + if(bSwap) + PtrValue = EndianSwap(PtrValue, Size/8); + int tpos = File.GetPosT(); + File.WriteT(&PtrValue, Size / 8, 1); // Emb pointers are within script files + Logger.Log("%6u EMBSET Triggered Write: ScriptPos $%X PointerPos $%X PointerValue $%X Size %dd", Cmd.Line, + EmbPtrs.GetTextPosition(PtrNum), tpos, PtrValue, Size); + Stats.IncEmbPointerWrites(); + } + else + Logger.Log("%6u EMBSET Failed to write due to insufficient space\n"); + } + else // Reserve space so the embedded pointer and script don't compete + { // for the same part of the file + if(File.GetMaxWritableBytes() > Size / 8) + { + unsigned int Zero = 0; + File.WriteT(&Zero, Size/8, 1); + } + else + Logger.Log("%6u EMBSET Failed to write due to insufficient space\n"); + } + return true; + case CMD_EMBTYPE: + Success = EmbPtrs.SetType(Cmd.Parameters[0].Value, StringToInt64(Cmd.Parameters[2].Value), StringToUInt(Cmd.Parameters[1].Value)); + if(!Success) + Logger.ReportError(Cmd.Line, "Bad size %d for EMBTYPE", StringToUInt(Cmd.Parameters[0].Value)); + else + Logger.Log("%6u EMBTYPE Embedded Pointer size %u Offsetting %I64d\n", Cmd.Line, StringToUInt(Cmd.Parameters[1].Value), StringToInt64(Cmd.Parameters[0].Value)); + return Success; + case CMD_EMBWRITE: + PtrNum = StringToUInt(Cmd.Parameters[0].Value); + Success = EmbPtrs.SetTextPosition(PtrNum, File.GetPosT()); + Size = EmbPtrs.GetSize(PtrNum); + if(Size == -1) + return false; + Logger.Log("%6u EMBWRITE Pointed Position %u set to $%X\n", Cmd.Line, PtrNum, File.GetPosT()); + if(Success) // Write out embedded pointer + { + PtrPos = EmbPtrs.GetPointerPosition(PtrNum); + PtrValue = EmbPtrs.GetPointerValue(PtrNum); + if(File.GetMaxWritableBytes() > Size / 8) + { + if(bSwap) + PtrValue = EndianSwap(PtrValue, Size/8); + File.WriteT(&PtrValue, Size/8, 1, PtrPos); + Logger.Log("%6u EMBWRITE Triggered Write: ScriptPos $%X PointerPos $%X PointerValue $%X Size %dd\n", Cmd.Line, + File.GetPosT(), PtrPos, PtrValue, Size); + Stats.IncEmbPointerWrites(); + } + else + Logger.Log("%6u EMBWRITE Failed to write due to insufficient space\n"); + } + return true; + case CMD_BREAK: + return false; + case CMD_PTRTBL: + Success = PtrHandler.CreatePointerTable(Cmd.Parameters[0].Value, StringToUInt(Cmd.Parameters[1].Value), StringToUInt(Cmd.Parameters[2].Value), Cmd.Parameters[3].Value); + if(Success) + Logger.Log("%6u PTRTBL Pointer Table '%s' created StartPos $%X Increment %dd CustomPointer '%s'\n", Cmd.Line, Cmd.Parameters[0].Value.c_str(), + StringToUInt(Cmd.Parameters[1].Value), StringToUInt(Cmd.Parameters[2].Value), Cmd.Parameters[3].Value.c_str()); + return Success; + case CMD_WRITETBL: + PtrValue = PtrHandler.GetTableAddress(Cmd.Parameters[0].Value, File.GetPosT(), Size, PtrPos); + if(PtrValue == -1) + return false; + if(bSwap) + PtrValue = EndianSwap(PtrValue, Size/8); + File.WriteP(&PtrValue, Size/8, 1, PtrPos); + Logger.Log("%6u WRITE PointerTable '%s' ScriptPos $%X PointerPos $%X PointerValue $%08X\n", Cmd.Line, + Cmd.Parameters[0].Value.c_str(), File.GetPosT(), PtrPos, PtrValue); + return true; + case CMD_PTRLIST: + Success = PtrHandler.CreatePointerList(Cmd.Parameters[0].Value, Cmd.Parameters[1].Value.c_str(), Cmd.Parameters[2].Value); + if(Success) + Logger.Log("%6u PTRTBL Pointer List '%s' created from file '%s' CustomPointer '%s'\n", Cmd.Line, Cmd.Parameters[0].Value.c_str(), + Cmd.Parameters[1].Value.c_str(), Cmd.Parameters[2].Value.c_str()); + return Success; + case CMD_WRITELIST: + PtrValue = PtrHandler.GetListAddress(Cmd.Parameters[0].Value, File.GetPosT(), Size, PtrPos); + if(PtrValue == -1) + return false; + if(bSwap) + PtrValue = EndianSwap(PtrValue, Size/8); + File.WriteP(&PtrValue, Size/8, 1, PtrPos); + Logger.Log("%6u WRITE PointerList '%s' ScriptPos $%X PointerPos $%X PointerValue $%08X\n", Cmd.Line, + Cmd.Parameters[0].Value.c_str(), File.GetPosT(), PtrPos, PtrValue); + return true; + case CMD_AUTOWRITETBL: + Tbl = (PointerTable*)VarMap.GetVar(Cmd.Parameters[0].Value)->GetData(); + if(Tbl == NULL) + { + Logger.ReportError(CurrentLine, "Identifier '%s' has not been initialized with PTRTBL", Cmd.Parameters[0].Value.c_str()); + return false; + } + Success = File.AutoWrite(Tbl, Cmd.Parameters[1].Value); + if(!Success) + Logger.ReportError(CurrentLine, "'%s' has not been defined as an end token in the active table", Cmd.Parameters[1].Value.c_str()); + else + Logger.Log("%6u AUTOWRITE EndTag '%s' PointerTable '%s'\n", Cmd.Line, Cmd.Parameters[0].Value.c_str(), + Cmd.Parameters[1].Value.c_str()); + return Success; + case CMD_AUTOWRITELIST: + List = (PointerList*)VarMap.GetVar(Cmd.Parameters[0].Value)->GetData(); + if(List == NULL) + { + Logger.ReportError(CurrentLine, "Identifier '%s' has not been initialized with PTRLIST", Cmd.Parameters[0].Value.c_str()); + return false; + } + Success = File.AutoWrite(List, Cmd.Parameters[1].Value); + if(!Success) + Logger.ReportError(CurrentLine, "'%s' has not been defined as an end token in the active table", Cmd.Parameters[1].Value.c_str()); + else + Logger.Log("%6u AUTOWRITE EndTag '%s' PointerList '%s'\n", Cmd.Line, Cmd.Parameters[0].Value.c_str(), + Cmd.Parameters[1].Value.c_str()); + return Success; + case CMD_CREATEPTR: + Success = PtrHandler.CreatePointer(Cmd.Parameters[0].Value, Cmd.Parameters[1].Value, + StringToInt64(Cmd.Parameters[2].Value), StringToUInt(Cmd.Parameters[3].Value), HeaderSize); + if(Success) + Logger.Log("%6u CREATEPTR CustomPointer '%s' Addressing '%s' Offsetting %I64d Size %dd HeaderSize $%X\n", Cmd.Line, + Cmd.Parameters[0].Value.c_str(), Cmd.Parameters[1].Value.c_str(), StringToInt64(Cmd.Parameters[2].Value), StringToUInt(Cmd.Parameters[3].Value), HeaderSize); + return Success; + case CMD_WRITEPTR: + PtrValue = PtrHandler.GetPtrAddress(Cmd.Parameters[0].Value, File.GetPosT(), Size); + PtrPos = StringToUInt(Cmd.Parameters[1].Value); + if(PtrValue == -1) + return false; + if(bSwap) + PtrValue = EndianSwap(PtrValue, Size/8); + File.WriteP(&PtrValue, Size/8, 1, PtrPos); + Logger.Log("%6u WRITE CustomPointer '%s' ScriptPos $%X PointerPos $%X PointerValue $%08X\n", Cmd.Line, + Cmd.Parameters[0].Value.c_str(), File.GetPosT(), PtrPos, PtrValue); + return true; + case CMD_LOADEXT: + Success = Extensions.LoadExtension(Cmd.Parameters[0].Value, Cmd.Parameters[1].Value); + if(Success) + Logger.Log("%6u LOADEXT Loaded extension %s successfully\n", Cmd.Line, Cmd.Parameters[1].Value.c_str()); + return Success; + case CMD_EXECEXT: + return ExecuteExtension(Cmd.Parameters[0].Value, Cmd.Parameters[1].Value, &Context); + case CMD_DISABLETABLE: + Tbl = (PointerTable*)VarMap.GetVar(Cmd.Parameters[0].Value)->GetData(); + if(Tbl == NULL) + { + Logger.ReportError(CurrentLine, "Identifier '%s' has not been initialized with PTRTBL", Cmd.Parameters[0].Value.c_str()); + return false; + } + Success = File.DisableWrite(Cmd.Parameters[1].Value, true); + if(!Success) + Logger.ReportError(CurrentLine, "'%s' has not been defined as an autowrite end token", Cmd.Parameters[1].Value.c_str()); + else + Logger.Log("%6u DISABLE EndTag '%s' PointerTable '%s'\n", Cmd.Line, Cmd.Parameters[0].Value.c_str(), + Cmd.Parameters[1].Value.c_str()); + return Success; + case CMD_DISABLELIST: + List = (PointerList*)VarMap.GetVar(Cmd.Parameters[0].Value)->GetData(); + if(List == NULL) + { + Logger.ReportError(CurrentLine, "Identifier '%s' has not been initialized with PTRLIST", Cmd.Parameters[0].Value.c_str()); + return false; + } + Success = File.DisableWrite(Cmd.Parameters[1].Value, false); + if(!Success) + Logger.ReportError(CurrentLine, "'%s' has not been defined as an autowrite end token", Cmd.Parameters[1].Value.c_str()); + else + Logger.Log("%6u DISABLE EndTag '%s' PointerList '%s'\n", Cmd.Line, Cmd.Parameters[1].Value.c_str(), + Cmd.Parameters[0].Value.c_str()); + return Success; + case CMD_PASCALLEN: + Success = File.SetPascalLength(StringToUInt(Cmd.Parameters[0].Value)); + if(Success) + Logger.Log("%6u PASCALLEN Length for pascal strings set to %u\n", Cmd.Line, StringToUInt(Cmd.Parameters[0].Value)); + else + Logger.ReportError(CurrentLine, "Invalid length %u for PASCALLEN", StringToUInt(Cmd.Parameters[0].Value)); + return Success; + case CMD_AUTOEXEC: + Ext = (AtlasExtension*)VarMap.GetVar(Cmd.Parameters[0].Value)->GetData(); + if(Ext == NULL) + { + Logger.ReportError(CurrentLine, "Identifier '%s' has not been initialized with LOADEXT", Cmd.Parameters[0].Value.c_str()); + return false; + } + Success = File.AutoWrite(Ext, Cmd.Parameters[1].Value, Cmd.Parameters[2].Value); + if(Success) + Logger.Log("%6u AUTOEXEC EndTag '%s' Extension '%s'\n", Cmd.Line, Cmd.Parameters[0].Value.c_str(), + Cmd.Parameters[1].Value.c_str()); + return Success; + case CMD_DISABLEEXEC: + Success = File.DisableAutoExtension(Cmd.Parameters[0].Value, Cmd.Parameters[1].Value); + if(Success) + Logger.Log("%6u DISABLE EndTag '%s' Extension Function '%s'\n", Cmd.Line, Cmd.Parameters[1].Value.c_str(), + Cmd.Parameters[0].Value.c_str()); + return Success; + case CMD_FIXEDLENGTH: + Success = File.SetFixedLength(StringToUInt(Cmd.Parameters[0].Value), StringToUInt(Cmd.Parameters[1].Value)); + if(Success) + Logger.Log("%6u FIXEDLENGTH Length %d PaddingValue %d\n", Cmd.Line, StringToUInt(Cmd.Parameters[0].Value), + StringToUInt(Cmd.Parameters[0].Value)); + else + Logger.ReportError(CurrentLine, "FixedLength used a padding value not in the range of 0-255"); + return Success; + case CMD_WUBCUST: + PtrValue = PtrHandler.GetPtrAddress(Cmd.Parameters[0].Value, File.GetPosT(), Size); + PtrPos = StringToUInt(Cmd.Parameters[1].Value); + if(PtrValue == -1) + return false; + PtrByte = (PtrValue & 0xFF000000) >> 24; + File.WriteP(&PtrByte, 1, 1, PtrPos); + Logger.Log("%6u WUB CustomPointer '%s' ScriptPos $%X PointerPos $%X PointerValue $%02X\n", Cmd.Line, + Cmd.Parameters[0].Value.c_str(), File.GetPosT(), PtrPos, PtrByte); + return true; + case CMD_WBBCUST: + PtrValue = PtrHandler.GetPtrAddress(Cmd.Parameters[0].Value, File.GetPosT(), Size); + PtrPos = StringToUInt(Cmd.Parameters[1].Value); + if(PtrValue == -1) + return false; + PtrByte = (PtrValue & 0xFF0000) >> 16; + File.WriteP(&PtrByte, 1, 1, PtrPos); + Logger.Log("%6u WBB CustomPointer '%s' ScriptPos $%X PointerPos $%X PointerValue $%02X\n", Cmd.Line, + Cmd.Parameters[0].Value.c_str(), File.GetPosT(), PtrPos, PtrByte); + return true; + case CMD_WHBCUST: + PtrValue = PtrHandler.GetPtrAddress(Cmd.Parameters[0].Value, File.GetPosT(), Size); + PtrPos = StringToUInt(Cmd.Parameters[1].Value); + if(PtrValue == -1) + return false; + PtrByte = (PtrValue & 0xFF00) >> 8; + File.WriteP(&PtrByte, 1, 1, PtrPos); + Logger.Log("%6u WHB CustomPointer '%s' ScriptPos $%X PointerPos $%X PointerValue $%02X\n", Cmd.Line, + Cmd.Parameters[0].Value.c_str(), File.GetPosT(), PtrPos, PtrByte); + return true; + case CMD_WLBCUST: + PtrValue = PtrHandler.GetPtrAddress(Cmd.Parameters[0].Value, File.GetPosT(), Size); + PtrPos = StringToUInt(Cmd.Parameters[1].Value); + if(PtrValue == -1) + return false; + PtrByte = PtrValue & 0xFF; + File.WriteP(&PtrByte, 1, 1, PtrPos); + Logger.Log("%6u WLB CustomPointer '%s' ScriptPos $%X PointerPos $%X PointerValue $%02X\n", Cmd.Line, + Cmd.Parameters[0].Value.c_str(), File.GetPosT(), PtrPos, PtrByte); + return true; + case CMD_ENDIANSWAP: + Success = SetEndianSwap(Cmd.Parameters[0].Value); + if(Success) + Logger.Log("%6u ENDIANSWAP '%s'\n", Cmd.Line, Cmd.Parameters[0].Value.c_str()); + return Success; + case CMD_STRINGALIGN: + StringAlign = StringToUInt(Cmd.Parameters[0].Value); + Logger.Log("%6u STRINGALIGN '%s'\n", Cmd.Line, Cmd.Parameters[0].Value.c_str()); + return true; + case CMD_EMBPTRTABLE: + Success = PtrHandler.CreateEmbPointerTable(Cmd.Parameters[0].Value, File.GetPosT(), StringToUInt(Cmd.Parameters[1].Value), Cmd.Parameters[2].Value); + StartPos = File.GetPosT(); + Size = PtrHandler.GetPtrSize(Cmd.Parameters[2].Value); + if(Success) + { + int TableSize = (Size / 8) * StringToUInt(Cmd.Parameters[1].Value); + if(File.GetMaxWritableBytes() == -1 || (int)File.GetMaxWritableBytes() > TableSize) + { + // Reserve space inside the script for the embedded pointer table + unsigned char Zero = 0; + for(int i = 0; i < TableSize; i++) + File.WriteT(&Zero, 1, 1); + + Logger.Log("%6u EMBPTRTBL Pointer Table '%s' created StartPos $%X PtrCount %dd CustomPointer '%s'\n", Cmd.Line, Cmd.Parameters[0].Value.c_str(), + StartPos, StringToUInt(Cmd.Parameters[1].Value), Cmd.Parameters[2].Value.c_str()); + } + else + Logger.Log("%6u EMBPTRTABLE Failed to allocate due to insufficient space within script\n", Cmd.Line); + } + return Success; + case CMD_WHW: + PtrValue = DefaultPointer.GetHighWord(File.GetPosT()); + if(bSwap) + PtrValue = EndianSwap(PtrValue, 2); + File.WriteP(&PtrValue, 2, 1, StringToUInt(Cmd.Parameters[0].Value)); + Logger.Log("%6u WHW ScriptPos $%X PointerPos $%X PointerValue $%04X\n", Cmd.Line, + File.GetPosT(), StringToUInt(Cmd.Parameters[0].Value), PtrValue); + return true; + case CMD_WHWCUST: + PtrValue = PtrHandler.GetPtrAddress(Cmd.Parameters[0].Value, File.GetPosT(), Size); + PtrPos = StringToUInt(Cmd.Parameters[1].Value); + if(PtrValue == -1) + return false; + PtrValue = (PtrValue & 0xFFFF0000) >> 16; + if(bSwap) + PtrValue = EndianSwap(PtrValue, 2); + File.WriteP(&PtrByte, 2, 1, PtrPos); + Logger.Log("%6u WHW CustomPointer '%s' ScriptPos $%X PointerPos $%X PointerValue $%04X\n", Cmd.Line, + Cmd.Parameters[0].Value.c_str(), File.GetPosT(), PtrPos, PtrValue); + return true; + case CMD_SETTARGETFILE: + File.CloseFileT(); + Success = File.OpenFileT(Cmd.Parameters[0].Value.c_str()); + IsInJmp = false; + if(!Success) + Logger.ReportError(CurrentLine, "SETTARGETFILE Could not open file '%s'", Cmd.Parameters[0].Value.c_str()); + else + Logger.Log("%6u SETTARGETFILE '%s'", Cmd.Line, Cmd.Parameters[0].Value.c_str()); + return Success; + case CMD_SETPTRFILE: + File.CloseFileP(); + Success = File.OpenFileP(Cmd.Parameters[0].Value.c_str()); + if(!Success) + Logger.ReportError(CurrentLine, "SETPTRFILE Could not open file '%s'", Cmd.Parameters[0].Value.c_str()); + else + Logger.Log("%6u SETPTRFILE '%s'", Cmd.Line, Cmd.Parameters[0].Value.c_str()); + return Success; + case CMD_WRITEEMBTBL1: + PtrValue = PtrHandler.GetEmbTableAddress(Cmd.Parameters[0].Value, File.GetPosT(), Size, PtrPos); + if(PtrValue == -1) + { + Logger.ReportError(CurrentLine, "WRITE EMBPTRTBL '%s' could not write due to insufficient space'", Cmd.Parameters[0].Value.c_str()); + return false; + } + if(bSwap) + PtrValue = EndianSwap(PtrValue, Size/8); + File.WriteT(&PtrValue, Size/8, 1, PtrPos); + Logger.Log("%6u WRITE PointerTable '%s' ScriptPos $%X PointerPos $%X PointerValue $%08X\n", Cmd.Line, + Cmd.Parameters[0].Value.c_str(), File.GetPosT(), PtrPos, PtrValue); + return true; + case CMD_WRITEEMBTBL2: + PtrValue = PtrHandler.GetEmbTableAddress(Cmd.Parameters[0].Value, File.GetPosT(), StringToUInt(Cmd.Parameters[1].Value), Size, PtrPos); + if(PtrValue == -1) + { + Logger.ReportError(CurrentLine, "WRITE EMBPTRTBL '%s' could not write PtrNum '%d' due to out of table range'", Cmd.Parameters[0].Value.c_str(), StringToUInt(Cmd.Parameters[1].Value)); + return false; + } + if(bSwap) + PtrValue = EndianSwap(PtrValue, Size/8); + File.WriteT(&PtrValue, Size/8, 1, PtrPos); + Logger.Log("%6u WRITE PointerTable '%s' ScriptPos $%X PointerPos $%X PointerValue $%08X\n", Cmd.Line, + Cmd.Parameters[0].Value.c_str(), File.GetPosT(), PtrPos, PtrValue); + return true; + case CMD_WRITETBL2: + PtrValue = PtrHandler.GetTableAddress(Cmd.Parameters[0].Value, File.GetPosT(), StringToUInt(Cmd.Parameters[1].Value), Size, PtrPos); + if(PtrValue == -1) + return false; + if(bSwap) + PtrValue = EndianSwap(PtrValue, Size/8); + File.WriteP(&PtrValue, Size/8, 1, PtrPos); + Logger.Log("%6u WRITE PointerTable '%s' ScriptPos $%X PointerPos $%X PointerValue $%08X\n", Cmd.Line, + Cmd.Parameters[0].Value.c_str(), File.GetPosT(), PtrPos, PtrValue); + return true; + default: + Logger.BugReport(__LINE__, __FILE__, "Bad Cmd #%u", Cmd.Function); + return false; + } +} + +bool AtlasCore::ActivateTable(std::string& TableName) +{ + Table* Tbl = (Table*)(VarMap.GetVar(TableName))->GetData(); + if(Tbl == NULL) + { + ostringstream ErrorStr; + ErrorStr << "Uninitialized variable " << TableName << " used"; + Logger.ReportError(CurrentLine, "Uninitialized variable '%s' used", TableName); + return false; + } + else + { + File.SetTable(Tbl); + return true; + } +} + +bool AtlasCore::AddTable(Command& Cmd) +{ + Table* Tbl; + GenericVariable* Var; + Tbl = (Table*)(VarMap.GetVar(Cmd.Parameters[1].Value))->GetData(); + if(!LoadTable(Cmd.Parameters[0].Value, &Tbl)) + return false; + + Var = new GenericVariable(Tbl, P_TABLE); + VarMap.SetVar(Cmd.Parameters[1].Value, Var); + return true; +} + +bool AtlasCore::LoadTable(std::string& FileName, Table** Tbl) +{ + if(*Tbl != NULL) // Initialized already, overwrite + { + delete Tbl; + Tbl = NULL; + } + *Tbl = new Table; + int Result = (*Tbl)->OpenTable(FileName.c_str()); + + ostringstream ErrorStr; + switch(Result) + { + case TBL_OK: + break; + case TBL_PARSE_ERROR: + Logger.ReportError(CurrentLine, "The table file '%s' is incorrectly formatted", FileName.c_str()); + return false; + case TBL_OPEN_ERROR: + Logger.ReportError(CurrentLine, "The table file '%s' could not be opened", FileName.c_str()); + return false; + } + + return true; +} + + +void AtlasCore::CreateContext(AtlasContext** Context) +{ + if(*Context == NULL) + *Context = new AtlasContext; + (*Context)->CurrentLine = CurrentLine; + (*Context)->ScriptPos = File.GetPosT(); + (*Context)->ScriptRemaining = File.GetMaxWritableBytes(); + (*Context)->Target = File.GetFileT(); + File.GetScriptBuf((*Context)->StringTable); + (*Context)->PointerPosition = 0; + (*Context)->PointerSize = 0; + (*Context)->PointerValue = 0; +} + + +bool AtlasCore::ExecuteExtension(std::string& ExtId, std::string& FunctionName, + AtlasContext** Context) +{ + bool Success = false; + CreateContext(Context); + unsigned int DllRet = Extensions.ExecuteExtension(ExtId, FunctionName, Context); + if(DllRet == -1) + { + DllRet = NO_ACTION; + Success = false; + } + if(DllRet > MAX_RETURN_VAL) + { + Logger.ReportWarning(CurrentLine, "Extension returned invalid value %u", DllRet); + Success = false;; + } + if(DllRet & REPLACE_TEXT) + { + File.SetScriptBuf((*Context)->StringTable); + Logger.Log("%6u EXECEXT REPLACE_TEXT\n", CurrentLine); + Success = true; + } + if(DllRet & WRITE_POINTER) + { + unsigned int Size = (*Context)->PointerSize; + if(Size == 8 || Size == 16 || Size == 24 || Size == 32) + { + Size /= 8; + File.WriteP(&(*Context)->PointerValue, (*Context)->PointerSize, 1, (*Context)->PointerPosition); + Logger.Log("%6u EXECEXT WRITE_POINTER ScriptPos $%X PointerPos $%X PointerValue $%06X\n", CurrentLine, + File.GetPosT(), (*Context)->PointerPosition, (*Context)->PointerValue); + Success = true; + Stats.IncExtPointerWrites(); + } + else + { + Logger.ReportError(CurrentLine, "EXTEXEC Extension function '%s' returning WRITE_POINTER has an unsupported PointerSize field", FunctionName); + Success = false; + } + } + + delete (*Context); + *Context = NULL; + Logger.Log("%6u EXTEXEC Executed function '%s' from '%s' successfully\n", CurrentLine, FunctionName.c_str(), ExtId.c_str()); + return true; +} + +bool AtlasCore::ExecuteExtensionFunction(ExtensionFunction Func, AtlasContext** Context) +{ + unsigned int DllRet = Func(Context); + bool Success = false; + if(DllRet > MAX_RETURN_VAL) + { + Logger.ReportWarning(CurrentLine, "Extension returned invalid value %u", DllRet); + Success = false; + } + + if(DllRet & REPLACE_TEXT) + { + File.SetScriptBuf((*Context)->StringTable); + Logger.Log("%6u EXECEXT REPLACE_TEXT\n", CurrentLine); + Success = true; + } + if(DllRet & WRITE_POINTER) + { + unsigned int Size = (*Context)->PointerSize; + if(Size == 8 || Size == 16 || Size == 24 || Size == 32) + { + Size /= 8; + File.WriteP(&(*Context)->PointerValue, (*Context)->PointerSize, 1, (*Context)->PointerPosition); + Logger.Log("%6u EXTEXEC WRITE_POINTER ScriptPos $%X PointerPos $%X PointerValue $%06X\n", CurrentLine, + File.GetPosT(), (*Context)->PointerPosition, (*Context)->PointerValue); + Success = true; + Stats.IncExtPointerWrites(); + } + else + { + Logger.ReportError(CurrentLine, "EXTEXEC Extension function returning WRITE_POINTER has an unsupported PointerSize field"); + Success = false; + } + } + + delete (*Context); + *Context = NULL; + return true; +} + +bool AtlasCore::SetEndianSwap(string& Swap) +{ + if(Swap == "TRUE") + bSwap = 1; + else if(Swap == "FALSE") + bSwap = 0; + else + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// StringToUInt() - Converts a $ABCD string from hexadecimal radix else decimal +// Status - Working +//----------------------------------------------------------------------------- + +unsigned int StringToUInt(std::string& NumberString) +{ + unsigned int offset = 0; + + if(NumberString[0] == '$') + { + offset = strtoul(NumberString.substr(1, NumberString.length()).c_str(), NULL, 16); + } + else + offset = strtoul(NumberString.c_str(), NULL, 10); + + return offset; +} + +//----------------------------------------------------------------------------- +// StringToInt64() - Converts a string to int64 +// Status - Works+Fixed +//----------------------------------------------------------------------------- + +__int64 StringToInt64(string& NumberString) +{ + __int64 Num = 0; + bool bNeg = false; + size_t Pos = 0; + unsigned __int64 Mult; + + if(NumberString[Pos] == '$') // hex + { + Pos++; + if(NumberString[Pos] == '-') + { + bNeg = true; + Pos++; + } + size_t i = NumberString.length() - 1; + Num += GetHexDigit(NumberString[i]); + i--; + Mult = 16; + for(i; i >= Pos; i--, Mult*=16) + Num += Mult * GetHexDigit(NumberString[i]); + } + else // dec + { + if(NumberString[Pos] == '-') + { + bNeg = true; + Pos++; + } + size_t i = NumberString.length() - 1; + Num += GetHexDigit(NumberString[i]); + if(i != 0) + { + i--; + Mult = 10; + for(i; i > Pos; i--, Mult*=10) + Num += Mult * (NumberString[i] - '0'); + Num += Mult * (NumberString[i] - '0'); // prevent underflow of i + } + } + + if(bNeg) + Num = -Num; + return Num; +} + +unsigned int GetHexDigit(char digit) +{ + switch(digit) + { + case '0': + return 0; + case '1': + return 1; + case '2': + return 2; + case '3': + return 3; + case '4': + return 4; + case '5': + return 5; + case '6': + return 6; + case '7': + return 7; + case '8': + return 8; + case '9': + return 9; + case 'A': case 'a': + return 10; + case 'B': case 'b': + return 11; + case 'C': case 'c': + return 12; + case 'D': case 'd': + return 13; + case 'E': case 'e': + return 14; + case 'F': case 'f': + return 15; + default: + return 0; + } +} + +unsigned int EndianSwap(unsigned int Num, int Size) +{ + unsigned int a = 0; + switch(Size) + { + case 1: + return Num; + case 2: + a = (Num & 0xFF00) >> 8; + a |= (Num & 0x00FF) << 8; + return a; + case 3: + a = (Num & 0xFF) << 16; + a |= (Num & 0xFF00); + a |= (Num & 0xFF0000) >> 16; + return a; + case 4: + a = (Num & 0xFF) << 24; + a |= (Num & 0xFF00) << 8; + a |= (Num & 0xFF0000) >> 8; + a |= (Num & 0xFF000000) >> 24; + return a; + } + + return -1; +} \ No newline at end of file diff --git a/AtlasCore.h b/AtlasCore.h new file mode 100644 index 0000000..a391e11 --- /dev/null +++ b/AtlasCore.h @@ -0,0 +1,76 @@ +#pragma once + +#include "stdafx.h" +#include +#include +#include +#include +#include +#include "Table.h" +#include "GenericVariable.h" +#include "AtlasParser.h" +#include "AtlasFile.h" +#include "Pointer.h" +#include "AtlasLogger.h" +#include "AtlasStats.h" +#include "PointerHandler.h" +#include "AtlasExtension.h" +using namespace std; + +//----------------------------------------------------------------------------- +// AtlasCore Functionality +//----------------------------------------------------------------------------- + +class AtlasCore +{ +public: + AtlasCore(); + ~AtlasCore(); + + bool Insert(const char* RomFileName, const char* ScriptFileName); + void SetDebugging(FILE* output); + void CreateContext(AtlasContext** Context); + bool ExecuteExtension(string& ExtId, string& FunctionName, AtlasContext** Context); + bool ExecuteExtensionFunction(ExtensionFunction Func, AtlasContext** Context); + unsigned int GetHeaderSize(); + +private: + AtlasParser Parser; + AtlasFile File; + //AtlasFile GameFile; + //AtlasFile PtrFile; + VariableMap VarMap; // Variable Map for identifiers + PointerHandler PtrHandler; + Pointer DefaultPointer; + EmbeddedPointerHandler EmbPtrs; + InsertionStatistics Total; + ExtensionManager Extensions; + + bool IsInJmp; + unsigned int HeaderSize; + + bool ExecuteCommand(Command& Cmd); + + void PrintSummary(const char* Title, unsigned int TimeCompleted); + void PrintStatistics(); + void PrintStatisticsBlock(const char* Title, InsertionStatistics& Stats); + void PrintUnwrittenPointers(); + + bool AddTable(Command& Cmd); + bool ActivateTable(string& TableName); + bool LoadTable(string& FileName, Table** Tbl); + bool SetEndianSwap(string& Swap); +}; + +// Global Core variables +extern unsigned int CurrentLine; +extern int bSwap; +extern int StringAlign; +extern int MaxEmbPtr; +extern AtlasCore Atlas; + +// Misc functions +inline unsigned int StringToUInt(std::string& NumberString); +__int64 StringToInt64(std::string& NumberString); +unsigned int GetHexDigit(char digit); +unsigned int EndianSwap(unsigned int Num, int Size); \ No newline at end of file diff --git a/AtlasExtension.cpp b/AtlasExtension.cpp new file mode 100644 index 0000000..093a66c --- /dev/null +++ b/AtlasExtension.cpp @@ -0,0 +1,119 @@ +#include "stdafx.h" +#include +#include +#include "AtlasExtension.h" +#include "AtlasLogger.h" +#include "AtlasCore.h" + +using namespace std; + +ExtensionManager::ExtensionManager(VariableMap* Map) +{ + VarMap = Map; +} + +bool ExtensionManager::LoadExtension(string& ExtId, string& ExtensionFile) +{ + // Use file extension to pick which derived AtlasExtension to use + AtlasExtension* Ext; + size_t Pos = ExtensionFile.find_last_of('.'); + if(Pos == string::npos || Pos >= ExtensionFile.length()-1) + return false; + else if(ExtensionFile.substr(Pos+1, ExtensionFile.length()-1) == "dll") // dll + { + } + else + { + Logger.ReportError(CurrentLine, "Unsupported file format used in LOADEXT"); + return false; + } + + Ext = (AtlasExtension*)VarMap->GetVar(ExtId)->GetData(); + if(Ext != NULL) + { + Logger.ReportError(CurrentLine, "%s has alrady been initialized with LOADEXT", ExtId.c_str()); + delete Ext; + return false; + } + Ext = NULL; + Ext = new AtlasExtension; + if(!Ext->LoadExtension(ExtensionFile)) + { + Logger.ReportError(CurrentLine, "%s could not be loaded", ExtensionFile.c_str()); + delete Ext; + return false; + } + + VarMap->SetVarData(ExtId, Ext, P_EXTENSION); + return true; +} + +unsigned int ExtensionManager::ExecuteExtension(string& ExtId, string& FunctionName, AtlasContext** Context) +{ + AtlasExtension* Ext; + Ext = (AtlasExtension*)VarMap->GetVar(ExtId)->GetData(); + if(Ext == NULL) + { + Logger.ReportError(CurrentLine, "%s has not been initialized by LOADEXT", ExtId.c_str()); + return -1; + } + if(!Ext->IsLoaded()) + { + ReportBug("Extension not loaded but initialized in ExtensionManager::ExecuteExtension"); + return -1; + } + + ExtensionFunction Func = Ext->GetFunction(FunctionName); + if(Func == NULL) + { + Logger.ReportError(CurrentLine, "Function %s was not found in the extension file", FunctionName.c_str()); + return -1; + } + + unsigned int Res = Func(Context); + if(Res > MAX_RETURN_VAL) + { + Logger.ReportWarning(CurrentLine, "Extension returned invalid value %u", Res); + Res = NO_ACTION; + } + + return Res; +} + +AtlasExtension::AtlasExtension() : Extension(NULL) +{ +} + +AtlasExtension::~AtlasExtension() +{ + if(Extension) + FreeLibrary(Extension); +} + +bool AtlasExtension::LoadExtension(string& ExtensionName) +{ + Extension = LoadLibraryA(ExtensionName.c_str()); + + if(Extension) + return true; + else + return false; +} + +bool AtlasExtension::IsLoaded() +{ + if(Extension) + return true; + else + return false; +} + +ExtensionFunction AtlasExtension::GetFunction(string& FunctionName) +{ + if(NULL == Extension) + return NULL; + + ExtensionFunction func = (ExtensionFunction)GetProcAddress(Extension, FunctionName.c_str()); + + return func; +} \ No newline at end of file diff --git a/AtlasExtension.h b/AtlasExtension.h new file mode 100644 index 0000000..cd2f82a --- /dev/null +++ b/AtlasExtension.h @@ -0,0 +1,53 @@ +#pragma once +#include +#include +#include +#include "Table.h" +#include "GenericVariable.h" + +const unsigned int MAX_RETURN_VAL = 3; + +const unsigned int NO_ACTION = 0; +const unsigned int REPLACE_TEXT = 1; +const unsigned int WRITE_POINTER = 2; + +typedef struct AtlasContext +{ + unsigned int CurrentLine; + + std::list StringTable; + FILE* Target; + + unsigned int ScriptPos; + unsigned int ScriptRemaining; + + unsigned int PointerValue; + unsigned int PointerPosition; + unsigned int PointerSize; +} AtlasContext; + +typedef unsigned int (*ExtensionFunction) (AtlasContext** Context); + +class ExtensionManager +{ +public: + ExtensionManager(VariableMap* Map); + bool LoadExtension(std::string& ExtId, std::string& ExtensionFile); + unsigned int ExecuteExtension(std::string& ExtId, std::string& FunctionName, AtlasContext** Context); +private: + VariableMap* VarMap; +}; + +class AtlasExtension +{ +public: + AtlasExtension(); + ~AtlasExtension(); + + bool LoadExtension(std::string& ExtensionName); + bool IsLoaded(); + ExtensionFunction GetFunction(std::string& FunctionName); + +private: + HMODULE Extension; +}; \ No newline at end of file diff --git a/AtlasFile.cpp b/AtlasFile.cpp new file mode 100644 index 0000000..ea45bca --- /dev/null +++ b/AtlasFile.cpp @@ -0,0 +1,480 @@ +#include "stdafx.h" +#include +#include +#include "AtlasFile.h" +#include "Table.h" +#include "AtlasLogger.h" +#include "AtlasStats.h" +#include "AtlasCore.h" +#include "AtlasExtension.h" + +using namespace std; + +AtlasFile::AtlasFile() +{ + tfile = NULL; + pfile = NULL; + + MaxScriptPos = -1; + ActiveTbl = NULL; + BytesInserted = 0; + TotalBytes = 0; + TotalBytesSkipped = 0; + + StrType = STR_ENDTERM; + PascalLength = 1; + + FixedPadValue = 0; + StringLength = 0; +} + +AtlasFile::~AtlasFile() +{ + if(tfile != NULL) + fclose(tfile); + if(pfile != NULL) + fclose(pfile); +} + +bool AtlasFile::OpenFileT(const char* FileName) +{ + // Reset vars for new file + MaxScriptPos = -1; + + tfile = fopen(FileName, "r+b"); + return tfile != NULL; +} + +bool AtlasFile::OpenFileP(const char* Filename) +{ + pfile = fopen(Filename, "r+b"); + return pfile != NULL; +} + +void AtlasFile::CloseFileT() +{ + if(tfile != NULL) + fclose(tfile); +} + +void AtlasFile::CloseFileP() +{ + if(pfile != NULL) + fclose(pfile); +} + +void AtlasFile::WriteP(const void* Data, const unsigned int Size, + const unsigned int DataCount, const unsigned int Pos) +{ + unsigned int OldPos = ftell(pfile); + fseek(pfile, Pos, SEEK_SET); + fwrite(Data, Size, DataCount, pfile); + fseek(pfile, OldPos, SEEK_SET); +} + +void AtlasFile::WriteT(const void* Data, const unsigned int Size, + const unsigned int DataCount, const unsigned int Pos) +{ + unsigned int OldPos = ftell(tfile); + fseek(tfile, Pos, SEEK_SET); + fwrite(Data, Size, DataCount, tfile); + fseek(tfile, OldPos, SEEK_SET); +} + +// Does not revert file offset +void AtlasFile::WriteT(const void* Data, const unsigned int Size, const unsigned int DataCount) +{ + fwrite(Data, Size, DataCount, tfile); +} + +unsigned int AtlasFile::GetPosT() +{ + return ftell(tfile); +} + +FILE* AtlasFile::GetFileT() +{ + return tfile; +} + +FILE* AtlasFile::GetFileP() +{ + return pfile; +} + +void AtlasFile::GetScriptBuf(std::list& Strings) +{ + Strings = ActiveTbl->StringTable; +} + +void AtlasFile::SetScriptBuf(std::list& Strings) +{ + ActiveTbl->StringTable = Strings; +} + +unsigned int AtlasFile::GetStringType() +{ + return StrType; +} + +void AtlasFile::MoveT(const unsigned int Pos, const unsigned int ScriptBound) +{ + if(tfile) + fseek(tfile, Pos, SEEK_SET); + MaxScriptPos = ScriptBound; +} + +void AtlasFile::MoveT(const unsigned int Pos) +{ + if(tfile) + fseek(tfile, Pos, SEEK_SET); +} + +void AtlasFile::SetTable(Table* Tbl) +{ + FlushText(); + ActiveTbl = Tbl; +} + +bool AtlasFile::SetStringType(std::string& Type) +{ + for(int i = 0; i < StringTypeCount; i++) + { + if(Type == StringTypes[i]) + { + StrType = i; + return true; + } + } + + return false; +} + +bool AtlasFile::SetPascalLength(unsigned int Length) +{ + switch(Length) + { + case 1: case 2: case 3: case 4: + PascalLength = Length; + break; + default: + return false; + } + return true; +} + +bool AtlasFile::SetFixedLength(unsigned int StrLength, unsigned int PadValue) +{ + if(PadValue > 65536) + return false; + + StringLength = StrLength; + FixedPadValue = (unsigned char)PadValue; + + return true; +} + +bool AtlasFile::DisableWrite(string& EndTag, bool isPointerTable) +{ + if(isPointerTable) + { + std::map::iterator it; + it = TblAutoWrite.find(EndTag); + if(it == TblAutoWrite.end()) + return false; + TblAutoWrite.erase(it); + } + else + { + std::map::iterator it; + it = ListAutoWrite.find(EndTag); + if(it == ListAutoWrite.end()) + return false; + ListAutoWrite.erase(it); + } + return true; +} + +bool AtlasFile::DisableAutoExtension(string& FuncName, string& EndTag) +{ + std::map::iterator it; + it = ExtAutoWrite.find(EndTag); + if(it == ExtAutoWrite.end()) + { + Logger.ReportError(CurrentLine, "'%s' has not been defined as an autoexec end token", EndTag); + return false; + } + ExtAutoWrite.erase(it); + return true; +} + +bool AtlasFile::AutoWrite(PointerList* List, string& EndTag) +{ + bool EndTokenFound = false; + for(size_t i = 0; i < ActiveTbl->EndTokens.size(); i++) + { + if(EndTag == ActiveTbl->EndTokens[i]) + EndTokenFound = true; + } + if(EndTokenFound) + ListAutoWrite.insert(map::value_type(EndTag, List)); + return EndTokenFound; +} + +bool AtlasFile::AutoWrite(PointerTable* Tbl, string& EndTag) +{ + bool EndTokenFound = false; + for(size_t i = 0; i < ActiveTbl->EndTokens.size(); i++) + { + if(EndTag == ActiveTbl->EndTokens[i]) + EndTokenFound = true; + } + if(EndTokenFound) + TblAutoWrite.insert(map::value_type(EndTag, Tbl)); + return EndTokenFound; +} + +bool AtlasFile::AutoWrite(AtlasExtension* Ext, string& FuncName, string& EndTag) +{ + bool EndTokenFound = false; + ExtensionFunction Func; + + for(size_t i = 0; i < ActiveTbl->EndTokens.size(); i++) + { + if(EndTag == ActiveTbl->EndTokens[i]) + EndTokenFound = true; + } + Func = Ext->GetFunction(FuncName); + if(!EndTokenFound) + { + Logger.ReportError(CurrentLine, "'%s' has not been defined as an end token in the active table", EndTag); + return false; + } + if(Func == NULL) + { + Logger.ReportError(CurrentLine, "Function 's' could not be found in the extension", FuncName); + return false; + } + + ExtAutoWrite.insert(map::value_type(EndTag, Func)); + return true; +} + +bool AtlasFile::InsertText(string& Text, unsigned int Line) +{ + if(ActiveTbl == NULL) + { + // Add error + printf("No active table loaded\n"); + return false; + } + unsigned int BadCharPos = 0; + if(ActiveTbl->EncodeStream(Text, BadCharPos) == -1) // Failed insertion, char missing from tbl + { + // Add error + Logger.ReportError(Line, "Character '%c' missing from table. String = '%s'", Text[BadCharPos], Text.c_str()); + return false; + } + return true; +} + +bool AtlasFile::FlushText() +{ + static unsigned int Size; + static unsigned int Address; + static unsigned int WritePos; + AtlasContext* Context = NULL; + + if(ActiveTbl == NULL) + return false; + + if(ActiveTbl->StringTable.empty()) + return true; + + // For every string, check autowrite/autoexec (list, table, and extension) + // Automatically write pointer if appropriate end string is found, then write the text string to ROM + ListTxtStringIt j = ActiveTbl->TxtStringTable.begin(); + for(ListTblStringIt i = ActiveTbl->StringTable.begin(); + i != ActiveTbl->StringTable.end(); i++, j++) + { + // #ALIGNSTRING, must do before autowrite writes a pointer + AlignString(); + + if(!i->EndToken.empty()) // If there's an end token, check for autowrite + { + ListIt = ListAutoWrite.find(i->EndToken); + if(ListIt != ListAutoWrite.end()) + { + Address = ListIt->second->GetAddress(GetPosT(), Size, WritePos); + if(Address != -1) + { + if(bSwap) + Address = EndianSwap(Address, Size/8); + WriteP(&Address, Size/8, 1, WritePos); + Logger.Log("%6u AUTOWRITE Invoked ScriptPos $%X PointerPos $%X PointerValue $%08X\n", CurrentLine, + GetPosT(), WritePos, Address); + Stats.IncAutoPointerWrites(); + } + else + Stats.IncFailedListWrites(); + } + TblIt = TblAutoWrite.find(i->EndToken); + if(TblIt != TblAutoWrite.end()) + { + Address = TblIt->second->GetAddress(GetPosT(), Size, WritePos); + if(bSwap) + Address = EndianSwap(Address, Size/8); + WriteP(&Address, Size/8, 1, WritePos); + Logger.Log("%6u AUTOWRITE Invoked ScriptPos $%X PointerPos $%X PointerValue $%08X\n", CurrentLine, + GetPosT(), WritePos, Address); + Stats.IncAutoPointerWrites(); + } + ExtIt = ExtAutoWrite.find(i->EndToken); + if(ExtIt != ExtAutoWrite.end()) + { + Atlas.CreateContext(&Context); + bool Success = Atlas.ExecuteExtensionFunction(ExtIt->second, &Context); + delete Context; + Context = NULL; + if(!Success) + { + Logger.ReportError(CurrentLine, "Autoexecuting extension with end token '%s' failed", i->EndToken); + return false; + } + else + Logger.Log("%6u AUTOEXEC Invoked ScriptPos $%X PointerPos $%X PointerValue $%08X\n", CurrentLine, + GetPosT(), WritePos, Address); + } + } + + CurTextString = j->Text; + WriteString(i->Text); + Logger.Log("%s\n", CurTextString.c_str()); + CurTextString.clear(); + } + + ActiveTbl->StringTable.clear(); + + return true; +} + +inline bool AtlasFile::WriteString(string& text) +{ + unsigned int StringSize = 0; + int PadBytes; + + // Write string type + if(StrType == STR_ENDTERM) + StringSize = WriteNullString(text); + else if(StrType == STR_PASCAL) + StringSize = WritePascalString(text); + else + return false; + + // #FIXEDLENGTH padding + if(StringLength != 0) + { + PadBytes = StringLength - StringSize; + if(PadBytes > 0) + { + for(int i = 0; i < PadBytes; i++) + fputc((int)FixedPadValue, tfile); + BytesInserted += PadBytes; + } + } + + return true; +} + +inline unsigned int AtlasFile::WriteNullString(string& text) +{ + unsigned int size = (unsigned int)text.length(); + unsigned int maxwrite = GetMaxWritableBytes(); + + Stats.AddScriptBytes(size); + + // Truncate string if it overflows ROM bounds + if(maxwrite < size) + { + int overflowbytes = size - maxwrite; + TotalBytesSkipped += overflowbytes; + size = maxwrite; + } + + // Truncate string if it's too long for a fixed length string + if(size > StringLength && StringLength != 0) + { + TotalBytesSkipped += (size - StringLength); + size = StringLength; + printf("Changed string length for %s to %d at %X\n", CurTextString.c_str(), StringLength, GetPosT()); + } + + fwrite(text.data(), 1, size, tfile); + BytesInserted += size; + + return size; +} + +inline unsigned int AtlasFile::WritePascalString(string& text) +{ + unsigned int size = (unsigned int)text.length(); + unsigned int maxwrite = GetMaxWritableBytes(); + + Stats.AddScriptBytes(size+PascalLength); + + // Truncate string if it overflows ROM bounds + if(PascalLength > maxwrite) // PascalLength doesn't even fit + goto nowrite; + if(maxwrite < size + PascalLength) // PascalLength and maybe partial string fits + { + int overflowbytes = (size+PascalLength) - maxwrite; + TotalBytesSkipped += overflowbytes; + size = maxwrite - PascalLength; + } + + // Truncate string if it's too long for a fixed length string + if(size > StringLength && StringLength != 0) + { + TotalBytesSkipped += (size - StringLength); + size = StringLength - PascalLength; + printf("Changed string length for %s to %d at %X\n", text.c_str(), StringLength, GetPosT()); + } + + int swaplen = size; + if(bSwap) + swaplen = EndianSwap(size, PascalLength); + + fwrite(&swaplen, PascalLength, 1, tfile); + fwrite(text.c_str(), 1, size, tfile); + BytesInserted += size+PascalLength; + +nowrite: + return size+PascalLength; +} + +inline void AtlasFile::AlignString() +{ + if(StringAlign != 0) // String align turned on + { + int curoffset = GetPosT() - Atlas.GetHeaderSize(); + int PadBytes = StringAlign - (curoffset % StringAlign); + if(PadBytes == StringAlign) + PadBytes = 0; + if(PadBytes > 0) + { + for(int i = 0; i < PadBytes; i++) + fputc(0, tfile); + BytesInserted += PadBytes; + } + } +} + +inline unsigned int AtlasFile::GetMaxWritableBytes() +{ + if(MaxScriptPos == -1) + return -1; + unsigned int CurPos = ftell(tfile); + if(CurPos > MaxScriptPos) + return 0; + return MaxScriptPos - CurPos + 1; +} \ No newline at end of file diff --git a/AtlasFile.h b/AtlasFile.h new file mode 100644 index 0000000..5f3a19c --- /dev/null +++ b/AtlasFile.h @@ -0,0 +1,87 @@ +#pragma once +#include +#include +#include +#include +#include "Table.h" +#include "PointerHandler.h" +#include "AtlasExtension.h" +using namespace std; + +static const unsigned int STR_ENDTERM = 0; +static const unsigned int STR_PASCAL = 1; +static const unsigned int StringTypeCount = 2; +static const char* StringTypes[StringTypeCount] = { "ENDTERM", "PASCAL" }; + +class AtlasFile +{ +public: + AtlasFile(); + ~AtlasFile(); + + bool AutoWrite(PointerList* List, string& EndTag); + bool AutoWrite(PointerTable* Tbl, string& EndTag); + bool AutoWrite(AtlasExtension* Ext, string& FuncName, string& EndTag); + bool DisableAutoExtension(string& FuncName, string& EndTag); + bool DisableWrite(string& EndTag, bool isPointerTable); + + // File functions. T for text file, P for pointer file + bool OpenFileT(const char* FileName); + bool OpenFileP(const char* FileName); + void CloseFileT(); + void CloseFileP(); + void MoveT(const unsigned int Pos, const unsigned int ScriptBound); + void MoveT(const unsigned int Pos); + void WriteP(const void* Data, const unsigned int Size, const unsigned int DataCount, const unsigned int Pos); + void WriteT(const void* Data, const unsigned int Size, const unsigned int DataCount, const unsigned int Pos); + void WriteT(const void* Data, const unsigned int Size, const unsigned int DataCount); + unsigned int GetPosT(); + + unsigned int GetMaxBound() { return MaxScriptPos; } + unsigned int GetBytesInserted() { return BytesInserted; } + unsigned int GetBytesOverflowed() { return TotalBytesSkipped; } + + void SetTable(Table* Tbl); + bool SetStringType(string& Type); + bool SetPascalLength(unsigned int Length); + bool SetFixedLength(unsigned int StrLength, unsigned int PadValue); + + bool InsertText(string& Text, unsigned int Line); + bool FlushText(); + + inline unsigned int GetMaxWritableBytes(); + FILE* GetFileT(); + FILE* GetFileP(); + void GetScriptBuf(list& Strings); + void SetScriptBuf(list& Strings); + unsigned int GetStringType(); + +private: + FILE* tfile; // Target file for script + FILE* pfile; // Pointer write file + Table* ActiveTbl; + PointerHandler* PtrHandler; + map ListAutoWrite; + map TblAutoWrite; + map ExtAutoWrite; + map::iterator ListIt; + map::iterator TblIt; + map::iterator ExtIt; + + inline bool WriteString(string& text); + inline unsigned int WriteNullString(string& text); + inline unsigned int WritePascalString(string& text); + inline void AlignString(); + + unsigned int MaxScriptPos; + unsigned int BytesInserted; + unsigned int TotalBytesSkipped; + unsigned int TotalBytes; + + unsigned int StrType; + unsigned int PascalLength; + + unsigned int StringLength; + unsigned char FixedPadValue; + string CurTextString; // Used to keep track and report text that overflows the FIXEDLENGTH value +}; \ No newline at end of file diff --git a/AtlasLogger.cpp b/AtlasLogger.cpp new file mode 100644 index 0000000..c02eca4 --- /dev/null +++ b/AtlasLogger.cpp @@ -0,0 +1,91 @@ +#include "stdafx.h" +#include +#include +#include +#include +#include "AtlasLogger.h" + +using namespace std; + +AtlasLogger Logger; + +AtlasLogger::AtlasLogger() +{ + output = NULL; + isLogging = true; + Errors.clear(); +} + +AtlasLogger::~AtlasLogger() +{ + if(output != NULL && output != stdout) + fclose(output); +} + +void AtlasLogger::ReportError(unsigned int ScriptLine, const char* FormatStr ...) +{ + AtlasError Error; + Error.Severity = FATALERROR; + Error.LineNumber = ScriptLine; + + va_list arglist; + va_start(arglist, FormatStr); + int length = _vsnprintf(buf, BufSize, FormatStr, arglist); + va_end(arglist); + + Error.Error.assign(buf, length); + + Errors.push_back(Error); +} + +void AtlasLogger::ReportWarning(unsigned int ScriptLine, const char* FormatStr ...) +{ + AtlasError Error; + Error.Severity = WARNING; + Error.LineNumber = ScriptLine; + + va_list arglist; + va_start(arglist, FormatStr); + int length = _vsnprintf(buf, BufSize, FormatStr, arglist); + va_end(arglist); + + Error.Error.assign(buf, length); + + Errors.push_back(Error); +} + +void AtlasLogger::Log(const char* FormatStr ...) +{ + if(isLogging && output) + { + va_list arglist; + va_start(arglist, FormatStr); + vfprintf(output, FormatStr, arglist); + va_end(arglist); + } +} + +void AtlasLogger::SetLogStatus(bool LoggingOn) +{ + isLogging = LoggingOn; +} + +void AtlasLogger::SetLogSource(FILE* OutputSource) +{ + output = OutputSource; +} + +void AtlasLogger::BugReportLine(unsigned int Line, const char* Filename, const char* Msg) +{ + fprintf(stderr, "Bug: %s Line %u in source file %s\n", Msg, Line, Filename); +} + +void AtlasLogger::BugReport(unsigned int Line, const char* Filename, const char* FormatStr, ...) +{ + fprintf(stderr, "Bug: "); + va_list arglist; + va_start(arglist, FormatStr); + vfprintf(stderr, FormatStr, arglist); + va_end(arglist); + fprintf(stderr, " Line %u in source file %s\n", Line, Filename); +} \ No newline at end of file diff --git a/AtlasLogger.h b/AtlasLogger.h new file mode 100644 index 0000000..6b51a98 --- /dev/null +++ b/AtlasLogger.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include + +enum ErrorSeverity { FATALERROR = 0, WARNING }; + +typedef struct AtlasError +{ + std::string Error; + ErrorSeverity Severity; + unsigned int LineNumber; +} AtlasError; + +typedef std::list::iterator ListErrorIt; + +class AtlasLogger +{ +public: + AtlasLogger(); + ~AtlasLogger(); + + void ReportError(unsigned int ScriptLine, const char* FormatStr ...); + void ReportWarning(unsigned int ScriptLine, const char* FormatStr ...); + void Log(const char* FormatStr ...); + void SetLogSource(FILE* OutputSource); + void SetLogStatus(bool LoggingOn); + void BugReportLine(unsigned int Line, const char* Filename, const char* Msg); + void BugReport(unsigned int Line, const char* Filename, const char* FormatStr ...); + + std::list Errors; + +private: + FILE* output; + static const unsigned int BufSize = 512; + char buf[BufSize]; + bool isLogging; +}; + +extern AtlasLogger Logger; + +#define ReportBug(msg) Logger.BugReport(__LINE__, __FILE__, msg) \ No newline at end of file diff --git a/AtlasMain.cpp b/AtlasMain.cpp new file mode 100644 index 0000000..767bcc1 --- /dev/null +++ b/AtlasMain.cpp @@ -0,0 +1,47 @@ +// Atlas main + +#include "stdafx.h" +#include +#include +#include +#include "AtlasCore.h" + +using namespace std; + +int _tmain(int argc, _TCHAR* argv[]) +{ + clock_t StartTime, EndTime, ElapsedTime; + int argoff = 0; + + Logger.SetLogStatus(false); + StartTime = clock(); + + printf("Atlas 1.11 by Klarth\n\n"); + if(argc != 3 && argc != 5) + { + printf("Usage: %s [switches] ROM.ext Script.txt\n", argv[0]); + printf("Switches: -d filename or -d stdout (debugging)\n"); + printf("Arguments in brackets are optional\n"); + return 1; + } + + if(strcmp("-d", argv[1]) == 0) + { + if(strcmp("stdout", argv[2]) == 0) + Atlas.SetDebugging(stdout); + else + Atlas.SetDebugging(fopen(argv[2], "w")); + argoff+=2; + } + + if(!Atlas.Insert(argv[1+argoff], argv[2+argoff])) + printf("Insertion failed\n\n"); + + EndTime = clock(); + + ElapsedTime = EndTime - StartTime; + + printf("Execution time: %u msecs\n", (unsigned int)ElapsedTime); + + return 0; +} \ No newline at end of file diff --git a/AtlasParser.cpp b/AtlasParser.cpp new file mode 100644 index 0000000..363cba2 --- /dev/null +++ b/AtlasParser.cpp @@ -0,0 +1,362 @@ +#include "stdafx.h" +#include +#include +#include +#include +#include +#include +#include "AtlasTypes.h" +#include "AtlasParser.h" +#include "GenericVariable.h" +#include "AtlasLogger.h" +#include "AtlasCore.h" + +using namespace std; + +AtlasParser::AtlasParser(VariableMap* Map) +{ + VarMap = Map; + + // Initialize the function lookup map + for(unsigned int i=0; i < CommandCount; i++) + CmdMap.insert(multimap::value_type(CommandStrings[i], i)); + + for(unsigned int i=0; i < TypeCount; i++) + TypeMap.insert(multimap::value_type(TypeStrings[i], i)); + + CurrentLine = 0; + CurBlock.StartLine = -1; +} + +AtlasParser::~AtlasParser() +{ +} + +bool AtlasParser::ParseFile(ifstream& infile) +{ + list text; + unsigned char utfheader[4]; + + string line; + + // Detect UTF-8 header + if(infile.peek() == 0xEF) + { + infile.read((char*)utfheader, 3); + if(utfheader[0] != 0xEF || utfheader[1] != 0xBB || utfheader[2] != 0xBF) + infile.seekg(ios::beg); // Seek beginning, not a UTF-8 header + } + + // Read the file + while(!infile.eof()) + { + getline(infile, line); + text.push_back(line); + } + + infile.close(); + CurrentLine = 1; + + // Parse the file and build the series of AtlasBlocks + for(ListStringIt it = text.begin(); it != text.end(); it++) + { + ParseLine(*it); + CurrentLine++; + } + + if(!CurBlock.Commands.empty() || !CurBlock.TextLines.empty()) + FlushBlock(); + + for(ListErrorIt i = Logger.Errors.begin(); i != Logger.Errors.end(); i++) + { + if(i->Severity == FATALERROR) + return false; + } + + return true; +} + +void AtlasParser::ParseLine(string& line) +{ + size_t firstchar = line.find_first_not_of(" \t", 0); + + if(firstchar == string::npos) // All whitespace + { + string s = ""; + AddText(s); + return; + } + + string editline = line.substr(firstchar, line.length() - firstchar); + + switch(line[firstchar]) + { + case '#': // Atlas command + if(CurBlock.TextLines.empty()) // No text, build more commands + { + ParseCommand(editline); + } + else // Clear, parse the command + { + FlushBlock(); + ParseCommand(editline); + } + break; + case '/': // Possible comment + if(line.length() > firstchar+1) + { + if(line[firstchar+1] != '/') // Not a comment "//", but text + AddText(line); + // else; Comment + } + else // Single text character of '/' + AddText(line); + break; + default: // Text + AddText(line); + break; + } +} + +inline void AtlasParser::FlushBlock() +{ + Blocks.push_back(CurBlock); + CurBlock.TextLines.clear(); + CurBlock.Commands.clear(); + CurBlock.StartLine = -1; +} + +inline void AtlasParser::AddText(string& text) +{ + if(CurBlock.StartLine == -1) + CurBlock.StartLine = CurrentLine; + + CurBlock.TextLines.push_back(text); +} + +inline void AtlasParser::ParseCommand(string& line) +{ + if(line[0] != '#') + printf("Bug, %s %d. Should start with a '#'\n'%s'", __FILE__, __LINE__, line); + + size_t curpos = 1; + std::string CmdStr; + + Parameter Param; + Command Command; + Param.Type = P_INVALID; + + char ch; + + while(curpos < line.length() && (ch = line[curpos]) != '(') + { + if(isalpha(ch) || isdigit(ch)) + CmdStr += ch; + else Logger.ReportError(CurrentLine, "Invalid syntax: Nonalphabetical character in command"); + + curpos++; + } + + curpos = line.find_first_not_of(" \t", curpos + 1); // Skip ')', get first non + // wspace character + + // Parse parameters + unsigned int ParamNum = 1; + while(curpos < line.length() && (ch = line[curpos]) != ')') + { + if(ch == ',') + { + // Trim trailing whitespace + size_t Last; + for(Last = Param.Value.length() - 1; Last > 0; Last--) + if(Param.Value[Last] != ' ' && Param.Value[Last] != '\t') + break; + if(Last < Param.Value.length()) + Param.Value.erase(Last+1); + + Param.Type = IdentifyType(Param.Value); + if(Param.Type == P_INVALID) + Logger.ReportError(CurrentLine, "Invalid argument for %s for parameter %d", CmdStr.c_str(), ParamNum); + Command.Parameters.push_back(Param); + Param.Type = P_INVALID; + Param.Value.clear(); + ParamNum++; + curpos = line.find_first_not_of(" \t", curpos + 1); + } + else + { + Param.Value += ch; + curpos++; + } + } + + // Trim trailing whitespace + size_t Last; + for(Last = Param.Value.length() - 1; Last > 0; Last--) + if(Param.Value[Last] != ' ' && Param.Value[Last] != '\t') + break; + if(Last < Param.Value.length()) + Param.Value.erase(Last+1); + + Param.Type = IdentifyType(Param.Value); + if(Param.Type == P_INVALID) + Logger.ReportError(CurrentLine, "Invalid argument for %s for parameter %d", CmdStr.c_str(), ParamNum); + + for(ListErrorIt i = Logger.Errors.begin(); i != Logger.Errors.end(); i++) + if(i->Severity = FATALERROR) + return; + + Command.Parameters.push_back(Param); + + AddCommand(CmdStr, Command); +} + +inline unsigned int AtlasParser::IdentifyType(string& str) +{ + if(str.empty()) + return P_VOID; + + size_t charpos = 0; + + // Check for number (int/uint) + if(str[0] == '$') + { + charpos = str.find_first_of('-', 1); + if(charpos == 1 || charpos == string::npos) + { + charpos = str.find_first_not_of("-0123456789ABCDEF", 1); + if(charpos == string::npos) + return P_NUMBER; + } + } + else + { + charpos = str.find_first_of('-'); + if(charpos == 0 || charpos == string::npos) + { + charpos = str.find_first_not_of("0123456789", 1); + if(charpos == string::npos) + return P_NUMBER; + } + } + + // Check for double + charpos = str.find_first_not_of("0123456789.", 0); + if(charpos == string::npos) + return P_DOUBLE; + + // Check for variable + charpos = str.find_first_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJLMNOPQRSTUVWXYZ", 0); + if(charpos == 0) + { + charpos = str.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJLMNOPQRSTUVWXYZ0123456789", 0); + if(charpos == string::npos) + return P_VARIABLE; + } + + // Check for string + if((str[0] == '"') && (str[str.length()-1] == '"')) + { + str = str.substr(1, str.length()-2); + return P_STRING; + } + + return P_INVALID; +} + +inline bool AtlasParser::AddCommand(string& CmdStr, Command& Cmd) +{ + bool bFound = false; + unsigned int CmdNum = 0; + + Cmd.Line = CurrentLine; + pair val = CmdMap.equal_range(CmdStr); + if(val.first == val.second) // not found + { + Logger.ReportError(CurrentLine, "Invalid command %s", CmdStr.c_str()); + return false; + } + + // Found one or more matches + for(StrCmdMapIt i = val.first; i != val.second; i++) + { + CmdNum = i->second; + if(ParamCount[CmdNum] != Cmd.Parameters.size()) + continue; + // Found a matching arg count function, check types + ListParamIt it = Cmd.Parameters.begin(); + for(unsigned int j = 0; j < Cmd.Parameters.size(); j++, it++) + { + if((it->Type == P_VARIABLE) && (CmdNum != CMD_VAR)) // Type-checking for vars + { + GenericVariable* var = VarMap->GetVar(it->Value); + if(var) // Found, check the type + { + if(var->GetType() != Types[CmdNum][j]) // Type mismatch + break; + else + it->Type = Types[CmdNum][j]; + } + else // NULL + { + Logger.ReportError(CurrentLine, "Undefined variable %s", (it->Value).c_str()); + return false; + } + } + if(it->Type != Types[CmdNum][j]) // Type checking for everything + break; + if(j == Cmd.Parameters.size() - 1) // Verified final parameter + bFound = true; + } + if(bFound) + break; + } + + if(bFound) // Successful lookup + { + Cmd.Function = CmdNum; + if(CmdNum == CMD_VAR) // Variable declaration, handled here explicitly + { + return AddUnitializedVariable(Cmd.Parameters[0].Value, Cmd.Parameters[1].Value); + } + else + { + // Hack for preallocating just enough embedded pointers + if(CmdNum == CMD_EMBSET || CmdNum == CMD_EMBWRITE) + { + int ptrcount = StringToUInt(Cmd.Parameters[0].Value); + if(ptrcount > MaxEmbPtr) + MaxEmbPtr = ptrcount; + } + CurBlock.Commands.push_back(Cmd); + } + return true; + } + else + { + ostringstream ErrorStr; + ErrorStr << "Invalid parameters " << "("; + if(Cmd.Parameters.size() > 0) + ErrorStr << TypeStrings[Cmd.Parameters.front().Type]; + for(unsigned int i = 1; i < Cmd.Parameters.size(); i++) + ErrorStr << "," << TypeStrings[Cmd.Parameters[i].Type]; + ErrorStr << ") for " << CmdStr; + Logger.ReportError(CurrentLine, "%s", ErrorStr.str().c_str()); + return false; + } +} + +inline bool AtlasParser::AddUnitializedVariable(string& VarName, string& Type) +{ + StrTypeMapIt it = TypeMap.find(Type); + if(it == TypeMap.end()) // not found + { + Logger.ReportError(CurrentLine, "Invalid VAR declaration of type %s", Type.c_str()); + return false; + } + else // Add to the variable map + { + VarMap->AddVar(VarName, 0, it->second); + return true; + } +} \ No newline at end of file diff --git a/AtlasParser.h b/AtlasParser.h new file mode 100644 index 0000000..44c1acb --- /dev/null +++ b/AtlasParser.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include +#include "AtlasTypes.h" +#include "GenericVariable.h" + +class AtlasParser +{ +public: + AtlasParser(VariableMap* Map); + ~AtlasParser(); + bool ParseFile(std::ifstream& infile); + + std::list Blocks; + +private: + void ParseLine(std::string& line); + inline void ParseCommand(std::string& line); + inline void FlushBlock(); + inline void AddText(std::string& text); + inline unsigned int IdentifyType(std::string& str); + inline bool AddCommand(std::string& CmdStr, Command& Cmd); + inline bool AddUnitializedVariable(std::string& VarName, std::string& Type); + + unsigned int CurrentLine; + AtlasBlock CurBlock; + StrCmdMap CmdMap; + StrTypeMap TypeMap; + VariableMap* VarMap; +}; \ No newline at end of file diff --git a/AtlasStats.cpp b/AtlasStats.cpp new file mode 100644 index 0000000..13d8430 --- /dev/null +++ b/AtlasStats.cpp @@ -0,0 +1,208 @@ +#include "stdafx.h" +#include +#include +#include "AtlasTypes.h" +#include "AtlasLogger.h" +#include "AtlasStats.h" + +StatisticsHandler Stats; + +InsertionStatistics::InsertionStatistics() +{ + ClearStats(); +} + +void InsertionStatistics::Init(unsigned int StartPos, unsigned int UpperBound, unsigned int LineStart) +{ + ClearStats(); + this->StartPos = StartPos; + this->LineStart = LineStart; + if(UpperBound != -1) + MaxBound = UpperBound; +} + +void InsertionStatistics::AddStats(InsertionStatistics& Stats) +{ + ScriptSize += Stats.ScriptSize; + ScriptOverflowed += Stats.ScriptOverflowed; + SpaceRemaining += Stats.SpaceRemaining; + PointerWrites += Stats.PointerWrites; + EmbPointerWrites += Stats.EmbPointerWrites; + AutoPointerWrites += Stats.AutoPointerWrites; + FailedListWrites += Stats.FailedListWrites; + ExtPointerWrites += Stats.ExtPointerWrites; + + for(int j = 0; j < CommandCount; j++) + ExecCount[j] += Stats.ExecCount[j]; +} + +void InsertionStatistics::ClearStats() +{ + ScriptSize = 0; + ScriptOverflowed = 0; + SpaceRemaining = 0; + PointerWrites = 0; + EmbPointerWrites = 0; + AutoPointerWrites = 0; + FailedListWrites = 0; + ExtPointerWrites = 0; + + StartPos = 0; + MaxBound = -1; + + LineStart = 0; + LineEnd = 0; + memset(ExecCount, 0, 4 * CommandCount); +} + +void InsertionStatistics::AddCmd(unsigned int CmdNum) +{ + ExecCount[CmdNum]++; + switch(CmdNum) + { + case CMD_WUB: case CMD_WBB: case CMD_WHB: case CMD_WLB: case CMD_WHW: + case CMD_W16: case CMD_W24: case CMD_W32: case CMD_WRITEPTR: + case CMD_WUBCUST: case CMD_WBBCUST: case CMD_WHBCUST: case CMD_WLBCUST: + case CMD_WHWCUST: + PointerWrites++; + break; + default: + break; + } +} + +bool InsertionStatistics::HasCommands() +{ + for(unsigned int i = 0; i < CommandCount; i++) + if(ExecCount[i] != 0) + return true; + + return false; +} + +InsertionStatistics& InsertionStatistics::operator=(const InsertionStatistics& rhs) +{ + if(this == &rhs) + return *this; + + ScriptSize = rhs.ScriptSize; + ScriptOverflowed = rhs.ScriptOverflowed; + SpaceRemaining = rhs.SpaceRemaining; + PointerWrites = rhs.PointerWrites; + EmbPointerWrites = rhs.EmbPointerWrites; + + StartPos = rhs.StartPos; + MaxBound = rhs.MaxBound; + + LineStart = rhs.LineStart; + LineEnd = rhs.LineEnd; + + for(unsigned int i = 0; i < CommandCount; i++) + ExecCount[i] = rhs.ExecCount[i]; + + return *this; +} + +StatisticsHandler::StatisticsHandler() +{ +} + +StatisticsHandler::~StatisticsHandler() +{ +} + +void StatisticsHandler::NewStatsBlock(unsigned int StartPos, unsigned int UpperBound, unsigned int LineStart) +{ + if(CurBlock.LineStart != 0) // If not first block + { + CurBlock.ScriptOverflowed = 0; + CurBlock.SpaceRemaining = 0; + + if(CurBlock.MaxBound != -1) // if there is a MaxBound, calc overflow and remaining space + { + if(CurBlock.StartPos + CurBlock.ScriptSize > CurBlock.MaxBound+1) + CurBlock.ScriptOverflowed = CurBlock.StartPos + CurBlock.ScriptSize - CurBlock.MaxBound; + else + CurBlock.ScriptOverflowed = 0; + + if(CurBlock.MaxBound+1 > (CurBlock.StartPos + CurBlock.ScriptSize)) + CurBlock.SpaceRemaining = CurBlock.MaxBound+1 - (CurBlock.StartPos + CurBlock.ScriptSize); + else + CurBlock.SpaceRemaining = 0; + } + CurBlock.LineEnd = LineStart; + Stats.push_back(CurBlock); + } + + CurBlock.Init(StartPos, UpperBound, LineStart); +} + +void StatisticsHandler::AddCmd(unsigned int CmdNum) +{ + if(CmdNum < CommandCount) + CurBlock.AddCmd(CmdNum); +} + +void StatisticsHandler::IncGenPointerWrites() +{ + CurBlock.PointerWrites++; +} + +void StatisticsHandler::IncEmbPointerWrites() +{ + CurBlock.EmbPointerWrites++; +} + +void StatisticsHandler::IncAutoPointerWrites() +{ + CurBlock.AutoPointerWrites++; +} + +void StatisticsHandler::IncFailedListWrites() +{ + CurBlock.FailedListWrites++; +} + +void StatisticsHandler::IncExtPointerWrites() +{ + CurBlock.ExtPointerWrites++; +} + +void StatisticsHandler::AddScriptBytes(unsigned int Count) +{ + CurBlock.ScriptSize += Count; +} + +void StatisticsHandler::End(unsigned int EndLine) +{ + if(CurBlock.StartPos + CurBlock.ScriptSize > CurBlock.MaxBound) + CurBlock.ScriptOverflowed = CurBlock.StartPos + CurBlock.ScriptSize - CurBlock.MaxBound; + else + CurBlock.ScriptOverflowed = 0; + + if(CurBlock.MaxBound != -1 && CurBlock.MaxBound > (CurBlock.StartPos + CurBlock.ScriptSize)) + CurBlock.SpaceRemaining = CurBlock.MaxBound - (CurBlock.StartPos + CurBlock.ScriptSize); + else + CurBlock.SpaceRemaining = 0; + + CurBlock.LineEnd = EndLine; + Stats.push_back(CurBlock); + CurBlock.ClearStats(); +} + +void StatisticsHandler::GenerateTotalStats(InsertionStatistics& Total) +{ + if(Stats.empty()) + { + ReportBug("Invalid size for statistics list in StatisticsHandler::GenerateTotalStats"); + return; + } + else if(Stats.size() == 1) + { + Total = Stats.front(); + return; + } + + for(ListStatsIt i = Stats.begin(); i != Stats.end(); i++) + Total.AddStats(*i); +} \ No newline at end of file diff --git a/AtlasStats.h b/AtlasStats.h new file mode 100644 index 0000000..4b2ecf9 --- /dev/null +++ b/AtlasStats.h @@ -0,0 +1,61 @@ +#pragma once +#include +#include "AtlasTypes.h" + +class InsertionStatistics +{ +public: + InsertionStatistics(); + void AddStats(InsertionStatistics& Stats); + void ClearStats(); + void Init(unsigned int StartPos, unsigned int UpperBound, unsigned int LineStart); + void AddCmd(unsigned int CmdNum); + bool HasCommands(); + + InsertionStatistics& operator=(const InsertionStatistics& rhs); + + unsigned int StartPos; + unsigned int ScriptSize; + unsigned int ScriptOverflowed; + unsigned int SpaceRemaining; + unsigned int MaxBound; + + unsigned int LineStart; + unsigned int LineEnd; + + unsigned int PointerWrites; + unsigned int EmbPointerWrites; + unsigned int AutoPointerWrites; + unsigned int FailedListWrites; + unsigned int ExtPointerWrites; + + unsigned int ExecCount[CommandCount]; +}; + +class StatisticsHandler +{ +public: + StatisticsHandler(); + ~StatisticsHandler(); + + std::list Stats; + + void NewStatsBlock(unsigned int StartPos, unsigned int UpperBound, unsigned int LineStart); + void AddCmd(unsigned int CmdNum); + void AddScriptBytes(unsigned int Count); + void End(unsigned int EndLine); + void GenerateTotalStats(InsertionStatistics& Total); + void IncGenPointerWrites(); + void IncEmbPointerWrites(); + void IncAutoPointerWrites(); + void IncFailedListWrites(); + void IncExtPointerWrites(); + +private: + InsertionStatistics CurBlock; +}; + +typedef std::list::iterator ListStatsIt; +typedef std::list::reverse_iterator ListStatsRevIt; + +extern StatisticsHandler Stats; \ No newline at end of file diff --git a/AtlasTypes.cpp b/AtlasTypes.cpp new file mode 100644 index 0000000..1577c4e --- /dev/null +++ b/AtlasTypes.cpp @@ -0,0 +1 @@ +#include "stdafx.h" \ No newline at end of file diff --git a/AtlasTypes.h b/AtlasTypes.h new file mode 100644 index 0000000..16767c8 --- /dev/null +++ b/AtlasTypes.h @@ -0,0 +1,153 @@ +#pragma once + +#include +#include + +/* Misc Functions */ +static const unsigned int CMD_JMP1 = 0; +static const unsigned int CMD_JMP2 = 1; +static const unsigned int CMD_SMA = 2; +static const unsigned int CMD_HDR = 3; +static const unsigned int CMD_STRTYPE = 4; +static const unsigned int CMD_ADDTBL = 5; +static const unsigned int CMD_ACTIVETBL = 6; +static const unsigned int CMD_VAR = 7; +/* Pointer Functions */ +static const unsigned int CMD_WUB = 8; +static const unsigned int CMD_WBB = 9; +static const unsigned int CMD_WHB = 10; +static const unsigned int CMD_WLB = 11; +static const unsigned int CMD_W16 = 12; +static const unsigned int CMD_W24 = 13; +static const unsigned int CMD_W32 = 14; +static const unsigned int CMD_EMBSET = 15; +static const unsigned int CMD_EMBTYPE = 16; +static const unsigned int CMD_EMBWRITE = 17; +/* Debugging Functions */ +static const unsigned int CMD_BREAK = 18; +/* Extended Pointer Functionality */ +static const unsigned int CMD_PTRTBL = 19; +static const unsigned int CMD_WRITETBL = 20; +static const unsigned int CMD_PTRLIST = 21; +static const unsigned int CMD_WRITELIST = 22; +static const unsigned int CMD_AUTOWRITETBL = 23; +static const unsigned int CMD_AUTOWRITELIST = 24; +static const unsigned int CMD_CREATEPTR = 25; +static const unsigned int CMD_WRITEPTR = 26; + +static const unsigned int CMD_LOADEXT = 27; +static const unsigned int CMD_EXECEXT = 28; +static const unsigned int CMD_DISABLETABLE = 29; +static const unsigned int CMD_DISABLELIST = 30; +static const unsigned int CMD_PASCALLEN = 31; +static const unsigned int CMD_AUTOEXEC = 32; +static const unsigned int CMD_DISABLEEXEC = 33; +static const unsigned int CMD_FIXEDLENGTH = 34; + +static const unsigned int CMD_WUBCUST = 35; +static const unsigned int CMD_WBBCUST = 36; +static const unsigned int CMD_WHBCUST = 37; +static const unsigned int CMD_WLBCUST = 38; +static const unsigned int CMD_ENDIANSWAP = 39; +static const unsigned int CMD_STRINGALIGN = 40; + +// Add these commands! +static const unsigned int CMD_EMBPTRTABLE = 41; +static const unsigned int CMD_WHW = 42; +static const unsigned int CMD_WHWCUST = 43; +static const unsigned int CMD_SETTARGETFILE = 44; +static const unsigned int CMD_SETPTRFILE = 45; +static const unsigned int CMD_WRITEEMBTBL1 = 46; +static const unsigned int CMD_WRITEEMBTBL2 = 47; +static const unsigned int CMD_WRITETBL2 = 48; + +static const unsigned int CommandCount = 49; + +static const char* CommandStrings[CommandCount] = { "JMP", "JMP", "SMA", "HDR", "STRTYPE", + "ADDTBL", "ACTIVETBL", "VAR", "WUB", "WBB", "WHB", "WLB", "W16", "W24", "W32", + "EMBSET", "EMBTYPE", "EMBWRITE", "BREAK", "PTRTBL", "WRITE", "PTRLIST", "WRITE", + "AUTOWRITE", "AUTOWRITE", "CREATEPTR", "WRITE", "LOADEXT", "EXECEXT", "DISABLE", "DISABLE", + "PASCALLEN", "AUTOEXEC", "DISABLE", "FIXEDLENGTH", "WUB", "WBB", "WHB", "WLB", + "ENDIANSWAP", "STRINGALIGN", "EMBPTRTBL", "WHW", "WHW", "SETTARGETFILE", "SETPTRFILE", "WRITE", + "WRITE", "WRITE" }; + +// Parameter types +static const unsigned int TypeCount = 12; + +static const unsigned int P_INVALID = 0; +static const unsigned int P_VOID = 1; +static const unsigned int P_STRING = 2; +static const unsigned int P_VARIABLE = 3; +static const unsigned int P_NUMBER = 4; +static const unsigned int P_DOUBLE = 5; +static const unsigned int P_TABLE = 6; +static const unsigned int P_POINTERTABLE = 7; +static const unsigned int P_EMBPOINTERTABLE = 8; +static const unsigned int P_POINTERLIST = 9; +static const unsigned int P_CUSTOMPOINTER = 10; +static const unsigned int P_EXTENSION = 11; + +static const char* TypeStrings[TypeCount] = { "INVALID", "VOID", "STRING", "VARIABLE", + "NUMBER", "DOUBLE", "TABLE", "POINTERTABLE", "EMBPOINTERTABLE", "POINTERLIST", "CUSTOMPOINTER", "EXTENSION" }; + +static const unsigned int Types[CommandCount][5] = { { P_NUMBER }, { P_NUMBER, P_NUMBER }, // JMP1 JMP2 +{ P_STRING }, { P_NUMBER }, { P_STRING }, { P_STRING, P_TABLE }, { P_TABLE }, // SMA HDR STRTYPE ADDTBL ACTIVETBL +{ P_VARIABLE, P_VARIABLE }, { P_NUMBER }, {P_NUMBER }, // VAR WUB WBB +{ P_NUMBER }, { P_NUMBER }, { P_NUMBER }, { P_NUMBER }, { P_NUMBER }, // WHB WLB W16 W24 W32 +{ P_NUMBER }, { P_STRING, P_NUMBER, P_NUMBER }, { P_NUMBER }, // EMBSET EMBTYPE EMBWRITE +{ P_VOID }, // BREAK +{ P_POINTERTABLE, P_NUMBER, P_NUMBER, P_CUSTOMPOINTER }, { P_POINTERTABLE }, // PTRTBL WRITE +{ P_POINTERLIST, P_STRING, P_CUSTOMPOINTER }, { P_POINTERLIST }, // PTRLIST WRITE +{ P_POINTERTABLE, P_STRING }, { P_POINTERLIST, P_STRING }, // AUTOWRITE AUTOWRITE +{ P_CUSTOMPOINTER, P_STRING, P_NUMBER, P_NUMBER }, { P_CUSTOMPOINTER, P_NUMBER }, // CREATEPTR WRITE +{ P_EXTENSION, P_STRING }, { P_EXTENSION, P_STRING }, // LOADEXT EXECEXT +{ P_POINTERTABLE, P_STRING }, { P_POINTERLIST, P_STRING }, // DISABLE DISABLE +{ P_NUMBER }, { P_EXTENSION, P_STRING, P_STRING }, // PASCALLEN AUTOEXEC +{ P_STRING, P_STRING }, { P_NUMBER, P_NUMBER }, // DISABLE FIXEDLENGTH +{ P_CUSTOMPOINTER, P_NUMBER }, { P_CUSTOMPOINTER, P_NUMBER }, // WUB WBB +{ P_CUSTOMPOINTER, P_NUMBER }, { P_CUSTOMPOINTER, P_NUMBER }, // WHB WLB +{ P_STRING }, { P_NUMBER }, // ENDIANSWAP STRINGALIGN +{ P_EMBPOINTERTABLE, P_NUMBER, P_CUSTOMPOINTER }, // EMBPTRTBL +{ P_NUMBER }, { P_CUSTOMPOINTER, P_NUMBER }, { P_STRING }, {P_STRING }, // WHW WHW SETTARGETFILE SETPTRFILE +{ P_EMBPOINTERTABLE }, { P_EMBPOINTERTABLE, P_NUMBER }, { P_POINTERTABLE, P_NUMBER } // WRITE WRITE WRITE +}; + +static const unsigned int ParamCount[CommandCount] = { 1, 2, 1, // JMP1 JMP2 SMA +1, 1, 2, 1, 2, 1, 1, // HDR STRTYPE ADDTBL ACTIVETBL VAR WUB WBB +1, 1, 1, 1, 1, 1, 3, 1, // WHB WLB W16 W24 W32 EMBSET EMBTYPE EMBWRITE +1, // BREAK +4, 1, 3, 1, 2, 2, // PTRTBL WRITE PTRLIST WRITE AUTOWRITE AUTOWRITE +4, 2, 2, 2, 2, 2, 1, 3, 2, 2, // CREATEPTR WRITE LOADEXT EXECEXT DISABLE DISABLE PASCALLEN AUTOEXEC DISABLE FIXEDLENGTH +2, 2, 2, 2, 1, 1, 3, 1, 2, 1, 1, // WUB WBB WHB WLB ENDIANSWAP STRINGALIGN EMBPTRTBL WHW WHW SETTARGETFILE SETPTRFILE +1, 2, 2 }; // WRITE WRITE WRITE + +typedef struct Parameter +{ + std::string Value; + unsigned int Type; +} Parameter; + +typedef struct Command +{ + unsigned int Function; + std::vector Parameters; + unsigned int Line; +} Command; + +typedef struct AtlasBlock +{ + std::list Commands; + std::list TextLines; + unsigned int StartLine; +} AtlasBlock; + +typedef std::multimap StrCmdMap; +typedef std::multimap::const_iterator StrCmdMapIt; + +typedef std::map StrTypeMap; +typedef std::map::const_iterator StrTypeMapIt; + +typedef std::vector::iterator ListParamIt; +typedef std::list::iterator ListStringIt; +typedef std::list::iterator ListCmdIt; +typedef std::list::iterator ListBlockIt; \ No newline at end of file diff --git a/GenericVariable.cpp b/GenericVariable.cpp new file mode 100644 index 0000000..59088b8 --- /dev/null +++ b/GenericVariable.cpp @@ -0,0 +1,169 @@ +#include "stdafx.h" +#include +#include +#include +#include "GenericVariable.h" +#include "Table.h" +#include "AtlasCore.h" +#include "AtlasExtension.h" +#include "Pointer.h" +#include "AtlasTypes.h" + +using namespace std; + +GenericVariable::GenericVariable(void* Data, unsigned int Type) +{ + DataType = Type; + DataPointer = Data; +} + +GenericVariable::GenericVariable() +{ + DataType = P_INVALID; + DataPointer = NULL; +} + +GenericVariable::~GenericVariable() +{ + Free(); +} + +void GenericVariable::SetData(void* Data, unsigned int Type) +{ + Free(); + DataType = Type; + DataPointer = Data; +} + +void* GenericVariable::GetData() +{ + return DataPointer; +} + +unsigned int GenericVariable::GetType() +{ + return DataType; +} + +bool GenericVariable::Free() +{ + if(DataPointer == NULL) + return true; + switch(DataType) + { + case P_INVALID: + break; + case P_STRING: + delete (string*)DataPointer; + break; + case P_NUMBER: + delete (__int64*)DataPointer; + break; + case P_DOUBLE: + delete (double*)DataPointer; + break; + case P_TABLE: + delete (Table*)DataPointer; + break; + case P_POINTERTABLE: + delete (PointerTable*)DataPointer; + break; + case P_POINTERLIST: + delete (PointerList*)DataPointer; + break; + case P_CUSTOMPOINTER: + delete (CustomPointer*)DataPointer; + break; + case P_EXTENSION: + delete (AtlasExtension*)DataPointer; + break; + default: + return false; + } + + return true; +} + +VariableMap::VariableMap() +{ +} + +VariableMap::~VariableMap() +{ + for(VarMapIt = VarMap.begin(); VarMapIt != VarMap.end(); VarMapIt++) + delete VarMapIt->second; +} + +bool VariableMap::AddVar(string& Identifier, void* Data, unsigned int Type) +{ + VarMapIt = VarMap.find(string(Identifier)); + if(VarMapIt != VarMap.end()) // Already a variable under that Identifier + return false; + + GenericVariable* CVar = new GenericVariable; + CVar->SetData(Data, Type); + VarMap[Identifier] = CVar; + return true; +} + +bool VariableMap::Exists(string& Identifier) +{ + VarMapIt = VarMap.find(Identifier); + if(VarMapIt == VarMap.end()) // Not found + return false; + return true; +} + +bool VariableMap::Exists(string& Identifier, unsigned int Type) +{ + VarMapIt = VarMap.find(Identifier); + if(VarMapIt == VarMap.end()) // Identifier not found + return false; + if(VarMap[string(Identifier)]->GetType() != Type) + return false; + return true; +} + +GenericVariable* VariableMap::GetVar(string& Identifier) +{ + VarMapIt = VarMap.find(Identifier); + if(VarMapIt == VarMap.end()) + return NULL; + else + return VarMapIt->second; +} + +void VariableMap::SetVar(string& Identifier, GenericVariable* Var) +{ + VarMapIt = VarMap.lower_bound(Identifier); + if(VarMapIt != VarMap.end() && !(VarMap.key_comp()(Identifier, VarMapIt->first))) + { + delete VarMapIt->second; + VarMapIt->second = Var; + } + else // Add variable + VarMap.insert(VarMapIt, VariableMapValue(Identifier, Var)); +} + +void VariableMap::SetVarData(string& Identifier, void* Data, unsigned int Type) +{ + VarMapIt = VarMap.lower_bound(Identifier); + if(VarMapIt != VarMap.end() && !(VarMap.key_comp()(Identifier, VarMapIt->first))) + (VarMapIt->second)->SetData(Data, Type); + else // Add variable + VarMap.insert(VarMapIt, VariableMapValue(Identifier, new GenericVariable(Data, Type))); +} + +unsigned int VariableMap::GetVarType(string& Identifier) +{ + if(!Exists(Identifier)) + return P_INVALID; + return VarMap[string(Identifier)]->GetType(); +} + +void* VariableMap::GetData(string& Identifier) +{ + if(!Exists(Identifier)) + return NULL; + return VarMap[Identifier]->GetData(); +} \ No newline at end of file diff --git a/GenericVariable.h b/GenericVariable.h new file mode 100644 index 0000000..f907af9 --- /dev/null +++ b/GenericVariable.h @@ -0,0 +1,50 @@ +#pragma once +#include +#include +#include +#include "AtlasTypes.h" + +using namespace std; + +class GenericVariable +{ +public: + GenericVariable(); + GenericVariable(void* Data, unsigned int Type); + ~GenericVariable(); + + unsigned int GetType(); + void* GetData(); + void SetData(void* Data, unsigned int Type); + void SetData(void* Data); + +private: + bool Free(); + + void* DataPointer; + unsigned int DataType; +}; + +typedef std::map VarMapType; +typedef std::map::iterator VariableMapIt; +typedef std::map::value_type VariableMapValue; + +class VariableMap +{ +public: + VariableMap(); + ~VariableMap(); + + bool AddVar(std::string& Identifier, void* Data, unsigned int Type); + bool Exists(std::string& Identifier, unsigned int Type); + bool Exists(std::string& Identifier); + GenericVariable* GetVar(std::string& Identifier); + void SetVarData(std::string& Identifier, void* Data, unsigned int Type); + void SetVar(std::string& Identifier, GenericVariable* Var); + void* GetData(std::string& Identifier); + unsigned int GetVarType(std::string& Identifier); + +private: + VarMapType VarMap; // Maps strings to variables + VariableMapIt VarMapIt; // Iterator for the map +}; \ No newline at end of file diff --git a/Pointer.cpp b/Pointer.cpp new file mode 100644 index 0000000..2d947c2 --- /dev/null +++ b/Pointer.cpp @@ -0,0 +1,463 @@ +#include "stdafx.h" +#include +#include "Pointer.h" +#include "AtlasLogger.h" + +using namespace std; + +Pointer::Pointer() +{ + AddressType = LINEAR; + HeaderSize = 0; +} + +Pointer::~Pointer() +{ +} + +bool Pointer::SetAddressType(string& Type) +{ + for(int i = 0; i < AddressTypeCount; i++) + { + if(Type == AddressTypes[i]) + { + AddressType = i; + return true; + } + } + + return false; +} + +bool Pointer::SetAddressType(unsigned int Type) +{ + if(Type < AddressTypeCount) + { + AddressType = Type; + return true; + } + else + return false; +} + +void Pointer::SetHeaderSize(const unsigned int Size) +{ + HeaderSize = Size; +} + +unsigned int Pointer::GetAddress(const unsigned int Address) const +{ + return GetMachineAddress(Address); +} + +unsigned int Pointer::GetMachineAddress(unsigned int Address) const +{ + Address -= HeaderSize; + + switch(AddressType) + { + case LINEAR: + return Address; + case LOROM00: + return GetLoROMAddress(Address); + case LOROM80: + return GetLoROMAddress(Address) + 0x800000; + case HIROM: + return GetHiROMAddress(Address); + case GB: + return GetGBAddress(Address); + default: + return Address; // Error handling + } +} + +unsigned int Pointer::GetLoROMAddress(unsigned int Offset) const +{ + char bankbyte = (char) ((Offset & 0xFF0000) >> 16); + unsigned short int Word = (unsigned short int) (Offset & 0xFFFF); + unsigned int Address = 0; + + if(Word >= 0x8000) + Address = bankbyte * 0x20000 + 0x10000 + Word; + else + Address = bankbyte * 0x20000 + Word + 0x8000; + + return Address; +} + +unsigned int Pointer::GetHiROMAddress(unsigned int Offset) const +{ + unsigned int Address = 0; + + Address = Offset + 0xC00000; + + return Address; +} + +unsigned int Pointer::GetGBAddress(unsigned int Offset) const +{ + unsigned int Address = 0; + unsigned short int Bank = 0; + unsigned short int Word = 0; + + Bank = Offset / 0x4000; + Word = Offset % ((Bank+1) * 0x4000); + + Address = Bank * 0x10000 + Word; + + return Address; +} + +unsigned char Pointer::GetUpperByte(const unsigned int ScriptPos) const +{ + return (GetAddress(ScriptPos) & 0xFF000000) >> 24; +} + + + +// #WBB(param) - Working + +unsigned char Pointer::GetBankByte(const unsigned int ScriptPos) const +{ + return (GetAddress(ScriptPos) & 0xFF0000) >> 16; +} + + + +// #WHB(param) - Working + +unsigned char Pointer::GetHighByte(const unsigned int ScriptPos) const +{ + return (GetAddress(ScriptPos) & 0xFF00) >> 8; +} + + + +// #WLB(param) - Working + +unsigned char Pointer::GetLowByte(const unsigned int ScriptPos) const +{ + return GetAddress(ScriptPos) & 0xFF; +} + + + +// #W16(param) - Working + +unsigned short Pointer::Get16BitPointer(const unsigned int ScriptPos) const +{ + return GetAddress(ScriptPos) & 0xFFFF; +} + + + +// #W24(param) - Working + +unsigned int Pointer::Get24BitPointer(const unsigned int ScriptPos) const +{ + return GetAddress(ScriptPos) & 0xFFFFFF; +} + + + +// #W32 - Working + +unsigned int Pointer::Get32BitPointer(const unsigned int ScriptPos) const +{ + return GetAddress(ScriptPos); +} + +// #WHW (Write High Word) - Working + +unsigned int Pointer::GetHighWord(const unsigned int ScriptPos) const +{ + return ((GetAddress(ScriptPos) & 0xFFFF0000) >> 16); +} + +//--------------------------- Custom Pointer ---------------------------------- +// \\ +// \\ + +bool CustomPointer::Init(__int64 Offsetting, unsigned int Size, unsigned int HeaderSize) +{ + this->Offsetting = Offsetting; + SetHeaderSize(HeaderSize); + switch(Size) + { + case 8: case 16: case 24: case 32: + this->Size = Size; + break; + default: + return false; + } + return true; +} + +unsigned int CustomPointer::GetSize() +{ + return Size; +} + +unsigned int CustomPointer::GetAddress(const unsigned int Address) const +{ + unsigned int Val; + Val = (unsigned int) ((__int64)GetMachineAddress(Address) - Offsetting); + switch(Size) + { + case 8: + return Val & 0xFF; + case 16: + return Val & 0xFFFF; + case 24: + return Val & 0xFFFFFF; + case 32: + return Val; + default: + Logger.BugReport(__LINE__, __FILE__, "Bad size in CustomPointer::GetAddress"); + return -1; + } +} + +//--------------------------- Embedded Pointer -------------------------------- +// \\ +// \\ + +EmbeddedPointer::EmbeddedPointer() +{ + TextPos = -1; + PointerPos = -1; + Size = 0; +} + +EmbeddedPointer::~EmbeddedPointer() +{ +} + +bool EmbeddedPointer::SetPointerPosition(const unsigned int Address) +{ + PointerPos = Address; + if(TextPos != -1) + return true; // Return true if pointer is ready to write + else + return false; +} + +bool EmbeddedPointer::SetTextPosition(const unsigned int Address) +{ + TextPos = Address; + if(PointerPos != -1) + return true; + else + return false; +} + +void EmbeddedPointer::SetSize(const unsigned int size) +{ + Size = size; +} + +unsigned int EmbeddedPointer::GetSize() const +{ + return Size; +} + +void EmbeddedPointer::SetOffsetting(const __int64 Offsetting) +{ + this->Offsetting = Offsetting; +} + +unsigned int EmbeddedPointer::GetPointer() const +{ + unsigned int Val = (unsigned int)(GetAddress(TextPos) - Offsetting); + switch(Size) + { + case 8: + return Val & 0xFF; + case 16: + return Val & 0xFFFF; + case 24: + return Val & 0xFFFFFF; + case 32: + return Val & 0xFFFFFFFF; + default: + Logger.BugReport(__LINE__, __FILE__, + "Bad embedded pointer size %d in EmbeddedPointer::GetTextPosition", Size); + return 0; + } +} + +unsigned int EmbeddedPointer::GetTextPosition() const +{ + return TextPos; +} + +unsigned int EmbeddedPointer::GetPointerPosition() const +{ + return PointerPos; +} + +//------------------------ Embedded Pointer Handler --------------------------- +// \\ +// \\ + +EmbeddedPointerHandler::EmbeddedPointerHandler() +{ + PtrSize = 0; + HdrSize = 0; + Offsetting = 0; +} + +EmbeddedPointerHandler::~EmbeddedPointerHandler() +{ +} + +void EmbeddedPointerHandler::SetListSize(int Size) +{ + PtrList.reserve(Size); + if((int)PtrList.size() < Size) + { + int j = Size - (int)PtrList.size(); + + EmbeddedPointer elem; + elem.SetAddressType(AddressType); + elem.SetSize(PtrSize); + elem.SetHeaderSize (HdrSize); + elem.SetOffsetting(Offsetting); + elem.SetPointerPosition(-1); + elem.SetTextPosition(-1); + + for(int i = 0; i < j; i++) + PtrList.push_back(elem); + } +} + +int EmbeddedPointerHandler::GetListSize() +{ + return (int)PtrList.size(); +} + +bool EmbeddedPointerHandler::GetPointerState(const unsigned int PointerNum, unsigned int& TextPos, + unsigned int& PointerPos) +{ + if(PtrList.size() < PointerNum) + { + TextPos = -1; + PointerPos = -1; + return false; + } + + TextPos = GetTextPosition(PointerNum); + PointerPos = GetPointerPosition(PointerNum); + + if(TextPos == -1 || PointerPos == -1) + return false; + else + return true; +} + +bool EmbeddedPointerHandler::SetType(std::string& AddressString, const __int64 Offsetting, const unsigned int PointerSize) +{ + this->Offsetting = Offsetting; + switch(PointerSize) + { + case 8: case 16: case 24: case 32: + PtrSize = PointerSize; + break; + default: // Bad size + return false; + } + return SetAddressType(AddressString); +} + +void EmbeddedPointerHandler::SetHeaderSize(const unsigned int HeaderSize) +{ + HdrSize = HeaderSize; +} + +unsigned int EmbeddedPointerHandler::GetDefaultSize() +{ + return PtrSize; +} + +unsigned int EmbeddedPointerHandler::GetSize(const unsigned int PointerNum) +{ + unsigned int i = PointerNum; + if(PtrList.size() < i) + return -1; + + return PtrList[i].GetSize(); +} + +bool EmbeddedPointerHandler::SetTextPosition(const unsigned int PointerNum, const unsigned int TextPos) +{ + unsigned int i = PointerNum; + if(PtrList.size() < i) + return false; + + // If still with default allocation + if(PtrList[i].GetTextPosition() == -1 && PtrList[i].GetPointerPosition() == -1) + { + PtrList[i].SetAddressType(AddressType); + PtrList[i].SetSize(PtrSize); + PtrList[i].SetHeaderSize(HdrSize); + PtrList[i].SetOffsetting(Offsetting); + } + + return PtrList[i].SetTextPosition(TextPos); +} + +bool EmbeddedPointerHandler::SetPointerPosition(const unsigned int PointerNum, const unsigned int PointerPos) +{ + unsigned int i = PointerNum; + if(PtrList.size() < i) + return false; + + // If still with default allocation + if(PtrList[i].GetTextPosition() == -1 && PtrList[i].GetPointerPosition() == -1) + { + PtrList[i].SetAddressType(AddressType); + PtrList[i].SetSize(PtrSize); + PtrList[i].SetHeaderSize(HdrSize); + PtrList[i].SetOffsetting(Offsetting); + } + + return PtrList[i].SetPointerPosition(PointerPos); +} + +unsigned int EmbeddedPointerHandler::GetPointerValue(const unsigned int PointerNum) +{ + if(PtrList.size() < PointerNum) + return -1; + + return PtrList[PointerNum].GetPointer(); +} + +unsigned int EmbeddedPointerHandler::GetTextPosition(const unsigned int PointerNum) +{ + if(PtrList.size() < PointerNum) + return -1; + + return PtrList[PointerNum].GetTextPosition(); +} + +unsigned int EmbeddedPointerHandler::GetPointerPosition(const unsigned int PointerNum) +{ + if(PtrList.size() < PointerNum) + return -1; + + return PtrList[PointerNum].GetPointerPosition(); +} + +bool EmbeddedPointerHandler::SetAddressType(std::string& Type) +{ + for(int i = 0; i < AddressTypeCount; i++) + { + if(Type == AddressTypes[i]) + { + AddressType = i; + return true; + } + } + + return false; +} \ No newline at end of file diff --git a/Pointer.h b/Pointer.h new file mode 100644 index 0000000..671c51e --- /dev/null +++ b/Pointer.h @@ -0,0 +1,111 @@ +#pragma once +#include + +// MachineAddresses- The type of addressing the machine uses +static const unsigned int MA_INVALID = 0; +static const unsigned int LINEAR = 1; +static const unsigned int LOROM00 = 2; +static const unsigned int LOROM80 = 3; +static const unsigned int HIROM = 4; +static const unsigned int GB = 5; + +static const unsigned int AddressTypeCount = 6; +static const char* AddressTypes[AddressTypeCount] = { "INVALID", "LINEAR", "LOROM00", "LOROM80", + "HIROM", "GB" }; + +class Pointer +{ +public: + Pointer(); + ~Pointer(); + bool SetAddressType(std::string& AddressString); + bool SetAddressType(unsigned int Type); + void SetHeaderSize(const unsigned int Size); + + // Pointer writing functions + unsigned short Pointer::Get16BitPointer(const unsigned int ScriptPos) const; + unsigned int Pointer::Get24BitPointer(const unsigned int ScriptPos) const; + unsigned int Pointer::Get32BitPointer(const unsigned int ScriptPos) const; + + unsigned char Pointer::GetLowByte(const unsigned int ScriptPos) const; + unsigned char Pointer::GetHighByte(const unsigned int ScriptPos) const; + unsigned char Pointer::GetBankByte(const unsigned int ScriptPos) const; + unsigned char Pointer::GetUpperByte(const unsigned int ScriptPos) const; + unsigned int Pointer::GetHighWord(const unsigned int ScriptPos) const; + +protected: + unsigned int AddressType; + unsigned int HeaderSize; + virtual unsigned int GetAddress(const unsigned int Address) const; + unsigned int GetMachineAddress(unsigned int Address) const; + +private: + // Machine Address translation functions + unsigned int GetLoROMAddress(unsigned int Offset) const; + unsigned int GetHiROMAddress(unsigned int Offset) const; + unsigned int GetGBAddress(unsigned int Offset) const; +}; + +class CustomPointer : public virtual Pointer +{ +public: + bool Init(__int64 Offsetting, unsigned int Size, unsigned int HeaderSize); + unsigned int GetSize(); + unsigned int GetAddress(const unsigned int Address) const; +private: + __int64 Offsetting; + unsigned int Size; +}; + +class EmbeddedPointer : public virtual Pointer +{ +public: + EmbeddedPointer(); + ~EmbeddedPointer(); + + bool SetTextPosition(const unsigned int Address); + bool SetPointerPosition(const unsigned int Address); + void SetSize(const unsigned int size); + void SetOffsetting(const __int64 Offsetting); + + unsigned int GetTextPosition() const; + unsigned int GetPointer() const; + unsigned int GetPointerPosition() const; + unsigned int GetSize() const; +private: + __int64 Offsetting; + unsigned int TextPos; + unsigned int PointerPos; + unsigned int Size; +}; + +typedef std::list::iterator ListEmbPtrIt; + +class EmbeddedPointerHandler +{ +public: + EmbeddedPointerHandler(); + ~EmbeddedPointerHandler(); + + void SetListSize(int Size); + int GetListSize(); + bool GetPointerState(const unsigned int PointerNum, unsigned int& TextPos, unsigned int& PointerPos); + bool SetType(std::string& AddressString, const __int64 Offsetting, const unsigned int PointerSize); + unsigned int GetDefaultSize(); + bool SetTextPosition(const unsigned int PointerNum, const unsigned int TextPos); + bool SetPointerPosition(const unsigned int PointerNum, const unsigned int PointerPos); + void SetHeaderSize(const unsigned int HeaderSize); + bool SetAddressType(std::string& Type); + + unsigned int GetTextPosition(const unsigned int PointerNum); + unsigned int GetPointerPosition(const unsigned int PointerNum); + unsigned int GetPointerValue(const unsigned int PointerNum); + unsigned int GetSize(const unsigned int PointerNum); + +private: + std::vector PtrList; + unsigned int AddressType; + __int64 Offsetting; + unsigned int PtrSize; + unsigned int HdrSize; +}; \ No newline at end of file diff --git a/PointerHandler.cpp b/PointerHandler.cpp new file mode 100644 index 0000000..d955394 --- /dev/null +++ b/PointerHandler.cpp @@ -0,0 +1,364 @@ +#include "stdafx.h" +#include +#include +#include "PointerHandler.h" +#include "Pointer.h" +#include "AtlasLogger.h" +#include "GenericVariable.h" +#include "AtlasCore.h" +#include "AtlasTypes.h" + +using namespace std; + +PointerHandler::PointerHandler(VariableMap* Map) +{ + this->Map = Map; +} + +bool PointerHandler::CreatePointer(std::string& PtrId, std::string& AddressType, + __int64 Offsetting, unsigned int Size, unsigned int HeaderSize) +{ + CustomPointer* Ptr = (CustomPointer*)Map->GetVar(PtrId)->GetData(); + if(Ptr != NULL) // Already initialized + { + Logger.ReportError(CurrentLine, "Identifier %s has already been allocated", PtrId.c_str()); + return false; + } + Ptr = new CustomPointer; + if(!Ptr->Init(Offsetting, Size, HeaderSize)) + { + Logger.ReportError(CurrentLine, "Invalid size parameter for CREATEPTR"); + return false; + } + if(!Ptr->SetAddressType(AddressType)) + { + Logger.ReportError(CurrentLine, "Invalid address type for CREATEPTR"); + return false; + } + + Map->SetVarData(PtrId, Ptr, P_CUSTOMPOINTER); + return true; +} + +unsigned int PointerHandler::GetPtrSize(string& PtrId) +{ + CustomPointer* Ptr = (CustomPointer*)Map->GetVar(PtrId)->GetData(); + if(Ptr == NULL) // Uninitialized + { + Logger.ReportError(CurrentLine, "Identifier %s has not been initialized with CREATEPTR", PtrId.c_str()); + return -1; + } + + return Ptr->GetSize(); +} + +unsigned int PointerHandler::GetPtrAddress(std::string& PtrId, unsigned int ScriptPos, + unsigned int& Size) +{ + CustomPointer* Ptr = (CustomPointer*)Map->GetVar(PtrId)->GetData(); + if(Ptr == NULL) // Uninitialized + { + Logger.ReportError(CurrentLine, "Identifier %s has not been initialized with CREATEPTR", PtrId.c_str()); + return -1; + } + unsigned int Address = Ptr->GetAddress(ScriptPos); + Size = Ptr->GetSize(); + return Address; +} + +bool PointerHandler::CreatePointerList(std::string& ListId, const char* Filename, + std::string& PtrId) +{ + PointerList* List = (PointerList*)Map->GetVar(ListId)->GetData(); + if(List != NULL) // Already initialized + { + Logger.ReportError(CurrentLine, "Identifier %s has already been allocated", ListId.c_str()); + return false; + } + CustomPointer* Ptr = (CustomPointer*)Map->GetVar(PtrId)->GetData(); + if(Ptr == NULL) + { + Logger.ReportError(CurrentLine, "Identifier %s has not been initialized with CREATEPTR", PtrId.c_str()); + return false; + } + + List = new PointerList; + bool Success = List->Create(Filename, *Ptr); + Map->SetVarData(ListId, List, P_POINTERLIST); + return Success; +} + +unsigned int PointerHandler::GetListAddress(std::string& ListId, unsigned int ScriptPos, unsigned int& Size, unsigned int& WritePos) +{ + PointerList* List = (PointerList*)Map->GetVar(ListId)->GetData(); + if(List == NULL) // Not initialized + { + Logger.ReportError(CurrentLine, "Identifier %s has not been initialized with PTRLIST", ListId.c_str()); + return -1; + } + return List->GetAddress(ScriptPos, Size, WritePos); +} + +bool PointerHandler::CreatePointerTable(std::string& TblId, unsigned int Start, + unsigned int Increment, std::string& PtrId) +{ + PointerTable* Tbl = (PointerTable*)Map->GetVar(TblId)->GetData(); + if(Tbl != NULL) // Already allocated + { + Logger.ReportError(CurrentLine, "Identifier %s has already been allocated", TblId.c_str()); + return false; + } + CustomPointer* Ptr = (CustomPointer*)Map->GetVar(PtrId)->GetData(); + if(Ptr == NULL) + { + Logger.ReportError(CurrentLine, "Identifier %s has not been initialized with CREATEPTR", PtrId.c_str()); + return false; + } + Tbl = new PointerTable; + Tbl->Create(Increment, Start, *Ptr); + Map->SetVarData(TblId, Tbl, P_POINTERTABLE); + return true; +} + +bool PointerHandler::CreateEmbPointerTable(string& TblId, unsigned int Start, unsigned int PtrCount, string& PtrId) +{ + EmbPointerTable* Tbl = (EmbPointerTable*)Map->GetVar(TblId)->GetData(); + if(Tbl != NULL) // Already allocated + { + Logger.ReportError(CurrentLine, "Identifier %s has already been allocated", TblId.c_str()); + return false; + } + CustomPointer* Ptr = (CustomPointer*)Map->GetVar(PtrId)->GetData(); + if(Ptr == NULL) + { + Logger.ReportError(CurrentLine, "Identifier %s has not been initialized with CREATEPTR", PtrId.c_str()); + return false; + } + + Tbl = new EmbPointerTable; + Tbl->Create(Start, PtrCount, *Ptr); + Map->SetVarData(TblId, Tbl, P_EMBPOINTERTABLE); + return true; +} + +unsigned int PointerHandler::GetEmbTableAddress(string& TblId, unsigned int ScriptPos, + unsigned int& Size, unsigned int& WritePos) +{ + EmbPointerTable* Tbl = (EmbPointerTable*)Map->GetVar(TblId)->GetData(); + if(Tbl == NULL) // Not initialized + { + Logger.ReportError(CurrentLine, "Identifier %s has not been initialized with EMBPTRTBL", TblId.c_str()); + return -1; + } + return Tbl->GetAddress(ScriptPos, Size, WritePos); +} + +unsigned int PointerHandler::GetEmbTableAddress(string& TblId, unsigned int ScriptPos, unsigned int PtrNum, + unsigned int& Size, unsigned int& WritePos) +{ + EmbPointerTable* Tbl = (EmbPointerTable*)Map->GetVar(TblId)->GetData(); + if(Tbl == NULL) // Not initialized + { + Logger.ReportError(CurrentLine, "Identifier %s has not been initialized with EMBPTRTBL", TblId.c_str()); + return -1; + } + return Tbl->GetAddress(ScriptPos, PtrNum, Size, WritePos); +} + +unsigned int PointerHandler::GetTableAddress(std::string& TblId, unsigned int ScriptPos, + unsigned int& Size, unsigned int& WritePos) +{ + PointerTable* Tbl = (PointerTable*)Map->GetVar(TblId)->GetData(); + if(Tbl == NULL) // Not initialized + { + Logger.ReportError(CurrentLine, "Identifier %s has not been initialized with PTRTBL", TblId.c_str()); + return -1; + } + return Tbl->GetAddress(ScriptPos, Size, WritePos); +} + +unsigned int PointerHandler::GetTableAddress(std::string& TblId, unsigned int ScriptPos, unsigned int PtrNum, + unsigned int& Size, unsigned int& WritePos) +{ + PointerTable* Tbl = (PointerTable*)Map->GetVar(TblId)->GetData(); + if(Tbl == NULL) // Not initialized + { + Logger.ReportError(CurrentLine, "Identifier %s has not been initialized with PTRTBL", TblId.c_str()); + return -1; + } + return Tbl->GetAddress(ScriptPos, PtrNum, Size, WritePos); +} + +PointerList::PointerList() +{ + Location = 0; +} + +PointerList::~PointerList() +{ +} + +bool PointerList::Create(const char* Filename, CustomPointer& CustPointer) +{ + ifstream Input(Filename); + if(!Input.is_open()) + { + // File Error + return false; + } + + string Line; + size_t FirstPos = 0; + bool bRet = true; + unsigned int Res = 0; + + unsigned int CurLine = 1; + while(!Input.eof()) + { + getline(Input, Line); + FirstPos = Line.find_first_not_of(" \t", 0); + + if(FirstPos == string::npos) // Whitespace line + continue; + + if(Line.length() > FirstPos+1) + if(Line[FirstPos] == '/' && Line[FirstPos] == '/') // Comment + continue; + + // Trim trailing whitespace + size_t Last; + for(Last = Line.length() - 1; Last > 0; Last--) + if(Line[Last] != ' ' && Line[Last] != '\t') + break; + if(Last < Line.length()) + Line.erase(Last+1); + + if(Line[FirstPos] == '$') + { + FirstPos++; + if(string::npos == Line.find_first_not_of("0123456789ABCDEF", FirstPos)) + Res = strtoul(Line.substr(FirstPos, Line.length() - FirstPos).c_str(), NULL, 16); + else + { + Logger.ReportError(CurLine, "Error parsing %s in %s", Line.c_str(), Filename); + bRet = false; + } + } + else + { + if(string::npos == Line.find_first_not_of("0123456789", FirstPos)) + Res = strtoul(Line.substr(FirstPos, Line.length() - FirstPos).c_str(), NULL, 10); + else + { + Logger.ReportError(CurLine, "Error parsing %s in %s", Line.c_str(), Filename); + bRet = false; + } + } + + LocationList.push_back(Res); + CurLine++; + } + + Input.close(); + LocationIt = LocationList.begin(); + Location = 0; + Pointer = CustPointer; + return bRet; +} + +unsigned int PointerList::GetAddress(unsigned int TextPosition, unsigned int& Size, unsigned int& WritePos) +{ + if(Location < LocationList.size()) + { + Size = Pointer.GetSize(); + WritePos = *LocationIt; + LocationIt++; + Location++; + return Pointer.GetAddress(TextPosition); + } + else + return -1; +} + + + +PointerTable::PointerTable() +{ + Increment = 0; + CurOffset = 0; +} + +PointerTable::~PointerTable() +{ +} + +bool PointerTable::Create(unsigned int Inc, unsigned int StartOffset, CustomPointer& CustPointer) +{ + Increment = Inc; + CurOffset = StartOffset; + Pointer = CustPointer; + TableStart = StartOffset; + return true; +} + +unsigned int PointerTable::GetAddress(unsigned int TextPosition, unsigned int& Size, unsigned int& WritePos) +{ + Size = Pointer.GetSize(); + WritePos = CurOffset; + CurOffset += Increment; + return Pointer.GetAddress(TextPosition); +} + +unsigned int PointerTable::GetAddress(unsigned int TextPosition, unsigned int PtrNum, + unsigned int& Size, unsigned int& WritePos) +{ + Size = Pointer.GetSize(); + + WritePos = TableStart + (PtrNum * Increment); + CurOffset = WritePos + Increment; + return Pointer.GetAddress(TextPosition); +} + +EmbPointerTable::EmbPointerTable() +{ + TableStart = 0; + CurPointer = 0; + PtrCount = 0; +} + +EmbPointerTable::~EmbPointerTable() +{ +} + +bool EmbPointerTable::Create(unsigned int StartOffset, unsigned int PointerCount, CustomPointer& CustPointer) +{ + TableStart = StartOffset; + CurPointer = 0; + PtrCount = PointerCount; + Pointer = CustPointer; + return true; +} + +unsigned int EmbPointerTable::GetAddress(unsigned int TextPosition, unsigned int &Size, unsigned int &WritePos) +{ + if(CurPointer >= PtrCount) + return -1; // Out of bounds + Size = Pointer.GetSize(); + + WritePos = TableStart + CurPointer*(Size/8); + CurPointer++; + return Pointer.GetAddress(TextPosition); +} + +unsigned int EmbPointerTable::GetAddress(unsigned int TextPosition, unsigned int PtrNum, + unsigned int &Size, unsigned int &WritePos) +{ + if(PtrNum >= PtrCount) + return -1; // Out of bounds + + Size = Pointer.GetSize(); + + WritePos = TableStart + PtrNum * (Size/8); + CurPointer = PtrNum+1; + return Pointer.GetAddress(TextPosition); +} \ No newline at end of file diff --git a/PointerHandler.h b/PointerHandler.h new file mode 100644 index 0000000..82fa6d0 --- /dev/null +++ b/PointerHandler.h @@ -0,0 +1,82 @@ +#pragma once +#include +#include +#include "Pointer.h" +#include "GenericVariable.h" + +using namespace std; + +class PointerHandler +{ +public: + PointerHandler(VariableMap* Map); + bool CreatePointer(string& PtrId, string& AddressType, + __int64 Offsetting, unsigned int Size, unsigned int HeaderSize); + unsigned int GetPtrAddress(string& PtrId, unsigned int ScriptPos, unsigned int& Size); + bool CreatePointerList(string& ListId, const char* Filename, string& PtrId); + bool CreatePointerTable(string& TblId, unsigned int Start, unsigned int Increment, + string& PtrId); + bool CreateEmbPointerTable(string& TblId, unsigned int Start, unsigned int PtrCount, string& PtrId); + unsigned int GetListAddress(string& ListId, unsigned int ScriptPos, + unsigned int& Size, unsigned int& WritePos); + unsigned int GetTableAddress(string& TblId, unsigned int ScriptPos, + unsigned int& Size, unsigned int& WritePos); + unsigned int GetTableAddress(string& TblId, unsigned int ScriptPos, + unsigned int PtrNum, unsigned int& Size, unsigned int& WritePos); + + unsigned int GetEmbTableAddress(string& TblId, unsigned int ScriptPos, unsigned int& Size, unsigned int& WritePos); + unsigned int GetEmbTableAddress(string& TblId, unsigned int ScriptPos, unsigned int PtrNum, + unsigned int& Size, unsigned int& WritePos); + unsigned int GetPtrSize(string& PtrId); +private: + VariableMap* Map; +}; + +class PointerList +{ +public: + PointerList(); + ~PointerList(); + + bool Create(const char* Filename, CustomPointer& CustPointer); + unsigned int GetAddress(unsigned int TextPosition, unsigned int& Size, unsigned int& WritePos); +private: + std::list LocationList; + std::list::iterator LocationIt; + unsigned int Location; + CustomPointer Pointer; +}; + +class PointerTable +{ +public: + PointerTable(); + ~PointerTable(); + bool Create(unsigned int Inc, unsigned int StartOffset, CustomPointer& CustPointer); + unsigned int GetAddress(unsigned int TextPosition, unsigned int& Size, unsigned int& WritePos); + unsigned int GetAddress(unsigned int TextPosition, unsigned int PtrNum, unsigned int& Size, unsigned int& WritePos); + +private: + unsigned int Increment; + unsigned int CurOffset; + unsigned int TableStart; + CustomPointer Pointer; +}; + +class EmbPointerTable +{ +public: + EmbPointerTable(); + ~EmbPointerTable(); + + bool Create(unsigned int StartOffset, unsigned int PointerCount, CustomPointer& CustPointer); + unsigned int GetAddress(unsigned int TextPosition, unsigned int& Size, unsigned int& WritePos); + unsigned int GetAddress(unsigned int TextPosition, unsigned int PtrNum, + unsigned int &Size, unsigned int &WritePos); + +private: + unsigned int TableStart; + unsigned int CurPointer; + unsigned int PtrCount; + CustomPointer Pointer; +}; \ No newline at end of file diff --git a/ReadMe.txt b/ReadMe.txt new file mode 100644 index 0000000..06b5d1b --- /dev/null +++ b/ReadMe.txt @@ -0,0 +1,32 @@ +======================================================================== + CONSOLE APPLICATION : Atlas Project Overview +======================================================================== + +AppWizard has created this Atlas application for you. +This file contains a summary of what you will find in each of the files that +make up your Atlas application. + + +Atlas.vcproj + This is the main project file for VC++ projects generated using an Application Wizard. + It contains information about the version of Visual C++ that generated the file, and + information about the platforms, configurations, and project features selected with the + Application Wizard. + +Atlas.cpp + This is the main application source file. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named Atlas.pch and a precompiled types file named StdAfx.obj. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" comments to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/Table.cpp b/Table.cpp new file mode 100644 index 0000000..830983e --- /dev/null +++ b/Table.cpp @@ -0,0 +1,639 @@ +//----------------------------------------------------------------------------- +// Table - A table library by Klarth, http://rpgd.emulationworld.com/klarth +// email - stevemonaco@hotmail.com +// Open source and free to use +//----------------------------------------------------------------------------- + +#include "stdafx.h" +#include +#include +#include +#include +#include +#include +#include "Table.h" + +using namespace std; + +Table::Table() +{ + TblEntries = 0; + memset(LongestText, 0, 256*4); + LongestText[(int)'<'] = 5; // Length of <$XX> + LongestText[(int)'('] = 5; // Length of ($XX) + LongestHex = 1; + StringCount = 0; + bAddEndToken = true; +} + +Table::~Table() +{ + // Clear Errors + if(!Errors.empty()) + Errors.clear(); + + // Clear the map + if(!LookupHex.empty()) + LookupHex.clear(); +} + + + +//----------------------------------------------------------------------------- +// EncodeStream() - Encodes text in a vector to the string tables +//----------------------------------------------------------------------------- + +unsigned int Table::EncodeStream(string& scriptbuf, unsigned int& BadCharOffset) +{ + TBL_STRING TblString; + TXT_STRING TxtString; + string hexstr; + string subtextstr; + unsigned char i; + unsigned int EncodedSize = 0; + bool bIsEndToken = false; + std::map::iterator mapit; + unsigned int BufOffset = 0; + + hexstr.reserve(LongestHex * 2); + + if(scriptbuf.empty()) + return 0; + + if(!StringTable.empty()) + { + TBL_STRING RestoreStr = StringTable.back(); + if(RestoreStr.EndToken.empty()) // No end string...restore and keep adding + { + StringTable.pop_back(); + TblString.Text = RestoreStr.Text; + TxtString = TxtStringTable.back(); + TxtStringTable.pop_back(); + } + } + + while(BufOffset < scriptbuf.size()) // Translate the whole buffer + { + bIsEndToken = false; + i = LongestText[(unsigned char)scriptbuf[BufOffset]]; // Use LUT + while(i) + { + subtextstr = scriptbuf.substr(BufOffset, i); + mapit = LookupHex.find(subtextstr); + if(mapit == LookupHex.end()) // if the entry isn't found + { + i--; + continue; + } + + hexstr = mapit->second; + TxtString.Text += subtextstr; + + // Search to see if it's an end token, if it is, add to the string table + for(unsigned int j = 0; j < EndTokens.size(); j++) + if(EndTokens[j] == subtextstr) + { + bIsEndToken = true; + if(bAddEndToken) + AddToTable(hexstr, &TblString); + + TxtString.EndToken = subtextstr; + TblString.EndToken = subtextstr; + EncodedSize += (unsigned int)TblString.Text.size(); + TxtStringTable.push_back(TxtString); + StringTable.push_back(TblString); + TxtString.EndToken = ""; + TxtString.Text.clear(); + TblString.EndToken = ""; + TblString.Text.clear(); + break; // Only once + } + + if(!bIsEndToken) + AddToTable(hexstr, &TblString); + + BufOffset += i; + break; // Entry is finished + } + if (i == 0) // no entries found + { + BadCharOffset = BufOffset; + return -1; + } + } + + // Encode any extra data that doesn't have an EndToken + if(!TblString.Text.empty()) + StringTable.push_back(TblString); + if(!TxtString.Text.empty()) + TxtStringTable.push_back(TxtString); + + EncodedSize += (unsigned int)TblString.Text.size(); + + scriptbuf.clear(); + + return EncodedSize; +} + +inline void Table::InitHexTable() +{ + char textbuf[16]; + char hexbuf[16]; + + for(unsigned int i = 0; i < 0x100; i++) + { + sprintf(textbuf, "<$%02X>", i); + sprintf(hexbuf, "%02X", i); + LookupHex.insert(map::value_type(string(textbuf), string(hexbuf))); + // WindHex style hex codes + sprintf(textbuf, "($%02X)", i); + LookupHex.insert(map::value_type(string(textbuf), string(hexbuf))); + } + for(unsigned int i = 0x0A; i < 0x100; i += 0x10) + { + for(unsigned int j = 0; j < 6; j++) + { + sprintf(textbuf, "<$%02x>", i+j); + sprintf(hexbuf, "%02X", i+j); + LookupHex.insert(map::value_type(string(textbuf), string(hexbuf))); + // WindHex style hex codes (shouldn't be necessary for lowercase, though) + sprintf(textbuf, "($%02x)", i); + LookupHex.insert(map::value_type(string(textbuf), string(hexbuf))); + } + } +} + +//----------------------------------------------------------------------------- +// GetHexValue() - Returns a Hex value from a Text string from the table +//----------------------------------------------------------------------------- + +inline string& Table::GetHexValue(string& Textstring) +{ + return (LookupHex.find(Textstring))->second; +} + +//----------------------------------------------------------------------------- +// OpenTable() - Opens, Parses, and Loads a file to memory +//----------------------------------------------------------------------------- + +int Table::OpenTable(const char* TableFilename) +{ + string HexVal; + char testchar; + string TextString; + + LineNumber = 1; + LookupHex.clear(); + InitHexTable(); + + ifstream TblFile(TableFilename); + if(!TblFile.is_open()) // File can't be opened + return TBL_OPEN_ERROR; + + unsigned char utfheader[4]; + // Detect UTF-8 header + if(TblFile.peek() == 0xEF) + { + TblFile.read((char*)utfheader, 3); + if(utfheader[0] != 0xEF || utfheader[1] != 0xBB || utfheader[2] != 0xBF) + TblFile.seekg(ios::beg); // Seek beginning, not a UTF-8 header + } + + // Read the Table File until eof + while(!TblFile.eof()) + { + HexVal.clear(); + TextString.clear(); + // Read the hex number, skip whitespace, skip equal sign + parsews(TblFile); + + TblFile.get(testchar); + if(TblFile.eof()) + break; + TblFile.seekg(-1, ios::cur); + + switch(testchar) + { + case '(': + if(parsebookmark(TblFile)) + break; + else + return TBL_PARSE_ERROR; + case '[': + parsescriptdump(TblFile); + break; + case '{': + parsescriptinsert(TblFile); + break; + case '/': + if(parseendstring(TblFile)) + { + TblEntries++; + break; + } + else + return TBL_PARSE_ERROR; + case '*': + if(parseendline(TblFile)) + { + TblEntries++; + break; + } + else + return TBL_PARSE_ERROR; + case '$': case '!': case '@': // Skip line, linked/dakuten/handakuten entries not supported + while(TblFile.get() != '\n' && !TblFile.eof()); + break; + default: + if(parseentry(TblFile)) + { + break; + TblEntries++; + } + else + return TBL_PARSE_ERROR; + } + + } // End table reading loop + + return TBL_OK; +} + +//----------------------------------------------------------------------------- +// parsebookmark() - Parses a bookmark like (8000h)Text1 +//----------------------------------------------------------------------------- + +inline bool Table::parsebookmark(ifstream& file) +{ + char testch; + string bookname; + string hexaddress; + unsigned int address; + + file.get(testch); // should be '(' + + while(true) + { + file.get(testch); + if((file.eof()) || (testch == 'h') || (testch == 'H') || (testch == '\n')) + break; + hexaddress += testch; + } + + // Convert a hex string to an unsigned long + address = strtoul(hexaddress.c_str(), NULL, 16); + + parsews(file); + file.get(testch); // should be ')' + if(testch != ')') + return false; + + parsews(file); + + // Get the name + while(true) + { + file.get(testch); + if((testch == '\n') || file.eof()) + break; + bookname += testch; + } + + TBL_BOOKMARK bookmark; + bookmark.address = address; + bookmark.description = bookname; + + Bookmarks.push_back(bookmark); + + return true; +} + +//----------------------------------------------------------------------------- +// parseendline() - parses a break line table value: ex, *FE +// You can also define messages like *FE= +//----------------------------------------------------------------------------- + +inline bool Table::parseendline(ifstream& file) +{ + char testch; + string hexstr, textstr; + + file.get(testch); // the * + parsews(file); + + // Get the hex + while(true) + { + file.get(testch); + if((testch == '\n') || file.eof() || (testch == '=')) + break; + hexstr += testch; + } + + if(testch != '=') // normal entry + { + // Add to the map + LookupHex[DefEndString] = hexstr; + } + else + { + // Get what the string is + while(true) + { + file.get(testch); + if((testch == '\n') || file.eof()) + break; + textstr += testch; + } + + // Add custom message to the map + LookupHex[textstr] = hexstr; + } + + return true; +} + +//----------------------------------------------------------------------------- +// parseendstring() - parses a string break table value +// Only ones like /FF= +// and / (gives a blank string value) +//----------------------------------------------------------------------------- + +inline bool Table::parseendstring(ifstream& file) +{ + char testch; + string hexstr, textstr; + + file.get(testch); // the / + parsews(file); + + // Get the first part + while(true) + { + file.get(testch); + if((testch == '\n') || file.eof() || (testch == '=')) + break; + hexstr += testch; + } + + if(testch == '\n' || file.eof()) // Must be a blank value string (/) + { + size_t Pos = hexstr.find_first_of("0123456789ABCDEF"); + if(Pos == 0) + return false; + textstr = hexstr; + hexstr.clear(); + } + else if(testch == '=') // Must be a /FF= type string + { + while(true) + { + file.get(testch); + if((testch == '\n') || file.eof()) + break; + textstr += testch; + } + } + else + return false; + + // Add custom string to the map + LookupHex[textstr] = hexstr; + EndTokens.push_back(textstr); + + return true; +} + + + +//----------------------------------------------------------------------------- +// parseentry() - parses a hex = text line +//----------------------------------------------------------------------------- + +inline bool Table::parseentry(ifstream& file) +{ + char testch; + string Hex, Text; + + // get the hex + while(true) + { + file.get(testch); + if((testch == SPACE) || (testch == '=')) + break; + else + Hex += testch; + } + + // get the equal sign + if(testch != '=') + { + parsews(file); + file.get(testch); + if(testch != '=') + return false; // bad formatting + } + + // get the value + file.get(testch); + while(!file.eof() && testch != '\n') + { + Text += testch; + file.get(testch); + } + + // Hex entries are strings, so divide the length by two to get the bytes + if(Hex.length() & 1) // Not a 8n bit hex number + Hex.insert(0, "0"); + if((Hex.length() >> 1) > LongestHex) + LongestHex = ((unsigned int)Hex.length() / 2); + + // Get the longest text string + if(Text.length() > LongestText[(unsigned char)Text[0]]) + LongestText[(unsigned char)Text[0]] = (int)Text.length(); + + LookupHex.insert(std::map::value_type(Text, Hex)); + + return true; +} + + + +//----------------------------------------------------------------------------- +// parsescriptdump() - Parses a script dump entry, like [8000h-8450h]Block 1 +//----------------------------------------------------------------------------- + +inline bool Table::parsescriptdump(ifstream& file) +{ + char testch; + unsigned int HexAddr1, HexAddr2; + string HexOff1, HexOff2, Description; + TBL_DUMPMARK dumpmark; + + file.get(testch); // the '[' + + // The first hex entry + while(true) + { + file.get(testch); + if((file.eof()) || (testch == '-') || (testch == '\n')) + break; + HexOff1 += testch; + } + + HexAddr1 = strtoul(HexOff1.c_str(), NULL, 16); + parsews(file); + + // The second hex entry + while(true) + { + file.get(testch); + if((file.eof()) || (testch == ']') || (testch == '\n')) + break; + HexOff2 += testch; + } + + HexAddr2 = strtoul(HexOff2.c_str(), NULL, 16); + parsews(file); + + // The name of the scriptdump + while(true) + { + file.get(testch); + if((testch == '\n') || file.eof()) + break; + Description += testch; + } + + if(HexAddr1 <= HexAddr2) + { + dumpmark.StartAddress = HexAddr1; + dumpmark.EndAddress = HexAddr2; + } + else + { + dumpmark.StartAddress = HexAddr2; + dumpmark.EndAddress = HexAddr1; + } + + dumpmark.description = Description; + + Dumpmarks.push_back(dumpmark); + + return 1; +} + + + +//----------------------------------------------------------------------------- +// parsescriptinsert() - Parses script insert bookmarks +// ex - {8000h-TextDump.txt}Block-e 1 +//----------------------------------------------------------------------------- + +inline bool Table::parsescriptinsert(ifstream& file) +{ + char testch; + int HexAddress; + string HexOff, FileName, Description; + TBL_INSMARK insertmark; + + file.get(testch); // { + + // Get the hex offset + while(true) + { + file.get(testch); + if((file.eof()) || (testch == '-') || (testch == '\n')) + break; + HexOff += testch; + } + + HexAddress = strtoul(HexOff.c_str(), NULL, 16); + parsews(file); + + // Get the filename + while(true) + { + file.get(testch); + if((file.eof()) || (testch == ')') || (testch == '\n')) + break; + HexOff += testch; + } + + parsews(file); + + // Get the description + while(true) + { + file.get(testch); + if((testch == '\n') || file.eof()) + break; + Description += testch; + } + + insertmark.address = HexAddress; + insertmark.filename = FileName; + insertmark.description = Description; + + Insertmarks.push_back(insertmark); + + return 1; +} + + + +//----------------------------------------------------------------------------- +// parsews() - Eats all blanks and eoln's until a valid character or eof +//----------------------------------------------------------------------------- + +inline void Table::parsews(ifstream& file) +{ + char testch; + do{ + file.get(testch); + if(testch == '\n') + LineNumber++; + }while(((testch == SPACE) || (testch == '\n')) && (!file.eof())); + + if((!file.eof()) || (testch != '\n')) + file.seekg(-1, ios::cur); +} + + + +//----------------------------------------------------------------------------- +// HexToDec(...) - Converts a hex character to its dec equiv +//----------------------------------------------------------------------------- + +inline unsigned short HexToDec(char HexChar) +{ + switch(HexChar) + { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'a': case 'A': return 10; + case 'b': case 'B': return 11; + case 'c': case 'C': return 12; + case 'd': case 'D': return 13; + case 'e': case 'E': return 14; + case 'f': case 'F': return 15; + } + + // Never gets here + printf("badstr"); + return 15; +} + +inline void Table::AddToTable(string& Hexstring, TBL_STRING* TblStr) +{ + for(unsigned int k = 0; k < Hexstring.length(); k+=2) + TblStr->Text += (HexToDec(Hexstring[k+1]) | (HexToDec(Hexstring[k]) << 4)); +} \ No newline at end of file diff --git a/Table.h b/Table.h new file mode 100644 index 0000000..b3fee4a --- /dev/null +++ b/Table.h @@ -0,0 +1,118 @@ +//----------------------------------------------------------------------------- +// Return Messages +//----------------------------------------------------------------------------- +#pragma once + +#define TBL_OK 0x00 // Success +#define TBL_OPEN_ERROR 0x01 // Cannot open the Table properly +#define TBL_PARSE_ERROR 0x02 // Cannot parse how the Table is typed +#define NO_MATCHING_ENTRY 0x10 // There was an entry that cannot be matched in the table + +// Other +#define SPACE 0x20 + +#include "stdafx.h" +#include +#include +#include +#include + +// Structure for errors +typedef struct TBL_ERROR +{ + unsigned int LineNo; // The line number which the error occurred + std::string ErrorDesc; // A description of what the error was +} TBL_ERROR; + +// Data Structure for a table bookmark +typedef struct TBL_BOOKMARK +{ + unsigned int address; + std::string description; +} TBL_BOOKMARK; + +// Data Structure for a script dump bookmark +typedef struct TBL_DUMPMARK +{ + unsigned int StartAddress; + unsigned int EndAddress; + std::string description; +} TBL_DUMPMARK; + +// Data Structure for a script insertion bookmark +typedef struct TBL_INSMARK +{ + unsigned int address; + std::string filename; + std::string description; +} TBL_INSMARK; + +// Data Structure for a script string +typedef struct TBL_STRING +{ + std::string Text; + std::string EndToken; +} TBL_STRING; + +// Data Structure for an unencoded (text) string +typedef struct TXT_STRING +{ + std::string Text; + std::string EndToken; +} TXT_STRING; + +typedef std::map StrStrMap; +typedef std::list::iterator ListTblStringIt; +typedef std::list::iterator ListTxtStringIt; + +//----------------------------------------------------------------------------- +// Table Interfaces +//----------------------------------------------------------------------------- + +class Table +{ +public: + Table(); + ~Table(); + + int OpenTable(const char* TableFilename); + unsigned int EncodeStream(std::string& scriptbuf, unsigned int& BadCharOffset); + + std::vector Errors; // Errors + std::vector Bookmarks; // Normal bookmarks + std::vector Dumpmarks; // Script dump bookmarks + std::vector Insertmarks; // Insertion bookmarks + std::list StringTable; // (Encoded) String table + std::list TxtStringTable; // Text String Table + std::vector EndTokens; // String end tokens + + std::map LookupHex; // for looking up hex values. (insertion) + + unsigned int StringCount; + bool bAddEndToken; + +private: + inline void InitHexTable(); + + inline bool parsebookmark(std::ifstream& file); + inline bool parseendline(std::ifstream& file); + inline bool parseendstring(std::ifstream& file); + inline bool parseentry(std::ifstream& file); + inline bool parsescriptinsert(std::ifstream& file); + inline bool parsescriptdump(std::ifstream& file); + inline void parsews(std::ifstream& file); + + inline std::string& GetHexValue(std::string& Textstring); + + inline void AddToTable(std::string& Hexstring, TBL_STRING* TblStr); + + std::string DefEndLine; + std::string DefEndString; + unsigned int LineNumber; // The line number that the library is reading + unsigned int TblEntries; // The number of table entries + unsigned int LongestHex; // The longest hex entry, in bytes + + unsigned int LongestText[256]; +}; + +inline unsigned short HexToDec(char HexChar); \ No newline at end of file diff --git a/UpgradeLog.XML b/UpgradeLog.XML new file mode 100644 index 0000000..adecc1b --- /dev/null +++ b/UpgradeLog.XML @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/UpgradeLog2.XML b/UpgradeLog2.XML new file mode 100644 index 0000000..9d85cf5 --- /dev/null +++ b/UpgradeLog2.XML @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/stdafx.cpp b/stdafx.cpp new file mode 100644 index 0000000..0ce6784 --- /dev/null +++ b/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// Atlas.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/stdafx.h b/stdafx.h new file mode 100644 index 0000000..090c6d5 --- /dev/null +++ b/stdafx.h @@ -0,0 +1,25 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#include +#include + +// TODO: reference additional headers your program requires here +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include \ No newline at end of file