Example #1
0
static int FetchAndVerifyConfigFile(TCascStorage * hs, PQUERY_KEY pFileKey, PQUERY_KEY pFileBlob)
{
    TCHAR * szFileName;
    int nError;

    // Construct the local file name
    szFileName = NewStr(hs->szDataPath, 8 + 3 + 3 + 32);
    if(szFileName == NULL)
        return ERROR_NOT_ENOUGH_MEMORY;

    // Add the part where the config file path is
    AppendConfigFilePath(szFileName, pFileKey);
    
    // Load the config file
    nError = LoadTextFile(szFileName, pFileBlob);
    if(nError == ERROR_SUCCESS)
    {
        // Verify the blob's MD5
        if(!VerifyDataBlockHash(pFileBlob->pbData, pFileBlob->cbData, pFileKey->pbData))
        {
            FreeCascBlob(pFileBlob);
            nError = ERROR_BAD_FORMAT;
        }
    }

    CASC_FREE(szFileName);
    return nError;
}
Example #2
0
// Checks whether there is a ".agent.db". If yes, the function
// sets "szRootPath" and "szDataPath" in the storage structure
// and returns ERROR_SUCCESS
int CheckGameDirectory(TCascStorage * hs, TCHAR * szDirectory)
{
    QUERY_KEY AgentFile;
    TCHAR * szFilePath;
    size_t nLength = 0;
    char * szValue;
    int nError = ERROR_FILE_NOT_FOUND;

    // Create the full name of the .agent.db file
    szFilePath = CombinePath(szDirectory, _T(".agent.db"));
    if(szFilePath != NULL)
    {
        // Load the file to memory
        nError = LoadTextFile(szFilePath, &AgentFile);
        if(nError == ERROR_SUCCESS)
        {
            // Extract the data directory from the ".agent.db" file
            szValue = ExtractStringVariable(&AgentFile, "data_dir", &nLength);
            if(szValue != NULL)
            {
                hs->szRootPath = CascNewStr(szDirectory, 0);
                hs->szDataPath = CombinePathAndString(szDirectory, szValue, nLength);
                nError = (hs->szDataPath != NULL) ? ERROR_SUCCESS : ERROR_NOT_ENOUGH_MEMORY;
            }

            // Free the loaded blob
            FreeCascBlob(&AgentFile);
        }

        // Freee the file path
        CASC_FREE(szFilePath);
    }

    return nError;
}
Example #3
0
static int ParseFile_BuildDb(TCascStorage * hs, void * pvListFile)
{
    QUERY_KEY TagString = {NULL, 0};
    CASC_CSV Csv;
    int nError;

    // Load the single line from the text file
    if(Csv.LoadNextLine(pvListFile) == 0)
        return ERROR_BAD_FORMAT;

    // Extract the CDN build key
    nError = Csv.GetData(hs->CdnBuildKey, 0, true);
    if (nError != ERROR_SUCCESS)
        return nError;

    // Load the CDN config key
    nError = Csv.GetData(hs->CdnConfigKey, 1, true);
    if (nError != ERROR_SUCCESS)
        return nError;

    // Load the the tags
    nError = Csv.GetData(TagString, 2, false);
    if (nError == ERROR_SUCCESS && TagString.pbData != NULL)
    {
        GetDefaultLocaleMask(hs, &TagString);
        FreeCascBlob(&TagString);
    }

    // Load the URL
    hs->szCdnList = Csv.GetString(3);
    if (hs->szCdnList == NULL)
        return ERROR_NOT_ENOUGH_MEMORY;

    // Verify all variables
    if (hs->CdnBuildKey.pbData == NULL || hs->CdnConfigKey.pbData == NULL)
        nError = ERROR_BAD_FORMAT;
    return nError;
}
Example #4
0
int LoadBuildInfo(TCascStorage * hs)
{
    QUERY_KEY InfoFile = {NULL, 0};
    QUERY_KEY FileData = {NULL, 0};
    TCHAR * szAgentFile;
    TCHAR * szInfoFile;
    bool bBuildConfigComplete = false;
    int nError = ERROR_SUCCESS;

    // Since HOTS build 30027, the game uses build.info file for storage info
    if(bBuildConfigComplete == false)
    {
        szInfoFile = CombinePath(hs->szRootPath, _T(".build.info"));
        if(szInfoFile != NULL)
        {
            nError = LoadTextFile(szInfoFile, &InfoFile);
            if(nError == ERROR_SUCCESS)
            {
                // Parse the info file
                nError = ParseInfoFile(hs, &InfoFile);
                if(nError == ERROR_SUCCESS)
                    bBuildConfigComplete = true;
                
                // Free the loaded blob
                FreeCascBlob(&InfoFile);
            }

            CASC_FREE(szInfoFile);
        }
    }

    // If the info file has not been loaded, try the legacy .build.db
    if(bBuildConfigComplete == false)
    {
        szAgentFile = CombinePath(hs->szRootPath, _T(".build.db"));
        if(szAgentFile != NULL)
        {
            nError = LoadTextFile(szAgentFile, &FileData);
            if(nError == ERROR_SUCCESS)
            {
                nError = ParseAgentFile(hs, &FileData);
                if(nError == ERROR_SUCCESS)
                    bBuildConfigComplete = true;

                FreeCascBlob(&FileData);
            }
            CASC_FREE(szAgentFile);
        }
    }

    // If the .build.info and .build.db file hasn't been loaded, 
    if(nError == ERROR_SUCCESS && bBuildConfigComplete == false)
    {
        nError = ERROR_FILE_CORRUPT;
    }

    // Load the configuration file
    if(nError == ERROR_SUCCESS)
    {
        nError = FetchAndVerifyConfigFile(hs, &hs->CdnConfigKey, &FileData);
        if(nError == ERROR_SUCCESS)
        {
            nError = LoadCdnConfigFile(hs, &FileData);
            FreeCascBlob(&FileData);
        }
    }

    // Load the build file
    if(nError == ERROR_SUCCESS)
    {
        nError = FetchAndVerifyConfigFile(hs, &hs->CdnBuildKey, &FileData);
        if(nError == ERROR_SUCCESS)
        {
            nError = LoadCdnBuildFile(hs, &FileData);
            FreeCascBlob(&FileData);
        }
    }

    // Fill the index directory
    if(nError == ERROR_SUCCESS)
    {
        // First, check for more common "data" subdirectory
        if((hs->szIndexPath = CheckForIndexDirectory(hs, _T("data"))) != NULL)
            return ERROR_SUCCESS;

        // Second, try the "darch" subdirectory (older builds of HOTS - Alpha)
        if((hs->szIndexPath = CheckForIndexDirectory(hs, _T("darch"))) != NULL)
            return ERROR_SUCCESS;

        nError = ERROR_FILE_NOT_FOUND;
    }

    return nError;
}
Example #5
0
static int ParseInfoFile(TCascStorage * hs, PQUERY_KEY pFileBlob)
{
    QUERY_KEY Active = {NULL, 0};
    QUERY_KEY TagString = {NULL, 0};
    QUERY_KEY CdnHost = {NULL, 0};
    QUERY_KEY CdnPath = {NULL, 0};
    const char * szLineBegin1 = NULL;
    const char * szLinePtr1 = NULL;
    const char * szLineBegin2 = NULL;
    const char * szLineEnd1 = NULL;
    const char * szLineEnd2 = NULL;
    const char * szFileEnd = (const char *)(pFileBlob->pbData + pFileBlob->cbData);
    const char * szFilePtr = (const char *)pFileBlob->pbData;
    int nError = ERROR_BAD_FORMAT;

    // Find the first line
    szLineBegin1 = szFilePtr;
    while(szFilePtr < szFileEnd)
    {
        // Check for the end of the line
        if(szFilePtr[0] == 0x0D || szFilePtr[0] == 0x0A)
        {
            szLineEnd1 = szFilePtr;
            break;
        }

        szFilePtr++;
    }

    while (szFilePtr < szFileEnd)
    {
        // Rewind header line pointers
        szLinePtr1 = szLineBegin1;

        // Skip the newline character(s)
        while (szFilePtr < szFileEnd && (szFilePtr[0] == 0x0D || szFilePtr[0] == 0x0A))
            szFilePtr++;

        // Find the next line
        szLineBegin2 = szFilePtr;
        while (szFilePtr < szFileEnd)
        {
            // Check for the end of the line
            if (szFilePtr[0] == 0x0D || szFilePtr[0] == 0x0A)
            {
                szLineEnd2 = szFilePtr;
                break;
            }

            szFilePtr++;
        }

        // Find the build key, CDN config key and the URL path
        while (szLinePtr1 < szLineEnd1)
        {
            // Check for variables we need
            if (IsInfoVariable(szLinePtr1, szLineEnd1, "Active", "DEC"))
                LoadInfoVariable(&Active, szLineBegin2, szLineEnd2, false);
            if (IsInfoVariable(szLinePtr1, szLineEnd1, "Build Key", "HEX"))
                LoadInfoVariable(&hs->CdnBuildKey, szLineBegin2, szLineEnd2, true);
            if (IsInfoVariable(szLinePtr1, szLineEnd1, "CDN Key", "HEX"))
                LoadInfoVariable(&hs->CdnConfigKey, szLineBegin2, szLineEnd2, true);
            if (IsInfoVariable(szLinePtr1, szLineEnd1, "CDN Hosts", "STRING"))
                LoadInfoVariable(&CdnHost, szLineBegin2, szLineEnd2, false);
            if (IsInfoVariable(szLinePtr1, szLineEnd1, "CDN Path", "STRING"))
                LoadInfoVariable(&CdnPath, szLineBegin2, szLineEnd2, false);
            if (IsInfoVariable(szLinePtr1, szLineEnd1, "Tags", "STRING"))
                LoadInfoVariable(&TagString, szLineBegin2, szLineEnd2, false);

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

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

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

    // 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);
    return nError;
}
Example #6
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;
}
Example #7
0
static int ParseFile_BuildInfo(TCascStorage * hs, void * pvListFile)
{
    CASC_CSV Csv;
    size_t Indices[4];
    char szActive[4];
    int nError;

    // Extract the first line, containing the headers
    if (Csv.LoadHeader(pvListFile) == 0)
        return ERROR_BAD_FORMAT;

    // Retrieve the column indices
    if (!Csv.GetColumnIndices(Indices, "Active!DEC:1", "Build Key!HEX:16", "CDN Key!HEX:16", NULL))
        return ERROR_BAD_FORMAT;

    // Find the active config
    for (;;)
    {
        // Load a next line
        if (Csv.LoadNextLine(pvListFile) == 0)
            break;

        // Is that build config active?
        if (Csv.GetString(szActive, 4, Indices[0]) == ERROR_SUCCESS && !strcmp(szActive, "1"))
        {
            // Retrieve the build key
            nError = Csv.GetData(hs->CdnBuildKey, Indices[1], true);
            if (nError != ERROR_SUCCESS)
                return nError;

            // Retrieve the config key
            nError = Csv.GetData(hs->CdnConfigKey, Indices[2], true);
            if (nError != ERROR_SUCCESS)
                return nError;

            // "CDN Servers"?
            if (Csv.GetColumnIndices(Indices, "CDN Servers!STRING:0", "CDN Path!STRING:0", NULL))
            {
                hs->szCdnList = MakeCdnList(Csv, Indices);
            }

            // "CDN Hosts"?
            else if (Csv.GetColumnIndices(Indices, "CDN Hosts!STRING:0", "CDN Path!STRING:0", NULL))
            {
                hs->szCdnList = MakeCdnList(Csv, Indices);
            }

            // If we found tags, we can extract language build from it
            if (Csv.GetColumnIndices(Indices, "Tags!STRING:0", NULL))
            {
                QUERY_KEY TagString = { NULL, 0 };

                if (Csv.GetData(TagString, Indices[0], false) == ERROR_SUCCESS && TagString.cbData != 0)
                {
                    GetDefaultLocaleMask(hs, &TagString);
                    FreeCascBlob(&TagString);
                }
            }

            // Build and Config keys are the ones we do really need
            return (hs->CdnConfigKey.cbData == MD5_HASH_SIZE && hs->CdnBuildKey.cbData == MD5_HASH_SIZE) ? ERROR_SUCCESS : ERROR_BAD_FORMAT;
        }
    }

    return ERROR_FILE_NOT_FOUND;
}