-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathDIMUnpack.c
347 lines (299 loc) · 8.82 KB
/
DIMUnpack.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <memory.h>
#if defined(WIN32) || defined(__WINDOWS__)
#include <direct.h> // for _mkdir()
#else
#include <sys/stat.h>
#define _mkdir(dir) mkdir(x, 0777)
#endif
#include "stdtype.h"
#if defined(_MSC_VER)
#define INLINE static __inline
#elif defined(__GNUC__)
#define INLINE static __inline__
#else
#define INLINE static inline
#endif
#pragma pack(1)
typedef struct _fat_boot_sector
{
UINT16 BytPerSect;
UINT8 SectPerCluster;
UINT16 ReservedSect;
UINT8 NumFats;
UINT16 RootDirEntries;
UINT16 LogicalSect;
UINT8 MediumDesc;
UINT16 SectPerFat;
UINT16 SectPerTrk;
UINT16 Heads;
UINT16 HiddenSect;
UINT8 Reserved[13];
char DiskName[11];
char FileSysType[8];
} FAT_BOOTSECT;
typedef struct _fat_file_entry
{
char Name[8];
char Extension[3];
UINT8 Attribute;
UINT8 Reserved[10];
UINT16 Time;
UINT16 Date;
UINT16 StartCluster;
UINT32 FileLength;
} FAT_ENTRY;
#pragma pack()
UINT32 DimSize;
UINT8* DimData;
FAT_BOOTSECT BootSect;
UINT32 ClusterBase;
UINT16 ClusterSize;
UINT16 FATEntries;
UINT16* FATTbl;
INLINE UINT16 ReadLE16(const UINT8* Data);
INLINE UINT16 ReadBE16(const UINT8* Data);
static void ReadFAT(UINT32 BasePos);
static void ReadDirectory(UINT32 Cluster, UINT16 NumEntries, const char* BasePath, UINT8 Layer);
static void BuildFilename(char* DestBuf, FAT_ENTRY* Entry);
static void ExtractFile(const char* FileName, UINT16 Cluster, UINT32 FileSize);
int main(int argc, char* argv[])
{
FILE* hFile;
char BootSig[0x11];
UINT8 BootFmt;
UINT8 BaseSects;
UINT16 RootDirSize;
UINT32 StartPos;
char* OutPath;
if (argc <= 2)
{
printf("Usage: DIMUnpack.exe DiskImg.dim OutPath\\\n");
return 0;
}
hFile = fopen(argv[1], "rb");
if (hFile == NULL)
return 1;
fseek(hFile, 0x00, SEEK_END);
DimSize = ftell(hFile);
fseek(hFile, 0x00, SEEK_SET);
DimData = (UINT8*)malloc(DimSize);
fread(DimData, 0x01, DimSize, hFile);
fclose(hFile);
strncpy(BootSig, (char*)&DimData[0x102], 0x10);
BootSig[0x10] = '\0';
printf("Disk Format:\t%s\n", BootSig);
if (BootSig[0] == '\x90')
{
// Verified to work with:
// "\x90X68IPL30" Asuka 120 Percent Burning Fest
// "\x90NEC 2.00" Arcus Odyssey [Disk 2]
BootFmt = 0x01;
StartPos = 0x10B;
BootSect.BytPerSect = ReadLE16( &DimData[StartPos + 0x00]);
BootSect.SectPerCluster = DimData[StartPos + 0x02];
BootSect.ReservedSect = ReadLE16( &DimData[StartPos + 0x03]);
BootSect.NumFats = DimData[StartPos + 0x05];
BootSect.RootDirEntries = ReadLE16( &DimData[StartPos + 0x06]);
BootSect.LogicalSect = ReadLE16( &DimData[StartPos + 0x08]);
BootSect.MediumDesc = DimData[StartPos + 0x0A];
BootSect.SectPerFat = ReadLE16( &DimData[StartPos + 0x0B]);
BootSect.SectPerTrk = ReadLE16( &DimData[StartPos + 0x0D]);
BootSect.Heads = ReadLE16( &DimData[StartPos + 0x0F]);
BootSect.HiddenSect = ReadLE16( &DimData[StartPos + 0x11]);
memcpy(BootSect.Reserved, &DimData[StartPos + 0x13], 0x0D);
memcpy(BootSect.DiskName, &DimData[StartPos + 0x20], 0x0B);
memcpy(BootSect.FileSysType, &DimData[StartPos + 0x2B], 0x08);
}
else if (! strncmp(BootSig, "Hudson soft", 11))
{
BootFmt = 0x02;
StartPos = 0x112;
BootSect.BytPerSect = ReadBE16( &DimData[StartPos + 0x00]);
BootSect.SectPerCluster = DimData[StartPos + 0x02];
BootSect.NumFats = DimData[StartPos + 0x03];
BootSect.ReservedSect = ReadBE16( &DimData[StartPos + 0x04]);
BootSect.RootDirEntries = ReadBE16( &DimData[StartPos + 0x06]);
BootSect.LogicalSect = ReadBE16( &DimData[StartPos + 0x08]);
BootSect.MediumDesc = DimData[StartPos + 0x0A];
BootSect.SectPerFat = DimData[StartPos + 0x0B];
BootSect.SectPerTrk = 0;
BootSect.Heads = 0;
BootSect.HiddenSect = 0;
memset(BootSect.Reserved, 0x00, 0x0D);
memset(BootSect.DiskName, 0x00, 0x0B);
memset(BootSect.FileSysType, 0x00, 0x08);
}
else
{
printf("Unknown disk format!\n");
free(DimData);
return 2;
}
printf("Bytes per Sector:\t%hu\n", BootSect.BytPerSect); BootSect.BytPerSect=1024;
printf("Boot Sectors:\t\t%hu\n", BootSect.ReservedSect); BootSect.ReservedSect=1;
printf("RootDir Entries:\t%hu\n", BootSect.RootDirEntries); BootSect.RootDirEntries=192;
printf("Sectors per Cluster:\t%hu\n", BootSect.SectPerCluster); BootSect.SectPerCluster=1;
BootSect.NumFats = 2; BootSect.SectPerFat = 2;
BaseSects = BootSect.ReservedSect + BootSect.NumFats * BootSect.SectPerFat;
RootDirSize = BootSect.RootDirEntries * 32;
RootDirSize = ((RootDirSize - 1) | (BootSect.BytPerSect - 1)) + 1; // round up to full sectors
ClusterSize = BootSect.SectPerCluster * BootSect.BytPerSect;
ClusterBase = 0x100 + BaseSects * BootSect.BytPerSect + RootDirSize - 2 * ClusterSize; // the first Cluster has number 2
printf("Cluster Base:\t0x%04X\n", ClusterBase);
printf("\n");
ReadFAT(0x100 + BootSect.ReservedSect * BootSect.BytPerSect);
OutPath = (char*)malloc(strlen(argv[2]) + 2);
strcpy(OutPath, argv[2]);
StartPos = strlen(OutPath);
if (StartPos && (OutPath[StartPos - 1] == '\\' || OutPath[StartPos - 1] == '/'))
OutPath[StartPos - 1] = '\0';
_mkdir(OutPath);
strcat(OutPath, "\\");
_getch();
ReadDirectory(0x100 + BaseSects * BootSect.BytPerSect, BootSect.RootDirEntries, OutPath, 0);
free(OutPath);
free(FATTbl);
free(DimData);
_getch();
return 0;
}
INLINE UINT16 ReadLE16(const UINT8* Data)
{
// read 16-Bit Word (Little Endian/Intel Byte Order)
return (Data[0x01] << 8) | (Data[0x00] << 0);
}
INLINE UINT16 ReadBE16(const UINT8* Data)
{
// read 16-Bit Word (Big Endian/Motorola Byte Order)
return (Data[0x00] << 8) | (Data[0x01] << 0);
}
static void ReadFAT(UINT32 BasePos)
{
UINT32 CurPos;
UINT16 CurEnt;
FATEntries = BootSect.SectPerFat * BootSect.BytPerSect / 3 * 2; // 12 bit per FAT entry (*8/12)
FATTbl = (UINT16*)malloc(sizeof(UINT16) * FATEntries);
for (CurEnt = 0x00, CurPos = BasePos; CurEnt < FATEntries; CurEnt += 2, CurPos += 0x03)
{
FATTbl[CurEnt + 0] = ( DimData[CurPos + 0] << 0) |
((DimData[CurPos + 1] & 0x0F) << 8);
FATTbl[CurEnt + 1] = ((DimData[CurPos + 1] & 0xF0) >> 4) |
( DimData[CurPos + 2] << 4);
}
return;
}
static void ReadDirectory(UINT32 Cluster, UINT16 NumEntries, const char* BasePath, UINT8 Layer)
{
UINT32 DirBasePos;
UINT16 CurClst;
UINT32 CurPos;
UINT32 EndPos;
FAT_ENTRY* CurEntry;
char* FileName;
char* FileTitle;
UINT8 TempByt;
FileName = (char*)malloc(strlen(BasePath) + 16); // Base + "8.3" + '\0' -> Base+13
strcpy(FileName, BasePath);
FileTitle = FileName + strlen(FileName);
if (NumEntries)
{
// Root Directory, Cluster == Base Offset
CurClst = 0x00;
DirBasePos = Cluster;
EndPos = DirBasePos + NumEntries * 0x20;
}
else
{
CurClst = (UINT16)Cluster;
}
do
{
if (CurClst) // if NOT Root Directory
{
// another Directory
DirBasePos = ClusterBase + ClusterSize * CurClst;
EndPos = DirBasePos + ClusterSize;
}
for (CurPos = DirBasePos; CurPos < EndPos; CurPos += 0x20)
{
CurEntry = (FAT_ENTRY*)&DimData[CurPos];
if (CurEntry->Name[0] == 0x00)
{
CurClst = 0x00; // terminate instantly
break;
}
BuildFilename(FileTitle, CurEntry);
TempByt = Layer;
while(TempByt --)
putchar('\t');
if ((CurEntry->Attribute & 0x10)) // Is Directory?
{
// "." and ".." are for changing directories
if (strcmp(FileTitle, ".") && strcmp(FileTitle, ".."))
{
_mkdir(FileName);
strcat(FileTitle, "\\");
printf("%s\n", FileTitle);
ReadDirectory(CurEntry->StartCluster, 0x00, FileName, Layer + 1);
}
else
{
printf("%s\n", FileTitle);
}
}
else
{
printf("%s\n", FileTitle);
ExtractFile(FileName, CurEntry->StartCluster, CurEntry->FileLength);
}
}
CurClst = FATTbl[CurClst];
} while(CurClst && CurClst < 0xFF0);
// Cluster 0x000 is the "free" cluster, so I use it as terminator.
// Clusters 0xFF0 are EOF or invalid clusters, so I stop here, too.
return;
}
static void BuildFilename(char* DestBuf, FAT_ENTRY* Entry)
{
UINT8 NameLen;
UINT8 ExtLen;
NameLen = 8;
while(NameLen && Entry->Name[NameLen - 1] == ' ')
NameLen --;
ExtLen = 3;
while(ExtLen && Entry->Extension[ExtLen - 1] == ' ')
ExtLen --;
if (ExtLen)
sprintf(DestBuf, "%.*s.%.*s", NameLen, Entry->Name, ExtLen, Entry->Extension);
else
sprintf(DestBuf, "%.*s", NameLen, Entry->Name);
return;
}
static void ExtractFile(const char* FileName, UINT16 Cluster, UINT32 FileSize)
{
FILE* hFile;
UINT16 CurClst;
UINT8* Buffer;
UINT32 ClstPos;
UINT32 WrtBytes;
hFile = fopen(FileName, "wb");
if (hFile == NULL)
return;
Buffer = (UINT8*)malloc(ClusterSize);
CurClst = Cluster;
while(FileSize)
{
if (CurClst >= 0xFF0)
break;
WrtBytes = (FileSize > ClusterSize) ? ClusterSize : FileSize;
ClstPos = ClusterBase + CurClst * ClusterSize;
fwrite(&DimData[ClstPos], 0x01, WrtBytes, hFile);
FileSize -= WrtBytes;
CurClst = FATTbl[CurClst];
}
fclose(hFile);
return;
}