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
|
/*****************************************************************************/
/* CascRootFile_Text.cpp Copyright (c) Ladislav Zezula 2017 */
/*---------------------------------------------------------------------------*/
/* Support for generic ROOT handler with mapping of FileName -> CKey */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 28.10.15 1.00 Lad The first version of CascRootFile_Text.cpp */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "CascLib.h"
#include "CascCommon.h"
//-----------------------------------------------------------------------------
// Handler definitions for Starcraft I root file
struct TRootHandler_SC1 : public TFileTreeRoot
{
public:
TRootHandler_SC1() : TFileTreeRoot(0)
{
// We have file names and return CKey as result of search
dwFeatures |= (CASC_FEATURE_FILE_NAMES | CASC_FEATURE_ROOT_CKEY);
}
static bool IsRootFile(LPBYTE pbRootFile, DWORD cbRootFile)
{
CASC_CSV Csv(1, false);
size_t nColumns;
bool bResult = false;
// Get the first line from the listfile
if(Csv.Load(pbRootFile, cbRootFile) == ERROR_SUCCESS)
{
// There must be 2 or 3 elements
nColumns = Csv[CSV_ZERO].GetColumnCount();
if (nColumns == 2 || nColumns == 3)
{
const CASC_CSV_COLUMN & FileName = Csv[CSV_ZERO][CSV_ZERO];
const CASC_CSV_COLUMN & CKeyStr = Csv[CSV_ZERO][1];
bResult = (FileName.szValue && CKeyStr.szValue && CKeyStr.nLength == MD5_STRING_SIZE);
}
}
// We need to reset the listfile to the begin position
return bResult;
}
DWORD Load(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile)
{
PCASC_CKEY_ENTRY pCKeyEntry;
CASC_CSV Csv(0, false);
BYTE CKey[MD5_HASH_SIZE];
DWORD dwErrCode;
// Parse the ROOT file first in order to see whether we have the correct format
dwErrCode = Csv.Load(pbRootFile, cbRootFile);
if(dwErrCode == ERROR_SUCCESS)
{
// Parse all lines
while(Csv.LoadNextLine())
{
const CASC_CSV_COLUMN & FileName = Csv[CSV_ZERO][CSV_ZERO];
const CASC_CSV_COLUMN & CKeyStr = Csv[CSV_ZERO][1];
// Convert the CKey to binary
if(ConvertStringToBinary(CKeyStr.szValue, MD5_STRING_SIZE, CKey) == ERROR_SUCCESS)
{
// Verify whether it is a known entry
if((pCKeyEntry = FindCKeyEntry_CKey(hs, CKey)) != NULL)
{
// Insert the FileName+CKey to the file tree
FileTree.InsertByName(pCKeyEntry, FileName.szValue);
}
}
}
}
return dwErrCode;
}
};
//-----------------------------------------------------------------------------
// Public functions
//
// Starcraft ROOT file is a text file with the following format:
// HD2/portraits/NBluCrit/NLCFID01.webm|c2795b120592355d45eba9cdc37f691e
// locales/enUS/Assets/campaign/EXPZerg/Zerg08/staredit/wav/zovtra01.ogg|316b0274bf2dabaa8db60c3ff1270c85
// locales/zhCN/Assets/sound/terran/ghost/tghdth01.wav|6637ed776bd22089e083b8b0b2c0374c
//
DWORD RootHandler_CreateStarcraft1(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile)
{
TRootHandler_SC1 * pRootHandler = NULL;
DWORD dwErrCode = ERROR_BAD_FORMAT;
// Verify whether this looks like a Starcraft I root file
if(TRootHandler_SC1::IsRootFile(pbRootFile, cbRootFile))
{
// Allocate the root handler object
pRootHandler = new TRootHandler_SC1();
if(pRootHandler != NULL)
{
// Load the root directory. If load failed, we free the object
dwErrCode = pRootHandler->Load(hs, pbRootFile, cbRootFile);
if(dwErrCode != ERROR_SUCCESS)
{
delete pRootHandler;
pRootHandler = NULL;
}
}
}
// Assign the root directory (or NULL) and return error
hs->pRootHandler = pRootHandler;
return dwErrCode;
}
|