예제 #1
0
size_t ListFile_GetNext(void * pvListFile, const char * szMask, char * szBuffer, size_t nMaxChars)
{
    size_t nLength = 0;
    int nError = ERROR_SUCCESS;

    // Check for parameters
    for(;;)
    {
        // Read the (next) line
        nLength = ListFile_GetNextLine(pvListFile, szBuffer, nMaxChars);
        if(nLength == 0)
        {
            nError = ERROR_NO_MORE_FILES;
            break;
        }

        // If some mask entered, check it
        if(CheckWildCard(szBuffer, szMask))
        {
            nError = ERROR_SUCCESS;
            break;
        }
    }

    if(nError != ERROR_SUCCESS)
        SetLastError(nError);
    return nLength;
}
예제 #2
0
static int LoadCdnConfigFile(TCascStorage * hs, void * pvListFile)
{
    const char * szLineBegin;
    const char * szVarBegin;
    const char * szLineEnd;
    int nError = ERROR_SUCCESS;

    // Keep parsing the listfile while there is something in there
    for(;;)
    {
        // Get the next line
        if(!ListFile_GetNextLine(pvListFile, &szLineBegin, &szLineEnd))
            break;

        // Archive group
        szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "archive-group");
        if(szVarBegin != NULL)
        {
            nError = LoadSingleBlob(&hs->ArchivesGroup, szVarBegin, szLineEnd);
            continue;
        }

        // Archives
        szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "archives");
        if(szVarBegin != NULL)
        {
            nError = LoadMultipleBlobs(&hs->ArchivesKey, szVarBegin, szLineEnd);
            continue;
        }

        // Patch archive group
        szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "patch-archive-group");
        if(szVarBegin != NULL)
        {
            LoadSingleBlob(&hs->PatchArchivesKey, szVarBegin, szLineEnd);
            continue;
        }

        // Patch archives
        szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "patch-archives");
        if(szVarBegin != NULL)
        {
            nError = LoadMultipleBlobs(&hs->PatchArchivesKey, szVarBegin, szLineEnd);
            continue;
        }
    }

    // Check if all required fields are present
    if(hs->ArchivesKey.pbData == NULL || hs->ArchivesKey.cbData == 0)
        return ERROR_BAD_FORMAT;

    return nError;
}
예제 #3
0
static int ParseAgentFile(TCascStorage * hs, void * pvListFile)
{
    const char * szLinePtr;
    const char * szLineEnd;
    char szOneLine[0x200];
    size_t nLength;
    int nError;

    // Load the single line from the text file
    nLength = ListFile_GetNextLine(pvListFile, szOneLine, _maxchars(szOneLine));
    if(nLength == 0)
        return ERROR_BAD_FORMAT;

    // Set the line range
    szLinePtr = szOneLine;
    szLineEnd = szOneLine + nLength;

    // Extract the CDN build key
    nError = LoadInfoVariable(&hs->CdnBuildKey, szLinePtr, szLineEnd, true);
    if(nError == ERROR_SUCCESS)
    {
        // Skip the variable
        szLinePtr = SkipInfoVariable(szLinePtr, szLineEnd);

        // Load the CDN config hash
        nError = LoadInfoVariable(&hs->CdnConfigKey, szLinePtr, szLineEnd, true);
        if(nError == ERROR_SUCCESS)
        {
            // Skip the variable
            szLinePtr = SkipInfoVariable(szLinePtr, szLineEnd);

            // Skip the Locale/OS/code variable
            szLinePtr = SkipInfoVariable(szLinePtr, szLineEnd);

            // Load the URL
            hs->szUrlPath = CascNewStrFromAnsi(szLinePtr, szLineEnd);
            if(hs->szUrlPath == NULL)
                nError = ERROR_NOT_ENOUGH_MEMORY;
        }
    }

    // Verify all variables
    if(hs->CdnBuildKey.pbData == NULL || hs->CdnConfigKey.pbData == NULL || hs->szUrlPath == NULL)
        nError = ERROR_BAD_FORMAT;
    return nError;
}
예제 #4
0
static int ParseFile_CdnConfig(TCascStorage * hs, void * pvListFile)
{
    const char * szLineBegin;
    const char * szLineEnd;
    int nError = ERROR_SUCCESS;

    // Keep parsing the listfile while there is something in there
    for(;;)
    {
        // Get the next line
        if(!ListFile_GetNextLine(pvListFile, &szLineBegin, &szLineEnd))
            break;

        // CDN key of ARCHIVE-GROUP. Archive-group is actually a very special '.index' file.
        // It is essentially a merger of all .index files, with a structure change
        // When ".index" added after the ARCHIVE-GROUP, we get file name in "indices" folder
        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, "archive-group", LoadQueryKey, &hs->ArchiveGroup))
            continue;

        // CDN key of all archives. When ".index" added to the string, we get file name in "indices" folder
        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, "archives", LoadQueryKey, &hs->ArchivesKey))
            continue;

        // CDN keys of patch archives (needs research) 
        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, "patch-archives", LoadQueryKey, &hs->PatchArchivesKey))
            continue;

        // CDN key of probably the combined patch index file (needs research)
        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, "patch-archive-group", LoadQueryKey, &hs->PatchArchivesGroup))
            continue;

        // List of build configs this config supports (optional)
        // Points to file: "data\config\%02X\%02X\%s
        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, "builds", LoadQueryKey, &hs->BuildFiles))
            continue;
    }

    // Check if all required fields are present
    if(hs->ArchivesKey.pbData == NULL || hs->ArchivesKey.cbData == 0)
        return ERROR_BAD_FORMAT;

    return nError;
}
예제 #5
0
size_t ListFile_GetNextLine(void * pvListFile, char * szBuffer, size_t nMaxChars)
{
    const char * szLineBegin = NULL;
    const char * szLineEnd = NULL;
    size_t nLength;

    // Retrieve the next line
    nLength = ListFile_GetNextLine(pvListFile, &szLineBegin, &szLineEnd);

    // Check the length
    if(nLength > nMaxChars)
    {
        SetLastError(ERROR_INSUFFICIENT_BUFFER);
        return 0;
    }

    // Copy the line to the user buffer
    memcpy(szBuffer, szLineBegin, nLength);
    szBuffer[nLength] = 0;
    return nLength;
}
예제 #6
0
static int LoadCdnBuildFile(TCascStorage * hs, void * pvListFile)
{
    const char * szLineBegin;
    const char * szVarBegin;
    const char * szLineEnd = NULL;
    int nError = ERROR_SUCCESS;

    for(;;)
    {
        // Get the next line
        if(!ListFile_GetNextLine(pvListFile, &szLineBegin, &szLineEnd))
            break;

        // Game name
        szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "build-product");
        if(szVarBegin != NULL)
        {
            GetGameType(hs, szVarBegin, szLineEnd);
            continue;
        }

        // Game build number
        szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "build-name");
        if(szVarBegin != NULL)
        {
            GetBuildNumber(hs, szVarBegin, szLineEnd);
            continue;
        }

        // Root
        szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "root");
        if(szVarBegin != NULL)
        {
            LoadSingleBlob(&hs->RootKey, szVarBegin, szLineEnd);
            continue;
        }

        // Patch
        szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "patch");
        if(szVarBegin != NULL)
        {
            LoadSingleBlob(&hs->PatchKey, szVarBegin, szLineEnd);
            continue;
        }

        // Download
        szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "download");
        if(szVarBegin != NULL)
        {
            LoadSingleBlob(&hs->DownloadKey, szVarBegin, szLineEnd);
            continue;
        }

        // Install
        szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "install");
        if(szVarBegin != NULL)
        {
            LoadSingleBlob(&hs->InstallKey, szVarBegin, szLineEnd);
            continue;
        }

        // Encoding keys
        szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "encoding");
        if(szVarBegin != NULL)
        {
            nError = LoadMultipleBlobs(&hs->EncodingKey, szVarBegin, szLineEnd, 2);
            continue;
        }
    }

    // Check the encoding keys
    if(hs->EncodingKey.pbData == NULL || hs->EncodingKey.cbData != MD5_HASH_SIZE * 2)
        return ERROR_BAD_FORMAT;
    return nError;
}
예제 #7
0
static int ParseInfoFile(TCascStorage * hs, void * pvListFile)
{
    QUERY_KEY Active = {NULL, 0};
    QUERY_KEY TagString = {NULL, 0};
    QUERY_KEY CdnHost = {NULL, 0};
    QUERY_KEY CdnPath = {NULL, 0};
    char szOneLine1[0x200];
    char szOneLine2[0x200];
    size_t nLength1;
    size_t nLength2;
    int nError = ERROR_BAD_FORMAT;

    // Extract the first line, cotaining the headers
    nLength1 = ListFile_GetNextLine(pvListFile, szOneLine1, _maxchars(szOneLine1));
    if(nLength1 == 0)
        return ERROR_BAD_FORMAT;

    // Now parse the second and the next lines. We are looking for line
    // with "Active" set to 1
    for(;;)
    {
        const char * szLinePtr1 = szOneLine1;
        const char * szLineEnd1 = szOneLine1 + nLength1;
        const char * szLinePtr2 = szOneLine2;
        const char * szLineEnd2;

        // Read the next line
        nLength2 = ListFile_GetNextLine(pvListFile, szOneLine2, _maxchars(szOneLine2));
        if(nLength2 == 0)
            break;
        szLineEnd2 = szLinePtr2 + nLength2;

        // Parse all variables
        while(szLinePtr1 < szLineEnd1)
        {
            // Check for variables we need
            if(IsInfoVariable(szLinePtr1, szLineEnd1, "Active", "DEC"))
                LoadInfoVariable(&Active, szLinePtr2, szLineEnd2, false);
            if(IsInfoVariable(szLinePtr1, szLineEnd1, "Build Key", "HEX"))
                LoadInfoVariable(&hs->CdnBuildKey, szLinePtr2, szLineEnd2, true);
            if(IsInfoVariable(szLinePtr1, szLineEnd1, "CDN Key", "HEX"))
                LoadInfoVariable(&hs->CdnConfigKey, szLinePtr2, szLineEnd2, true);
            if(IsInfoVariable(szLinePtr1, szLineEnd1, "CDN Hosts", "STRING"))
                LoadInfoVariable(&CdnHost, szLinePtr2, szLineEnd2, false);
            if(IsInfoVariable(szLinePtr1, szLineEnd1, "CDN Path", "STRING"))
                LoadInfoVariable(&CdnPath, szLinePtr2, szLineEnd2, false);
            if(IsInfoVariable(szLinePtr1, szLineEnd1, "Tags", "STRING"))
                LoadInfoVariable(&TagString, szLinePtr2, szLineEnd2, false);

            // Move both line pointers
            szLinePtr1 = SkipInfoVariable(szLinePtr1, szLineEnd1);
            if(szLinePtr1 == NULL)
                break;

            szLinePtr2 = SkipInfoVariable(szLinePtr2, szLineEnd2);
            if(szLinePtr2 == NULL)
                break;
        }

        // Stop parsing if found active config
        if(Active.pbData != NULL && *Active.pbData == '1')
            break;

        // Free the blobs
        FreeCascBlob(&CdnHost);
        FreeCascBlob(&CdnPath);
        FreeCascBlob(&TagString);
    }

    // All four must be present
    if(hs->CdnBuildKey.pbData != NULL &&
       hs->CdnConfigKey.pbData != NULL &&
       CdnHost.pbData != NULL &&
       CdnPath.pbData != NULL)
    {
        // Merge the CDN host and CDN path
        hs->szUrlPath = CASC_ALLOC(TCHAR, CdnHost.cbData + CdnPath.cbData + 1);
        if(hs->szUrlPath != NULL)
        {
            CopyString(hs->szUrlPath, (char *)CdnHost.pbData, CdnHost.cbData);
            CopyString(hs->szUrlPath + CdnHost.cbData, (char *)CdnPath.pbData, CdnPath.cbData);
            nError = ERROR_SUCCESS;
        }
    }

    // If we found tags, we can extract language build from it
    if(TagString.pbData != NULL)
        GetDefaultLocaleMask(hs, &TagString);

    FreeCascBlob(&CdnHost);
    FreeCascBlob(&CdnPath);
    FreeCascBlob(&TagString);
    FreeCascBlob(&Active);
    return nError;
}
예제 #8
0
static int ParseFile_CdnBuild(TCascStorage * hs, void * pvListFile)
{
    const char * szLineBegin;
    const char * szLineEnd = NULL;
    int nError;

    // Initialize the size of the internal files
    ConvertIntegerToBytes_4(CASC_INVALID_SIZE, hs->EncodingFile.ContentSize);

    // Initialize the empty VFS array
    nError = hs->VfsRootList.Create<QUERY_KEY_PAIR>(0x10);
    if (nError != ERROR_SUCCESS)
        return nError;

    // Parse all variables
    while(ListFile_GetNextLine(pvListFile, &szLineBegin, &szLineEnd) != 0)
    {
        // Product name and build name
        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, "build-product", LoadBuildProduct, NULL))
            continue;
        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, "build-name", LoadBuildName, NULL))
            continue;

        // Content key of the ROOT file. Look this up in ENCODING to get the encoded key
        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, "root", LoadCkeyEkey, &hs->RootFile))
            continue;

        // Content key [+ encoded key] of the INSTALL file
        // If CKey is absent, you need to query the ENCODING file for it
        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, "install", LoadCkeyEkey, &hs->InstallFile))
            continue;

        // Content key [+ encoded key] of the DOWNLOAD file
        // If CKey is absent, you need to query the ENCODING file for it
        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, "download", LoadCkeyEkey, &hs->DownloadFile))
            continue;

        // Content key + encoded key of the ENCODING file. Contains CKey+EKey
        // If either none or 1 is found, the game (at least Wow) switches to plain-data(?). Seen in build 20173 
        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, "encoding", LoadCkeyEkey, &hs->EncodingFile))
            continue;

        // Content and encoded size of the ENCODING file. This helps us to determine size
        // of the ENCODING file better, as the size in the EKEY entries is almost always wrong on WoW storages
        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, "encoding-size", LoadCkeyEkeySize, &hs->EncodingFile))
            continue;

        // PATCH file
        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, "patch", LoadCkeyEkey, &hs->PatchFile))
            continue;

        // Load the CKey+EKey of a VFS root file (the root file of the storage VFS)
        if (CheckConfigFileVariable(hs, szLineBegin, szLineEnd, "vfs-root", LoadCkeyEkey, &hs->VfsRoot))
            continue;

        // Load the content size of the VFS root
        if (CheckConfigFileVariable(hs, szLineBegin, szLineEnd, "vfs-root-size", LoadCkeyEkeySize, &hs->VfsRoot))
            continue;

        // Load a directory entry to the VFS
        if(CheckConfigFileVariable(hs, szLineBegin, szLineEnd, "vfs-*", LoadVfsRootEntry, &hs->VfsRootList))
            continue;
    }

    // Both CKey and EKey of ENCODING file is required
    if(!IsValidMD5(hs->EncodingFile.CKey) || !IsValidMD5(hs->EncodingFile.EKey))
        return ERROR_BAD_FORMAT;
    return nError;
}