aboutsummaryrefslogtreecommitdiff
path: root/dep/CascLib/src/CascRootFile_Install.cpp
blob: 2a01acb8590e5f99f92421b7e7286f40ca5c0382 (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
/*****************************************************************************/
/* CascRootFile_Install.cpp               Copyright (c) Ladislav Zezula 2018 */
/*---------------------------------------------------------------------------*/
/* Support for ROOT handler based on INSTALL manifest                        */
/*---------------------------------------------------------------------------*/
/*   Date    Ver   Who  Comment                                              */
/* --------  ----  ---  -------                                              */
/* 21.05.19  1.00  Lad  The first version of CascRootFile_Install.cpp        */
/*****************************************************************************/

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

//-----------------------------------------------------------------------------
// Handler definitions for Starcraft I root file

struct TRootHandler_Install : public TFileTreeRoot
{
    public:

    TRootHandler_Install() : TFileTreeRoot(0)
    {
        // We have file names and return CKey as result of search
        dwFeatures |= (CASC_FEATURE_FILE_NAMES | CASC_FEATURE_ROOT_CKEY);
    }

    DWORD Load(TCascStorage * hs, CASC_INSTALL_HEADER InHeader, LPBYTE pbInstallFile, LPBYTE pbInstallEnd)
    {
        PCASC_CKEY_ENTRY pCKeyEntry;
        const char * szString;
        size_t nBitmapLength;
        size_t nFileCount = InHeader.EntryCount;

        // Skip the header
        pbInstallFile += InHeader.HeaderLength;

        // Skip the tags
        for(DWORD i = 0; i < InHeader.TagCount; i++)
        {
            szString = (const char *)pbInstallFile;
            nBitmapLength = GetTagBitmapLength(pbInstallFile, pbInstallEnd, InHeader.EntryCount);
            pbInstallFile = pbInstallFile + strlen(szString) + 1 + sizeof(USHORT) + nBitmapLength;
        }

        // Load the names and insert them to the root handler
        while(nFileCount > 0 && pbInstallFile < pbInstallEnd)
        {
            // File Name and CKey
            szString = (const char *)pbInstallFile;
            pbInstallFile += strlen(szString) + 1;

            // Verify whether it is a known entry
            pCKeyEntry = FindCKeyEntry_CKey(hs, pbInstallFile);
            pbInstallFile += MD5_HASH_SIZE + sizeof(DWORD);

            // Insert the FileName+CKey to the file tree
            if(pCKeyEntry != NULL)
                FileTree.InsertByName(pCKeyEntry, szString);
            nFileCount--;
        }

        return ERROR_SUCCESS;
    }
};

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

DWORD CaptureInstallHeader(CASC_INSTALL_HEADER & InHeader, LPBYTE pbFileData, size_t cbFileData)
{
    PFILE_INSTALL_HEADER pFileHeader = (PFILE_INSTALL_HEADER)pbFileData;

    // Check the signature ('DL') and version
    if(cbFileData < sizeof(FILE_INSTALL_HEADER) || pFileHeader->Magic != FILE_MAGIC_INSTALL || pFileHeader->Version != 1)
        return ERROR_BAD_FORMAT;

    // Note that we don't support CKey sizes greater than 0x10 in the INSTALL file
    if(pFileHeader->EKeyLength > MD5_HASH_SIZE)
        return ERROR_BAD_FORMAT;

    // Capture the header version 1
    memset(&InHeader, 0, sizeof(CASC_INSTALL_HEADER));
    InHeader.Magic = pFileHeader->Magic;
    InHeader.Version = pFileHeader->Version;
    InHeader.EKeyLength = pFileHeader->EKeyLength;
    InHeader.TagCount = ConvertBytesToInteger_2(pFileHeader->TagCount);
    InHeader.EntryCount = ConvertBytesToInteger_4(pFileHeader->EntryCount);
    InHeader.HeaderLength = sizeof(FILE_INSTALL_HEADER);
    return ERROR_SUCCESS;
}

DWORD RootHandler_CreateInstall(TCascStorage * hs, CASC_BLOB & InstallFile)
{
    CASC_INSTALL_HEADER InHeader;
    TRootHandler_Install * pRootHandler = NULL;
    DWORD dwErrCode = ERROR_BAD_FORMAT;

    // Capture the header of the DOWNLOAD file
    dwErrCode = CaptureInstallHeader(InHeader, InstallFile.pbData, InstallFile.cbData);
    if(dwErrCode == ERROR_SUCCESS)
    {
        // Allocate the root handler object
        pRootHandler = new TRootHandler_Install();
        if(pRootHandler != NULL)
        {
            // Parse the entire install manifest
            dwErrCode = pRootHandler->Load(hs, InHeader, InstallFile.pbData, InstallFile.End());
            hs->pRootHandler = pRootHandler;
        }
    }

    return dwErrCode;
}