diff --git a/SpaceCadetPinball/NatvisFile.natvis b/SpaceCadetPinball/NatvisFile.natvis index cedec29..b8dac18 100644 --- a/SpaceCadetPinball/NatvisFile.natvis +++ b/SpaceCadetPinball/NatvisFile.natvis @@ -23,4 +23,28 @@ + + + {{ NumberOfGroups={NumberOfGroups} }} + + NumberOfGroups + Description + + NumberOfGroups + GroupData + + + + + {{ EntryCount={EntryCount} }} + + EntryCount + + EntryCount + Entries + + + + + \ No newline at end of file diff --git a/SpaceCadetPinball/SpaceCadetPinball.cpp b/SpaceCadetPinball/SpaceCadetPinball.cpp index eec39fd..2dcb374 100644 --- a/SpaceCadetPinball/SpaceCadetPinball.cpp +++ b/SpaceCadetPinball/SpaceCadetPinball.cpp @@ -2,6 +2,7 @@ // #include "pch.h" + #include #include "objlist_class.h" #include "partman.h" @@ -23,6 +24,19 @@ int main() char dataFileName[300]; partman::make_path_name(dataFileName, "PINBALL.DAT"); auto datFile = partman::load_records(dataFileName); + assert(datFile); + + assert(partman::field_size_nth(datFile, 0, String, 0) == 43); + assert(partman::field_size_nth(datFile, 2, Palette, 0) == 1024); + assert(partman::field_size_nth(datFile, 101, FloatArray, 4) == 32); + + assert(strcmp(partman::field(datFile, 0, String), "3D-Pinball: Copyright 1994, Cinematronics") == 0); + assert(strcmp(partman::field(datFile, 540, GroupName), "table_objects") == 0); + + assert(partman::record_labeled(datFile, "background") == 2); + assert(partman::record_labeled(datFile, "a_bump1") == 372); + + assert(memcmp(partman::field_labeled(datFile, "table_size", ShortArray), new short[2]{ 600, 416 }, 2 * 2) == 0); //DatParser::Parse(dataFileName); } diff --git a/SpaceCadetPinball/partman.cpp b/SpaceCadetPinball/partman.cpp index f9c3ae4..6200bd2 100644 --- a/SpaceCadetPinball/partman.cpp +++ b/SpaceCadetPinball/partman.cpp @@ -1,80 +1,324 @@ #include "pch.h" #include "partman.h" -short partman::_field_size[] = { 2, 0x0FFFF, 2, 0x0FFFF, 0x0FFFF, 0x0FFFF, 0x0FFFF, 0x0FFFF,0x0FFFF, 0x0FFFF, 0x0FFFF, 0x0FFFF, 0x0FFFF, 0 }; +short partman::_field_size[] = { + 2, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0 +}; datFileStruct* partman::load_records(LPCSTR lpFileName) { _OFSTRUCT ReOpenBuff{}; - datFileHeader Buffer; + datFileHeader Buffer{}; + dat8BitBmpHeader bmpHeader{}; datFileStruct* datFile; - HFILE fileHandle, hFile; - int lenOfStr, groupIndex; - unsigned short unknown; - char* descriptionBuf, * unknownBuf, * unknownBuf2; - char** groupDataBuf; + int groupIndex, groupDataSize; + datGroupData** groupDataBuf; - fileHandle = OpenFile(lpFileName, &ReOpenBuff, 0); - hFile = fileHandle; + const HFILE fileHandle = OpenFile(lpFileName, &ReOpenBuff, 0); if (fileHandle == -1) - return 0; + return nullptr; _lread(fileHandle, &Buffer, 183u); if (lstrcmpA("PARTOUT(4.0)RESOURCE", Buffer.FileSignature)) { _lclose(fileHandle); - return 0; + return nullptr; } - datFile = (datFileStruct*)memoryallocate(10); + datFile = (datFileStruct*)memoryallocate(sizeof(datFileStruct)); if (!datFile) { _lclose(fileHandle); - return 0; + return nullptr; } if (lstrlenA(Buffer.Description) <= 0) { - datFile->Description = 0; + datFile->Description = nullptr; } else { - lenOfStr = lstrlenA(Buffer.Description); - descriptionBuf = (char*)memoryallocate(lenOfStr + 1); + int lenOfStr = lstrlenA(Buffer.Description); + auto descriptionBuf = (char*)memoryallocate(lenOfStr + 1); datFile->Description = descriptionBuf; if (!descriptionBuf) { _lclose(fileHandle); - LABEL_10: memoryfree(datFile); - return 0; + return nullptr; } lstrcpyA(descriptionBuf, Buffer.Description); } - unknown = Buffer.Unknown; + if (Buffer.Unknown) { - unknownBuf = (char*)memoryallocate(Buffer.Unknown); - unknownBuf2 = unknownBuf; + auto unknownBuf = (char*)memoryallocate(Buffer.Unknown); if (!unknownBuf) { - _lclose(hFile); - goto LABEL_19; + _lclose(fileHandle); + if (datFile->Description) + memoryfree(datFile->Description); + memoryfree(datFile); + return nullptr; } - _lread(hFile, (void*)unknownBuf, unknown); - memoryfree(unknownBuf2); + _lread(fileHandle, static_cast(unknownBuf), Buffer.Unknown); + memoryfree(unknownBuf); } - groupDataBuf = (char**)memoryallocate(4 * Buffer.NumberOfGroups); + + groupDataBuf = (datGroupData**)memoryallocate(sizeof(void*) * Buffer.NumberOfGroups); datFile->GroupData = groupDataBuf; if (!groupDataBuf) { - LABEL_19: if (datFile->Description) memoryfree(datFile->Description); - goto LABEL_10; + memoryfree(datFile); + return nullptr; } + groupIndex = 0; + if (Buffer.NumberOfGroups) + { + do + { + char entryCount = _lread_char(fileHandle); + if (entryCount <= 0) + groupDataSize = 0; + else + groupDataSize = entryCount - 1; + datFile->GroupData[groupIndex] = (datGroupData*)memoryallocate( + sizeof(datEntryData) * groupDataSize + sizeof(datGroupData)); + datGroupData* groupData = datFile->GroupData[groupIndex]; + if (!groupData) + break; + int entryIndex = 0; + groupData->EntryCount = entryCount; + if (entryCount > 0) + { + datEntryData* entryData = groupData->Entries; + do + { + auto entryType = static_cast(_lread_char(fileHandle)); + entryData->EntryType = entryType; + int fieldSize = _field_size[entryType]; + if (fieldSize < 0) + { + fieldSize = _lread_long(fileHandle); + } + if (entryType == Bitmap8bit) + { + _hread(fileHandle, &bmpHeader, 14); + char* bmpBuffer = (char*)memoryallocate(0x25u); + entryData->Buffer = bmpBuffer; + if (!bmpBuffer) + goto LABEL_41; + /*if (bmpHeader.Unknown2 & 2 ? gdrv_create_bitmap((int)bmpBuffer, bmpHeader.Width, bmpHeader.Height) : gdrv_create_raw_bitmap((int)bmpBuffer, bmpHeader.Width, bmpHeader.Height, bmpHeader.Unknown2 & 1)) + goto LABEL_41;*/ + //_hread(fileHandle, *(LPVOID*)(entryData->Buffer + 8), bmpHeader.Size); + char* tempBuff = (char*)memoryallocate(bmpHeader.Size); + _hread(fileHandle, tempBuff, bmpHeader.Size); + memoryfree(tempBuff); + *((int*)entryData->Buffer + 29) = bmpHeader.XPosition; + *((int*)entryData->Buffer + 33) = bmpHeader.YPosition; + } + else + { + char* entryBuffer = (char*)memoryallocate(fieldSize); + entryData->Buffer = entryBuffer; + if (!entryBuffer) + goto LABEL_41; + _hread(fileHandle, entryBuffer, fieldSize); + } + + ++entryIndex; + entryData->FieldSize = fieldSize; + datFile->NumberOfGroups = groupIndex + 1; + ++entryData; + } + while (entryIndex < entryCount); + } + ++groupIndex; + } + while (groupIndex < Buffer.NumberOfGroups); + } + +LABEL_41: + _lclose(fileHandle); + if (datFile->NumberOfGroups == Buffer.NumberOfGroups) + return datFile; + unload_records(datFile); + return nullptr; +} - return datFile; +void partman::unload_records(datFileStruct* datFile) +{ + for (int groupIndex = 0; groupIndex < datFile->NumberOfGroups; ++groupIndex) + { + datGroupData* group = datFile->GroupData[groupIndex]; + if (group) + { + int entryIndex = 0; + if (group->EntryCount > 0) + { + datEntryData* entry = group->Entries; + do + { + if (entry->Buffer) + { + //if (HIWORD(entry->EntryType) == 1) + //gdrv_destroy_bitmap(entry->Buffer); + memoryfree(entry->Buffer); + } + ++entryIndex; + ++entry; + } + while (entryIndex < group->EntryCount); + } + memoryfree(group); + } + } + if (datFile->Description) + memoryfree(datFile->Description); + memoryfree(datFile->GroupData); + memoryfree(datFile); +} + +char* partman::field(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType) +{ + datGroupData* groupData = datFile->GroupData[groupIndex]; + int entryCount = groupData->EntryCount; + int entryIndex = 0; + if (entryCount <= 0) + return nullptr; + datEntryData* entry = groupData->Entries; + while (true) + { + int entryType = entry->EntryType; + if (entryType == targetEntryType) + break; + if (entryType > targetEntryType) + return nullptr; + ++entryIndex; + ++entry; + if (entryIndex < entryCount) + continue; + return nullptr; + } + return entry->Buffer; +} + + +char* partman::field_nth(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType, int skipFirstN) +{ + datGroupData* groupData = datFile->GroupData[groupIndex]; + int entryCount = groupData->EntryCount, skipCount = 0, entryIndex = 0; + if (0 < entryCount) + { + datEntryData* entry = groupData->Entries; + do + { + int entryType = entry->EntryType; + if (entryType == targetEntryType) + { + if (skipCount == skipFirstN) + { + return entry->Buffer; + } + skipCount++; + } + else + { + if (targetEntryType < entryType) + { + return nullptr; + } + } + entryIndex++; + entry++; + } + while (entryIndex < entryCount); + } + return nullptr; +} + +int partman::field_size_nth(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType, int skipFirstN) +{ + datGroupData* groupData = datFile->GroupData[groupIndex]; + int entryCount = groupData->EntryCount, skipCount = 0, entryIndex = 0; + if (0 < entryCount) + { + datEntryData* entry = groupData->Entries; + do + { + int entryType = entry->EntryType; + if (entryType == targetEntryType) + { + if (skipCount == skipFirstN) + { + return entry->FieldSize; + } + skipCount++; + } + else + { + if (targetEntryType < entryType) + { + return 0; + } + } + entryIndex++; + entry++; + } + while (entryIndex < entryCount); + } + return 0; +} + +int partman::field_size(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType) +{ + return field_size_nth(datFile, groupIndex, targetEntryType, 0); +} + +int partman::record_labeled(datFileStruct* datFile, LPCSTR targetGroupName) +{ + int trgGroupNameLen = lstrlenA(targetGroupName); + int groupIndex = datFile->NumberOfGroups; + while (true) + { + if (--groupIndex < 0) + return -1; + char* groupName = field(datFile, groupIndex, GroupName); + if (groupName) + { + int index = 0; + bool found = trgGroupNameLen == 0; + if (trgGroupNameLen > 0) + { + LPCSTR targetNamePtr = targetGroupName; + do + { + if (*targetNamePtr != targetNamePtr[groupName - targetGroupName]) + break; + ++index; + ++targetNamePtr; + } + while (index < trgGroupNameLen); + found = index == trgGroupNameLen; + } + if (found && !targetGroupName[index] && !groupName[index]) + break; + } + } + return groupIndex; +} + +char* partman::field_labeled(datFileStruct* datFile, LPCSTR lpString, datFieldTypes fieldType) +{ + char* result; + int groupIndex = record_labeled(datFile, lpString); + if (groupIndex < 0) + result = nullptr; + else + result = field(datFile, groupIndex, fieldType); + return result; } @@ -99,4 +343,18 @@ int partman::make_path_name(LPSTR lpFilename, LPCSTR lpString2, int nSize) } lstrcatA(lpFilename, "?"); return 1; -} \ No newline at end of file +} + +char partman::_lread_char(HFILE hFile) +{ + char Buffer = 0; + _lread(hFile, &Buffer, 1u); + return Buffer; +} + +int partman::_lread_long(HFILE hFile) +{ + int Buffer = 0; + _lread(hFile, &Buffer, 4u); + return Buffer; +} diff --git a/SpaceCadetPinball/partman.h b/SpaceCadetPinball/partman.h index 01a5189..2b1decf 100644 --- a/SpaceCadetPinball/partman.h +++ b/SpaceCadetPinball/partman.h @@ -1,8 +1,33 @@ #pragma once +enum datFieldTypes : __int16 +{ + ShortValue = 0, + //, does not have the 32bits size value, but a 16bits value(see above). + Bitmap8bit = 1, + // 8 bpp bitmap + Unknown2 = 2, + GroupName = 3, + // Group name + Unknown4 = 4, + Palette = 5, + // Palette(1 color is 1 DWORD, only present 1 time in PINBALL.DAT ,with a data size of 1024 bytes for 256 colors.Some colors are 0 ,because their indexes are reserved by Windows.) + Unknown6 = 6, + Unknown7 = 7, + Unknown8 = 8, + String = 9, + // String(content) + ShortArray = 10, + // Array of 16bits integer values + FloatArray = 11, + // Array of 32bits floating point values(collision box, ...) + Bitmap16bit = 12, + // 16 bpp bitmap(Heightmap ? ) +}; + #pragma pack(push) #pragma pack(1) -struct datFileHeader +struct datFileHeader { char FileSignature[21]; char AppName[50]; @@ -15,44 +40,60 @@ struct datFileHeader #pragma pack(pop) static_assert(sizeof(datFileHeader) == 183, "Wrong size of datFileHeader"); +struct datEntryData +{ + datFieldTypes EntryType; + int FieldSize; + char* Buffer; +}; + +struct datGroupData +{ + __int16 EntryCount; + datEntryData Entries[1]; +}; + struct datFileStruct { unsigned short NumberOfGroups; char* Description; - char** GroupData; + datGroupData** GroupData; }; - - -enum datFieldTypes +#pragma pack(push) +#pragma pack(1) +struct dat8BitBmpHeader { - ShortValue = 0,//, does not have the 32bits size value, but a 16bits value(see above). - Bitmap8bit = 1,// 8 bpp bitmap - Unknown2 = 2, - GroupName = 3,// Group name - Unknown4 = 4, - Palette = 5,// Palette(1 color is 1 DWORD, only present 1 time in PINBALL.DAT ,with a data size of 1024 bytes for 256 colors.Some colors are 0 ,because their indexes are reserved by Windows.) - Unknown6 = 6, - Unknown7 = 7, - Unknown8 = 8, - String = 9,// String(content) - ShortArray = 10,// Array of 16bits integer values - FloatArray = 11,// Array of 32bits floating point values(collision box, ...) - Bitmap16bit = 12,// 16 bpp bitmap(Heightmap ? ) + char Unknown1; + __int16 Width; + __int16 Height; + __int16 XPosition; + __int16 YPosition; + int Size; + char Unknown2; }; +#pragma pack(pop) +static_assert(sizeof(dat8BitBmpHeader) == 14, "Wrong size of dat8BitBmpHeader"); + + //typedef const char* LPCSTR; class partman { public: static datFileStruct* load_records(LPCSTR lpFileName); + static void unload_records(datFileStruct* datFile); + static char* field_nth(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType, int skipFirstN); + static char* field(datFileStruct* datFile, int groupIndex, datFieldTypes entryType); + static int field_size_nth(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType, int skipFirstN); + static int field_size(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType); + static int record_labeled(datFileStruct* datFile, LPCSTR targetGroupName); + static char* field_labeled(datFileStruct* datFile, LPCSTR lpString, datFieldTypes fieldType); static int make_path_name(LPSTR lpFilename, LPCSTR lpString2, int nSize = 0x12Cu); - + private: static short _field_size[]; + static char _lread_char(HFILE hFile); + static int _lread_long(HFILE hFile); }; - - - - diff --git a/SpaceCadetPinball/pch.h b/SpaceCadetPinball/pch.h index baa7afc..40ca0eb 100644 --- a/SpaceCadetPinball/pch.h +++ b/SpaceCadetPinball/pch.h @@ -11,8 +11,8 @@ // TODO: add headers that you want to pre-compile here #include - #include +#include #define memoryallocate(x) malloc(x); #define memoryfree(x) free(x);