Partman v1.

DAT file format doc.
This commit is contained in:
oz 2020-10-18 18:08:41 +03:00
parent 2d96ba2dd0
commit 375db278c4
11 changed files with 475 additions and 5 deletions

123
Doc/.dat file format.txt Normal file
View file

@ -0,0 +1,123 @@
+-----------------------------------------------------+
| 3D Pinball for Windows ("PARTOUT") .DAT file format |
| AdrienTD |
+-----------------------------------------------------+
//-- Header --//
+0x00: File signature BYTE*21
+0x15: App name BYTE*50
+0x47: Description BYTE*100
+0xAB: File size DWORD
+0xAF: Number of files/groups WORD
+0xB1: Size of body DWORD
+0xB5: Unknown (0) WORD
In 3D Pinball, the file signature is "PARTOUT(4.0)RESOURCE". The rest is
filled with 0.
//-- Body --//
The body is constitued of groups. Every group begins with a byte that tells
how many entries are in the group.
Every entry begins with a byte that specifies the type of the entry. A DWORD that
tells the size of the coming data follows the byte. Then there's some data for the
entry. However, if the type is 0, the type byte is followed by a short value,
and that's all.
Existing types:
Type Meaning/comments
---------------------------------------------------
0 ?, does not have the 32bits size value, but a 16bits value (see above).
1 8 bpp bitmap
3 Group name
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.)
9 String (content)
10 Array of 16bits integer values
11 Array of 32bits floating point values (collision box, ...)
12 16 bpp bitmap (Heightmap?)
//-- 8bpp bitmap data header --//
+0: Unknown (0) BYTE
+1: Width WORD
+3: Height WORD
+5: X position WORD
+7 Y position WORD
+9: Size of bitmap DWORD
+13: Unknown (1) BYTE
+14: Bitmap data BYTE*(DWORD@+9)
//-- 16bpp bitmap data header --//
+0: Width WORD
+2: Height WORD
+4: Pitch/2 WORD
+6: Unknown (0) DWORD
+10: Unknown (0) WORD
+12: Unknown (80) WORD
+14: Bitmap data BYTE*(DWORD@+9)
//-- Pinball 3D remarkable groups --//
-- table_size
Entry type 10 contains 2 16-bit integers: first is width, second is height.
-- table_objects
In entry type 10, the first integer is unknown, but then comes a series of
16-bits integer pairs. Every pair represents an object of the table. The
first integer is the type of object, and the second is the number of
a group/resource in this data file.
Types of object (3D Pinball Space Cadet for Windows):
1000: ?
1001: Plunger
1002: Light (lite###)
1003: Left flipper
1004: Right flipper
1005: Bumper
1006: Yellow target
1007: Drain (no bmp)
1010: ? (no bmp)
1011: Bloc (dot between the flippers)
1012: kout (no bmp) (?)
1013: Gate
1014: Kicker
1015: Roll
1016: One way (no bmp) (?)
1017: Sink (no bmp) (?)
1018: Flag
1019: Red target
1020: Roll (the green circle that makes a weird sound when rolling on it)
1021: Ramp (no bmp)
1022: Ramp hole (no bmp)
1023: Demo (no bmp)
1024: Trip (no bmp)
1026: Lights (no bmp, list?)
1028: Bumpers list (one for attack, one for launch)
1029: kout (no bmp) (?, similar to 1012?)
1030: Fuel bargraph (list?)
1031: Sound
1033: Text box (score, ball counter, player number)
//-- Information --//
There's an article of the format at http://rewiki.regengedanken.de/.
I haven't read it completely, but some informations helped me a bit.
Another thing: There's nearly nothing about hacking the game on the web (even
though the Space Cadet game bundled with Windows is very popular).
What I've only seen when doing a (Google) web search is the 'hidden test'
cheat code. [as of 2017 or even less]
//-- Contact --//
Any questions? Contact me at [see my GitHub profile @AdrienTD for contacts] .
AdrienTD :)

View file

@ -0,0 +1,147 @@
#include "pch.h"
#include "DatParser.h"
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
FILE* ff; unsigned char* fdat; int fsiz;
char tbuf[256];
int ngrp;
void err(int n)
{
printf("Error %i\n", n);
exit(n);
}
void cerr(int c, int n)
{
if (c) err(n);
}
void safeprint(char* s, int n)
{
int i;
for (i = 0; i < n; i++)
{
if (!s[i]) break;
fputc(s[i], stdout);
}
}
void printhexbytestr(uchar* s, int n)
{
int i;
for (i = 0; i < n; i++)
printf("%02X", s[i]);
}
void printshortstr(short* s, int n)
{
int i;
for (i = 0; i < n; i++)
printf(" %i", s[i]);
}
void printfloatstr(float* s, int n)
{
int i;
for (i = 0; i < n; i++)
printf(" %f", s[i]);
}
int main2(int argc, const char* argv[])
{
int g, en, es, n, et; unsigned char* p;
printf("pbwdlist - 3D Pinball for Windows DAT file listing program\nby AdrienTD\n\n");
if (argc < 2) { printf("Usage: pbwdlist FILE.DAT\n"); return 1; }
ff = fopen(argv[1], "rb");
cerr(!ff, -1);
printf("File: %s\n\n", argv[1]);
fseek(ff, 0, SEEK_END);
fsiz = ftell(ff);
fdat = (unsigned char*)malloc(fsiz);
cerr(!fdat, -2);
fseek(ff, 0, SEEK_SET);
fread(fdat, fsiz, 1, ff);
fclose(ff);
printf("-- Header --");
printf("\nFile signature:\t"); safeprint((char*)fdat, 21);
printf("\nApp name:\t"); safeprint((char*)fdat + 0x15, 50);
printf("\nDescription:\t"); safeprint((char*)fdat + 0x47, 100);
printf("\nFile size:\t%i", *((int*)(fdat + 0xAB)));
printf("\nNum. groups:\t%i", ngrp = *((short*)(fdat + 0xAF)));
printf("\nSize of body:\t%i", *((int*)(fdat + 0xB1)));
printf("\nUnknown value:\t%i", *((short*)(fdat + 0xB5)));
printf("\n\n-- Body --");
p = fdat + 0xB7;
for (g = 0; g < ngrp; g++)
{
n = *(p++);
printf("\nGroup %i:\tnum entries: %i, location: 0x%X\n", g, n, p - fdat - 1);
for (en = 0; en < n; en++)
{
et = *(p++);
if (et)
{
es = *((int*)p); p += 4;
printf("\t\t- type: %i, size: %i\n", et, es);
switch (et)
{
case 1: // Bitmap
printf("\t\t Bitmap, width: %i, height: %i\n", *(ushort*)(p + 1), *(ushort*)(p + 3));
break;
case 3: // Group name
printf("\t\t Group name: ");
safeprint((char*)p, es);
printf("\n"); break;
case 5: // Palette
printf("\t\t Palette\n"); break;
case 9: // String
printf("\t\t String: ");
safeprint((char*)p, es);
printf("\n"); break;
case 10:
//printf("\t\t Content: ");
//printhexbytestr(p, es);
printf("\t\t Shorts:");
printshortstr((short*)p, es / 2);
printf("\n"); break;
case 11:
printf("\t\t Floats:");
printfloatstr((float*)p, es / 4);
printf("\n"); break;
case 12:
printf("\t\t Special bitmap\n"); break;
default:
printf("\t\t Unknown!\n"); break;
}
p += es;
}
else
{
es = *((short*)p); p += 2;
printf("\t\t- type: %i, value: %i\n", et, es);
}
}
}
free(fdat);
}
void DatParser::Parse(const char* file)
{
main2(2, new const char* [2] {0, file});
}

View file

@ -0,0 +1,7 @@
#pragma once
class DatParser
{
public:
static void Parse(const char * file);
};

View file

@ -4,17 +4,27 @@
#include "pch.h"
#include <iostream>
#include "objlist_class.h"
#include "partman.h"
#include "DatParser.h"
int main()
{
std::cout << "Hello World!\n";
std::cout << "Hello World!\n";
objlist_class d = objlist_class(2, 4);
for(int i=0;i<100;i++)
objlist_class d = objlist_class(2, 4);
for (int i = 0; i < 100; i++)
{
d.Add((void*)i);
}
d.Delete(3);
auto xx = sizeof(datFileHeader);
char dataFileName[300];
partman::make_path_name(dataFileName, "PINBALL.DAT");
auto datFile = partman::load_records(dataFileName);
//DatParser::Parse(dataFileName);
}
// Run program: Ctrl + F5 or Debug > Start Without Debugging menu

View file

@ -91,6 +91,7 @@
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -151,11 +152,15 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="DatParser.h" />
<ClInclude Include="objlist_class.h" />
<ClInclude Include="partman.h" />
<ClInclude Include="pch.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="DatParser.cpp" />
<ClCompile Include="objlist_class.cpp" />
<ClCompile Include="partman.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>

View file

@ -21,6 +21,12 @@
<ClInclude Include="objlist_class.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="partman.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DatParser.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
@ -32,6 +38,12 @@
<ClCompile Include="objlist_class.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="partman.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DatParser.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="NatvisFile.natvis" />

View file

@ -1,4 +1,4 @@
#include "pch.h""
#include "pch.h"
#include "objlist_class.h"
#include <cstdlib>
// v1 from Ida

View file

@ -4,7 +4,7 @@ struct __declspec(align(4)) objlist_struct1
{
int Size;
int Count;
int Array[];
int Array[1];
};

View file

@ -0,0 +1,102 @@
#include "pch.h"
#include "partman.h"
short partman::_field_size[] = { 2, 0x0FFFF, 2, 0x0FFFF, 0x0FFFF, 0x0FFFF, 0x0FFFF, 0x0FFFF,0x0FFFF, 0x0FFFF, 0x0FFFF, 0x0FFFF, 0x0FFFF, 0 };
datFileStruct* partman::load_records(LPCSTR lpFileName)
{
_OFSTRUCT ReOpenBuff{};
datFileHeader Buffer;
datFileStruct* datFile;
HFILE fileHandle, hFile;
int lenOfStr, groupIndex;
unsigned short unknown;
char* descriptionBuf, * unknownBuf, * unknownBuf2;
char** groupDataBuf;
fileHandle = OpenFile(lpFileName, &ReOpenBuff, 0);
hFile = fileHandle;
if (fileHandle == -1)
return 0;
_lread(fileHandle, &Buffer, 183u);
if (lstrcmpA("PARTOUT(4.0)RESOURCE", Buffer.FileSignature))
{
_lclose(fileHandle);
return 0;
}
datFile = (datFileStruct*)memoryallocate(10);
if (!datFile)
{
_lclose(fileHandle);
return 0;
}
if (lstrlenA(Buffer.Description) <= 0)
{
datFile->Description = 0;
}
else
{
lenOfStr = lstrlenA(Buffer.Description);
descriptionBuf = (char*)memoryallocate(lenOfStr + 1);
datFile->Description = descriptionBuf;
if (!descriptionBuf)
{
_lclose(fileHandle);
LABEL_10:
memoryfree(datFile);
return 0;
}
lstrcpyA(descriptionBuf, Buffer.Description);
}
unknown = Buffer.Unknown;
if (Buffer.Unknown)
{
unknownBuf = (char*)memoryallocate(Buffer.Unknown);
unknownBuf2 = unknownBuf;
if (!unknownBuf)
{
_lclose(hFile);
goto LABEL_19;
}
_lread(hFile, (void*)unknownBuf, unknown);
memoryfree(unknownBuf2);
}
groupDataBuf = (char**)memoryallocate(4 * Buffer.NumberOfGroups);
datFile->GroupData = groupDataBuf;
if (!groupDataBuf)
{
LABEL_19:
if (datFile->Description)
memoryfree(datFile->Description);
goto LABEL_10;
}
groupIndex = 0;
return datFile;
}
int partman::make_path_name(LPSTR lpFilename, LPCSTR lpString2, int nSize)
{
int nameSize = GetModuleFileNameA(nullptr, lpFilename, nSize);
if (!nameSize || nameSize == nSize)
return 1;
for (CHAR* i = &lpFilename[nameSize]; i > lpFilename; --i)
{
if (*i == '\\' || *i == ':')
{
i[1] = 0;
break;
}
--nameSize;
}
if (nameSize + 13 < nSize)
{
lstrcatA(lpFilename, lpString2);
return 0;
}
lstrcatA(lpFilename, "?");
return 1;
}

View file

@ -0,0 +1,58 @@
#pragma once
#pragma pack(push)
#pragma pack(1)
struct datFileHeader
{
char FileSignature[21];
char AppName[50];
char Description[100];
int FileSize;
unsigned short NumberOfGroups;
int SizeOfBody;
unsigned short Unknown;
};
#pragma pack(pop)
static_assert(sizeof(datFileHeader) == 183, "Wrong size of datFileHeader");
struct datFileStruct
{
unsigned short NumberOfGroups;
char* Description;
char** GroupData;
};
enum datFieldTypes
{
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 ? )
};
//typedef const char* LPCSTR;
class partman
{
public:
static datFileStruct* load_records(LPCSTR lpFileName);
static int make_path_name(LPSTR lpFilename, LPCSTR lpString2, int nSize = 0x12Cu);
private:
static short _field_size[];
};

View file

@ -10,5 +10,11 @@
#define PCH_H
// TODO: add headers that you want to pre-compile here
#include <windows.h>
#include <cstdio>
#define memoryallocate(x) malloc(x);
#define memoryfree(x) free(x);
#endif //PCH_H