Common Data Types (Burnout Paradise)/CgsID Functions

From Burnout Wiki

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;
}