Common Data Types (Burnout Paradise)/CgsID Functions

From Burnout Wiki
Revision as of 05:31, 8 April 2022 by Burninrubber0 (talk | contribs) (Add line numbers.)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

This page lists C++ functions that can encode and decode the compressed strings Criterion uses. Though these functions are unofficial, the results are known to be accurate.

In the future, it may be worth simplifying the decompiled CgsIDCompress(), CgsIDUnCompress(), and CgsIDConvertToString() functions found in the DWARF symbols of certain development builds and listing them here instead.

Encode

#include <cstdint>
#include <iostream>
#include <string>

uint64_t encode(std::string id) {
    if (id.length() < 1) {
        std::cerr << "Error: No input to encode";
        return 0;
    }
    else if (id.length() > 12) {
        std::cerr << "Error: Input must be 12 characters or less";
        return 0;
    }
    
    uint64_t encoded = 0;

    if (id.length() < 13 && id.length() > 0) {
        for (int i = 0; i < 12; ++i) {
            char chr = 0;
            if (i < id.length())
                chr = id[i];
            if (chr == 0)
                chr = 32;

            if (chr == 95)
                encoded = encoded * 40 + 39;
            else if (chr >= 65)
                encoded = encoded * 40 + (chr - 52);
            else if (chr >= 48)
                encoded = encoded * 40 + (chr - 45);
            else if (chr >= 47)
                encoded = encoded * 40 + 2;
            else if (chr >= 45)
                encoded = encoded * 40 + 1;
            else
                encoded *= 40;
        }
    }

    return encoded;
}

Decode

Note that in Criterion's functions, trailing whitespace removal is done in CgsIDConvertToString().

#include <cstdint>
#include <string>

std::string decode(uint64_t id) {
    if (!id) // No data
        return "Invalid ID";
    
    std::string decoded = "";
    
    for (int i = 0; i < 12; ++i) {
        uint64_t mod = id % 40;
    
        if (mod == 39)
            decoded.insert(0, 1, '_');
        else if (mod >= 13)
            decoded.insert(0, 1, mod + 52);
        else if (mod >= 3)
            decoded.insert(0, 1, mod + 45);
        else if (mod >= 2)
            decoded.insert(0, 1, '/');
        else {
            mod = (mod - 1) & 32;
            decoded.insert(0, 1, mod);
        }
    
        id /= 40;
    }
    
    // Remove trailing spaces
    for (int i = 11; i >= 0; --i) {
        if (decoded.back() == 32)
            decoded.pop_back();
        else
            break;
    }
    
    return decoded;
}