This repository has been archived by the owner on Oct 28, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
/
IMG.h
472 lines (352 loc) · 13.4 KB
/
IMG.h
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
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
/* ---------------------------------------------------------------------------
** This software is in the public domain, furnished "as is", without technical
** support, and with no warranty, express or implied, as to its usefulness for
** any purpose.
**
** IMG.cpp
** Class to create or edit GTA IMG archives with efficient algorithms.
** Works with archive versions:
** • version 1 (GTA III, GTA VC, GTA III Mobile)
** • version 2 (GTA SA)
** does not support GTA IV yet.
**
** Version: 1.9
** Author: fastman92
** Site: fastman92-site.tk
** -------------------------------------------------------------------------*/
#include <windows.h>
#include <vector>
#include <algorithm>
#include <io.h>
#include <iostream>
#include <list>
#include <utility>
#include "Shlwapi.h"
#pragma comment( lib, "shlwapi.lib")
#include "GTASA_CRC32.h"
// #include "Rijndael.h"
#undef min
#undef max
#define GET_ALIGNED_SIZE(requested_size, block_size) (requested_size % block_size == 0 ? requested_size : ((requested_size / block_size)+1)*block_size)
#define GET_ALIGNED_SIZE_IN_BLOCKS(requested_size, block_size) (requested_size % block_size == 0 ? requested_size / block_size : (requested_size / block_size) + 1)
#define _countOfAndPointer(Array) _countof(Array), Array
// #define IMG_DEBUG
// Function to get number of digits
// Example: number 1000 has 4 digits.
template <class T>
int GetNumberOfDigits(T number, unsigned int base = 10)
{
int digits = 0;
if (number < 0) digits = 1; // remove this line if '-' counts as a digit
while (number) {
number /= base;
digits++;
}
return digits;
}
enum eIMG_file_ResourceTypes : DWORD
{
RESOURCE_UNDEFINED = 0x00,
RESOURCE_GENERIC = 0x01,
RESOURCE_TEXTURE_ARCHIVE = 0x08,
RESOURCE_BOUNDS = 0x20,
RESOURCE_MODEL_FILE = 0x6E,
RESOURCE_XPFL = 0x24
};
enum class eIMG_FileOrder
{
INVALID,
DFF,
IFP,
TXD,
COL,
IPL,
CUT,
DAT
};
enum eIMG_version
{
IMG_VERSION_UNDEFINED,
IMG_VERSION_1, // GTA III, GTA VC, GTA III Mobile
IMG_VERSION_2, // GTA SA
IMG_VERSION_3_UNENCRYPTED, // GTA IV
IMG_VERSION_3_ENCRYPTED // GTA IV
};
class IMG;
class IMG_Entry
{
friend class IMG;
private:
char Name[256]; // NULL terminated
DWORD NameHash;
// In IMG archive
DWORD Position; // In blocks
WORD SizeSecondPriority; // In blocks
WORD SizeFirstPriority; // In blocks
// Version 3
DWORD SizeInBytes;
// DWORD SizeInBlocks;
eIMG_file_ResourceTypes ResourceType;
// Updates hash of file name
void IMG_Entry::UpdateFileNameHash();
// Get file size aligned to blocks
size_t IMG_Entry::GetFilesizeAllignedToBlocks();
// Gets file size in blocks
size_t IMG_Entry::GetFilesizeInBlocks();
public:
IMG* IMG_Instance;
// For reading/writing
unsigned int curPos;
/////// Methods
// Constructor
IMG_Entry::IMG_Entry(IMG * IMG_Instance);
// Returns pointer to file name.
const char* IMG_Entry::GetFilename();
// Writes a filename without extension to sufficiently long buffer
void IMG_Entry::GetFilenameWithoutExtension(char* filenameWithoutExtension);
// Returns file order ID
eIMG_FileOrder IMG_Entry::GetFileOrderIDbyExtension();
// Reads whole file, doesn't affect current file position (curPos)
// Returns number of bytes read.
size_t IMG_Entry::ReadEntireFile(void* ptr);
// Get file size in bytes
size_t IMG_Entry::GetFilesize();
//////// File operations that may affect curPos
// Reads to memory
size_t IMG_Entry::Read(void* Ptr, size_t Size);
// Reads one byte
char IMG_Entry::ReadC();
// Write data
size_t IMG_Entry::Write(void* ptr, size_t size);
// Check End-of-File indicator
bool IMG_Entry::isEOF();
// Seek to certain position
bool IMG_Entry::Seek(unsigned int offset, int origin);
// Returns current position
unsigned int IMG_Entry::Tell();
// Outputs entry informations
void IMG_Entry::DebugEntry(int fileID);
};
struct tIMG_FileOrder {
eIMG_FileOrder orderID;
const char* orderExtension;
const char* orderName;
};
class IMG
{
friend class IMG_Entry;
public:
const static unsigned int UNDEFINED = 0xFFFFFFFF;
struct AssociatedFilesMatch
{
AssociatedFilesMatch(DWORD FileID, DWORD IPL_num)
{
this -> FileID = FileID;
this -> IPL_num = IPL_num;
}
DWORD FileID;
DWORD IPL_num;
};
typedef std::list<IMG_Entry> tIMGentriesContainer;
typedef tIMGentriesContainer::iterator tIMGEntryIterator;
typedef tIMGentriesContainer::const_iterator tIMGEntryConstIterator;
typedef tIMGentriesContainer::reference tIMGEntryReference;
typedef tIMGentriesContainer::const_reference tIMGEntryConstReference;
private:
#ifdef IMG_DEBUG
FILE* debugFile;
#endif
// File entries
tIMGentriesContainer ListOfEntries;
private:
typedef std::vector<tIMGEntryIterator> tRelatedFilesContainer;
FILE* IMG_Handle;
FILE* DIR_Handle;
char IMG_fullPath [MAX_PATH];
char* IMG_filename;
// Size of all filenames, only usable, when IMG version 3
DWORD FilenamesSize;
// Get end of list entries and header
DWORD IMG::GetEndOfHeaderDataPastTheListOfFiles();
// Gets IPL filename and num, returns true on success and false on failure.
static bool IMG::GetIPLfilenameAndNum(const char* fullFilename, char* IPL_name, DWORD* IPL_num);
// Gets ID of this file OR IDs of all .ipl files with this name
void IMG::GetIteratorsOfAssociatedFiles(const char* SearchedName, tRelatedFilesContainer& list);
// Loads files identified by DWORD indexes into continous aligned memory
// Returned is size of all files loaded from list
// Remember to free memory when it's no longer neccessary! Use delete!
// None of addresses may be NULL
void IMG::LoadFilesInCountinousAlignedMemory(tRelatedFilesContainer& FileIterators, void** retAddress, size_t* retSize, FILE* imgHandle = NULL);
// Moves files located in position before list of files to suitable position
void IMG::MoveFilesLocatedBeforeListOfFilesToSuitablePosition(FILE* imgHandle);
// Returns pattern of IMG validity
void IMG::GetPatternToCheckIfPositionIsValid(char* str);
// Tests if file position is valid
void IMG::TestIfPositionIsValid(FILE* imgHandle);
// reads version 1 or 2 header
void IMG::ReadEntryOfVersion1And2Header(IMG_Entry& entry, FILE* file);
// writes version 1 or 2 header
void IMG::WriteListOfEntriesVersion1And2(FILE* file);
// Does action when the list of entries needs to be saved
void IMG::DoModifiedListOfEntriesActions();
// Does action when the archive has been modified
void IMG::DoModifiedArchiveActions();
// Updates list of entries in IMG archive/DIR file
void IMG::WriteListOfEntries(FILE* imgHandle = nullptr);
// Writes file content alligned to IMG_BLOCK_SIZE
// Returned value is number of blocks written ( realSize / IMG_BLOCK_SIZE )
size_t IMG::WriteAllignedFileToIMGblocks(const void* ptr, size_t size);
// Sorts an array by
// 1. Position
// 2. Size
void IMG::SortListOfEntriesByPositionAndSize(IMG::tIMGentriesContainer& list);
#ifdef IMG_DEBUG
public:
#endif
// Finds a first free space for target file
unsigned __int64 IMG::FindFirstEmptySpaceForFile(size_t filesize, tRelatedFilesContainer* overwrittenFileIndexes = NULL);
public:
const static unsigned int IMG_BLOCK_SIZE = 2048; // 2 KB
const static unsigned int MAX_FILESIZE = 0xFFFF * IMG_BLOCK_SIZE; // 128 MB - IMG_BLOCK_SIZE bytes
const static unsigned int GTAIV_MAGIC_ID = 0xA94E2A52;
char* GTAIV_encryption_key;
#pragma pack(push, 1)
struct IMG_version2_tableItem // size: 32 bytes
{
DWORD Position; // In blocks
WORD SizeSecondPriority; // In blocks
WORD SizeFirstPriority; // In blocks
char Name[24]; // NULL terminated
};
#pragma pack(pop)
#pragma pack(push, 1)
struct IMG_version3_header // size: 20 bytes
{
DWORD MagicID;
DWORD Version; // always should be 3
DWORD NumberOfItems;
DWORD TableOfItemsSize;
WORD SingleTableItemSize; // should be 0x10 (16)
WORD Unknown;
};
#pragma pack(pop)
struct IMG_version3_tableItem // size: 20 bytes
{
DWORD SizeInBytes;
eIMG_file_ResourceTypes ResourceType;
DWORD Position; // in blocks
WORD SizeInBlocks;
WORD Unknown;
};
eIMG_version archiveVersion;
// true if archive was modified in any way, but rebuilding didn't happen
bool bHasArchiveBeenModifiedAndNotRebuiltYet;
// delays writing of list of entries
bool bWritingOfEntriesPending;
bool bUseManualWritingOfEntries;
static tIMG_FileOrder fileOrderByExtension[];
// Returns pointer to file order struct by ID or NULL
static tIMG_FileOrder* IMG::getFileOrderStructByID(eIMG_FileOrder orderID);
DWORD IMG_ENTRY_MAX_FILE_NAME_LENGTH;
private:
// Writes IMG archive version 3 header to memory.
void IMG::WriteVersion3HeaderToMemory(IMG_version3_header* header);
public:
// Default constructor
IMG::IMG();
// Destructor
IMG::~IMG();
// Copy constructor
// IMG::IMG(const IMG &cSource);
// Opens IMG archive, assumes IMG archive to exist.
// Detects archive type automatically
bool IMG::OpenArchive(const char* path);
// Creates .img archive
// Example: object.CreateArchive("new.img", IMG::IMG_version::VERSION_1);
bool IMG::CreateArchive(const char* path, eIMG_version version);
// Opens .img archive if exists or creates if not exists
// Example: object.OpenOrCreateArchive("new.img", IMG::IMG_version::VERSION_1);
bool IMG::OpenOrCreateArchive(const char* path, eIMG_version version);
// Checks if archive is currently opened.
bool IMG::IsArchiveOpened();
// Sets writing of list of IMG entries to be done on request
void IMG::SetWritingListOfEntriesToBeDoneOnRequest(bool state);
// Writes a list of entries
void IMG::WriteListOfEntriesNow();
// Closes archive
void IMG::CloseArchive();
// Rebuilds archive
bool IMG::RebuildArchive();
// Returns true if archive was modified, but not rebuilt yet.
bool IMG::hasArchiveBeenModifiedAndNotRebuiltYet();
// Gets the size of .img archive in bytes
unsigned __int64 IMG::GetImgArchiveSize();
// Gets size of unused space in .img file
unsigned __int64 IMG::GetSizeOfUnusedSpace();
// Retrieves the number of files inside of IMG archive
DWORD IMG::GetFileCount();
// Adds or replaces file if exists
IMG::tIMGEntryIterator IMG::AddOrReplaceFile(const char* name, const void* ptr, size_t size);
// Adds file
IMG::tIMGEntryIterator IMG::AddFile(const char* name, const void* ptr, size_t size);
// Replaces file depending on iterator
void IMG::ReplaceSingleFile(tIMGEntryIterator IMGentryIt, const void* ptr, size_t size);
private:
// Loop used in AddFile and ReplaceSingleFile functions
void IMG::DoRelatedFilesLoop(tRelatedFilesContainer& RelatedFiles, tIMGEntryIterator newIMGentry, const void* ptr, size_t size);
// Sets format properties
void IMG::SetArchiveFormat(eIMG_version version);
public:
// Renames a file
bool IMG::RenameFile(tIMGEntryIterator fileInfo, const char* NewName);
// Remove a file
IMG::tIMGEntryConstIterator IMG::RemoveFile(tIMGEntryConstIterator _Where);
// Removes files
IMG::tIMGEntryConstIterator IMG::RemoveFiles(
tIMGEntryConstIterator _First_arg,
tIMGEntryConstIterator _Last_arg
);
// Gets iterator of file pointing to ListOfFiles
IMG::tIMGEntryIterator IMG::GetFileIteratorByName(const char* name);
// Checks if file with specified name exists and returns TRUE/FALSE
bool IMG::FileExists(const char* name);
// Checks if filename's length is appropriate for IMG entry as well as name characters.
bool IMG::IsFileNameValid(const char* name);
// Gets filename for imported file, filename may be truncated if archive version is 1 or 2.
errno_t IMG::GetFilenameForImportedFile(const char* lpFileName, char* lpFilePart, DWORD nBufferLength);
// Access file by name
// Returns a reference to the last element in the vector container.
IMG::tIMGEntryReference IMG::GetFileRefByName(const char* name);
// Return iterator to beginning
IMG::tIMGEntryIterator IMG::begin();
// Return iterator to beginning
IMG::tIMGEntryConstIterator IMG::begin() const;
// Return iterator to end
IMG::tIMGEntryIterator IMG::end();
// Return iterator to end
IMG::tIMGEntryConstIterator IMG::end() const;
// Return reverse iterator to reverse beginning
IMG::tIMGentriesContainer::reverse_iterator IMG::rbegin();
// Return reverse iterator to reverse beginning
IMG::tIMGentriesContainer::const_reverse_iterator IMG::rbegin() const;
// Return reverse iterator to reverse end
IMG::tIMGentriesContainer::reverse_iterator IMG::rend();
// Return reverse iterator to reverse end
IMG::tIMGentriesContainer::const_reverse_iterator IMG::rend() const;
// Access last element
// Returns a reference to the last element in the vector container.
IMG::tIMGEntryReference IMG::back();
// Access last element
// Returns a reference to the last element in the vector container.
IMG::tIMGEntryConstReference IMG::back() const;
// Access first element
// Returns a reference to the first element in the vector container.
IMG::tIMGEntryReference IMG::front();
// Access first element
// Returns a reference to the first element in the vector container.
IMG::tIMGEntryConstReference IMG::front() const;
// Outputs list of entries specified as argument
void IMG::DebugListOfEntries(tIMGentriesContainer& list);
// Outputs ListOfEntries
void IMG::DebugListOfEntries();
};