aboutsummaryrefslogtreecommitdiff
path: root/dep/CascLib/src/CascDumpData.cpp
blob: 3c0e385ac07aa9b2d316a5ccad823f524037cb7e (plain)
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
/*****************************************************************************/
/* CascDumpData.cpp                       Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* System-dependent directory functions for CascLib                          */
/*---------------------------------------------------------------------------*/
/*   Date    Ver   Who  Comment                                              */
/* --------  ----  ---  -------                                              */
/* 07.05.14  1.00  Lad  The first version of CascDumpData.cpp                */
/*****************************************************************************/

#define __CASCLIB_SELF__
#include "CascLib.h"
#include "CascCommon.h"
#include "CascMndx.h"

#ifdef _DEBUG       // The entire feature is only valid for debug purposes

//-----------------------------------------------------------------------------
// Forward definitions

//LPBYTE VerifyLocaleBlock(PROOT_BLOCK_INFO pBlockInfo, LPBYTE pbFilePointer, LPBYTE pbFileEnd);

//-----------------------------------------------------------------------------
// Sort compare functions

static int CompareIndexEntries_FilePos(const void *, const void * pvIndexEntry1, const void * pvIndexEntry2)
{
    PCASC_INDEX_ENTRY pIndexEntry1 = (PCASC_INDEX_ENTRY)pvIndexEntry1;
    PCASC_INDEX_ENTRY pIndexEntry2 = (PCASC_INDEX_ENTRY)pvIndexEntry2;
    ULONGLONG FileOffset1 = ConvertBytesToInteger_5(pIndexEntry1->FileOffsetBE);
    ULONGLONG FileOffset2 = ConvertBytesToInteger_5(pIndexEntry2->FileOffsetBE);
    DWORD ArchIndex1 = (DWORD)(FileOffset1 >> 0x1E);
    DWORD ArchIndex2 = (DWORD)(FileOffset2 >> 0x1E);

    // First, compare the archive index
    if(ArchIndex1 < ArchIndex2)
        return -1;
    if(ArchIndex1 > ArchIndex2)
        return +1;

    // Second, compare the archive offset
    FileOffset1 &= 0x3FFFFFFF;
    FileOffset2 &= 0x3FFFFFFF;
    if(FileOffset1 < FileOffset2)
        return -1;
    if(FileOffset1 > FileOffset2)
        return +1;

    return 0;
}

//-----------------------------------------------------------------------------
// Public functions

void CascDumpSparseArray(const char * szFileName, void * pvSparseArray)
{
    TSparseArray * pSparseArray = (TSparseArray *)pvSparseArray;
    FILE * fp;

    // Create the dump file
    fp = fopen(szFileName, "wt");
    if(fp != NULL)                             
    {
        // Write header
        fprintf(fp, "##   Value\n--   -----\n");
                          
        // Write the values
        for(DWORD i = 0; i < pSparseArray->TotalItemCount; i++)
        {
            DWORD Value = 0;

            if(pSparseArray->IsItemPresent(i))
            {
                Value = pSparseArray->GetItemValue(i);
                fprintf(fp, "%02X    %02X\n", i, Value);
            }
            else
            {
                fprintf(fp, "%02X    --\n", i);
            }
        }

        fclose(fp);
    }
}

void CascDumpNameFragTable(const char * szFileName, void * pMarFile)
{
    TFileNameDatabase * pDB = ((PMAR_FILE)pMarFile)->pDatabasePtr->pDB;
    FILE * fp;

    // Create the dump file
    fp = fopen(szFileName, "wt");
    if(fp != NULL)                             
    {
        PNAME_FRAG pNameTable = pDB->NameFragTable.NameFragArray;
        const char * szNames = pDB->IndexStruct_174.NameFragments.CharArray;
        const char * szLastEntry;
        char szMatchType[0x100];

        // Dump the table header
        fprintf(fp, "Indx  ThisHash NextHash FragOffs\n");
        fprintf(fp, "----  -------- -------- --------\n");

        // Dump all name entries
        for(DWORD i = 0; i < pDB->NameFragTable.ItemCount; i++)
        {
            // Reset both match types
            szMatchType[0] = 0;
            szLastEntry = "";

            // Only if the table entry is not empty
            if(pNameTable->ItemIndex != 0xFFFFFFFF)
            {
                // Prepare the entry
                if(IS_SINGLE_CHAR_MATCH(pDB->NameFragTable, i))
                    sprintf(szMatchType, "SINGLE_CHAR (\'%c\')", (pNameTable->FragOffs & 0xFF));
                else
                    sprintf(szMatchType, "NAME_FRAGMT (\"%s\")", szNames + pNameTable->FragOffs);
            }

            // Dump the entry
            fprintf(fp, "0x%02X  %08x %08x %08x %s%s\n", i, pNameTable->ItemIndex,
                                                            pNameTable->NextIndex,
                                                            pNameTable->FragOffs,
                                                            szMatchType,
                                                            szLastEntry);
            pNameTable++;
        }
        fclose(fp);
    }
}

void CascDumpFileNames(const char * szFileName, void * pvMarFile)
{
    TMndxFindResult Struct1C;
    PMAR_FILE pMarFile = (PMAR_FILE)pvMarFile;
    FILE * fp;
    char szNameBuff[0x200];
    bool bFindResult;

    // Create the dump file
    fp = fopen(szFileName, "wt");
    if(fp != NULL)
    {
        // Set an empty path as search mask (?)
        Struct1C.SetSearchPath("", 0);

        // Keep searching
        for(;;)
        {
            // Search the next file name
            pMarFile->pDatabasePtr->sub_1956CE0(&Struct1C, &bFindResult);

            // Stop the search in case of failure
            if(!bFindResult)
                break;

            // Printf the found file name
            memcpy(szNameBuff, Struct1C.szFoundPath, Struct1C.cchFoundPath);
            szNameBuff[Struct1C.cchFoundPath] = 0;
            fprintf(fp, "%s\n", szNameBuff);
        }

        fclose(fp);
    }

    // Free the search structures
    Struct1C.FreeStruct40();
}

void CascDumpIndexEntry(
    TCascStorage * /* hs */,
    TDumpContext * dc,
    PCASC_INDEX_ENTRY pIndexEntry,
    int /* nDumpLevel */)
{
    if(pIndexEntry != NULL)
    {
        ULONGLONG FileOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffsetBE);
        DWORD ArchIndex = (DWORD)(FileOffset >> 0x1E);
        DWORD FileSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE);

        // Mask the file offset
        FileOffset &= 0x3FFFFFFF;
        dump_print(dc, "    data.%03u at 0x%08x (0x%lx bytes)\n",
                       ArchIndex,
                (DWORD)FileOffset,
                       FileSize);

        //if(nDumpLevel > 2)
        //{
        //    QueryKey.pbData = pIndexEntry->IndexKey;
        //    QueryKey.cbData = MD5_HASH_SIZE;
        //    if(CascOpenFileByIndexKey((HANDLE)hs, &QueryKey, 0, &hFile))
        //    {
        //        // Make sure that the data file is open and frame header loaded
        //        CascGetFileSize(hFile, NULL);
        //        hf = IsValidFileHandle(hFile);
        //        assert(hf->pStream != NULL);

        //        // Read the header area
        //        FileOffset = hf->HeaderOffset - BLTE_HEADER_DELTA;
        //        FileStream_Read(hf->pStream, &FileOffset, HeaderArea, sizeof(HeaderArea));
        //        CascCloseFile(hFile);

        //        // Dump the header area
        //        dump_print(dc, "    FileSize: %X  Rest: %s\n",
        //                       ConvertBytesToInteger_4_LE(&HeaderArea[0x10]),
        //                       StringFromBinary(&HeaderArea[0x14], 10, szBuffer));
        //    }
        //}
    }
    else
    {
        dump_print(dc, "    NO INDEX ENTRY\n");
    }
}

void CascDumpEncodingEntry(
    TCascStorage * hs,
    TDumpContext * dc,
    PCASC_ENCODING_ENTRY pEncodingEntry,
    int nDumpLevel)
{
    PCASC_INDEX_ENTRY pIndexEntry;
    QUERY_KEY QueryKey;
    LPBYTE pbIndexKey;
    char szMd5[MD5_STRING_SIZE+1];

    // If the encoding key exists
    if(pEncodingEntry != NULL)
    {
        dump_print(dc, "  Size %lx Key Count: %u\n",
                       ConvertBytesToInteger_4(pEncodingEntry->FileSizeBE),
                       pEncodingEntry->KeyCount);

        // Dump all index keys
        pbIndexKey = pEncodingEntry->EncodingKey + MD5_HASH_SIZE;
        for(DWORD j = 0; j < pEncodingEntry->KeyCount; j++, pbIndexKey += MD5_HASH_SIZE)
        {
            // Dump the index key
            dump_print(dc, "  %s\n", StringFromMD5(pbIndexKey, szMd5));
            
            // Dump the index entry as well
            if(nDumpLevel >= DUMP_LEVEL_INDEX_ENTRIES)
            {
                QueryKey.pbData = pbIndexKey;
                QueryKey.cbData = MD5_HASH_SIZE;
                pIndexEntry = FindIndexEntry(hs, &QueryKey);
                CascDumpIndexEntry(hs, dc, pIndexEntry, nDumpLevel);
            }
        }
    }
    else
    {
        dump_print(dc, "  NO ENCODING KEYS\n");
    }
}

void CascDumpIndexEntries(const char * szFileName, TCascStorage * hs)
{
    PCASC_INDEX_ENTRY * ppIndexEntries;
    FILE * fp;
    size_t nIndexEntries = hs->pIndexEntryMap->ItemCount;
    char szIndexKey[0x40];

    // Create the dump file
    fp = fopen(szFileName, "wt");
    if(fp != NULL)
    {
        // Create linear aray
        ppIndexEntries = CASC_ALLOC(PCASC_INDEX_ENTRY, nIndexEntries);
        if(ppIndexEntries != NULL)
        {
            // Obtain the linear array of index entries
            Map_EnumObjects(hs->pIndexEntryMap, (void **)ppIndexEntries);

            // Sort the array by archive number and archive offset
            qsort_pointer_array((void **)ppIndexEntries, nIndexEntries, CompareIndexEntries_FilePos, NULL);

            // Parse the array
            fprintf(fp, "ArNo ArOffset FileSize IndexKey\n==== ======== ======== ================================\n");
            for(size_t i = 0; i < nIndexEntries; i++)
            {
                PCASC_INDEX_ENTRY pIndexEntry = ppIndexEntries[i];
                ULONGLONG ArchOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffsetBE);
                DWORD ArchIndex = (DWORD)(ArchOffset >> 0x1E);
                DWORD FileSize;

                FileSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE);
                ArchOffset &= 0x3FFFFFFF;
                
                fprintf(fp, " %02X  %08X %08X %s\n", ArchIndex, (DWORD)ArchOffset, FileSize, StringFromBinary(pIndexEntry->IndexKey, CASC_FILE_KEY_SIZE, szIndexKey));
            }

            CASC_FREE(ppIndexEntries);
        }

        fclose(fp);
    }
}

void CascDumpFile(const char * szFileName, HANDLE hFile)
{
    FILE * fp;
    DWORD dwBytesRead = 1;
    DWORD dwFilePos = CascSetFilePointer(hFile, 0, NULL, FILE_BEGIN);
    BYTE Buffer[0x1000];

    // Create the dump file
    fp = fopen(szFileName, "wb");
    if(fp != NULL)
    {
        // Read data as long as we can, write as long as we can
        while(dwBytesRead != 0)
        {
            // Read from the source file
            if(!CascReadFile(hFile, Buffer, sizeof(Buffer), &dwBytesRead))
                break;

            // Write to the destination file
            if(fwrite(Buffer, 1, dwBytesRead, fp) != dwBytesRead)
                break;
        }

        // Close the local file
        fclose(fp);

        // Restore the file pointer
        CascSetFilePointer(hFile, dwFilePos, NULL, FILE_BEGIN);
    }
}

#endif // _DEBUG