summaryrefslogtreecommitdiff
path: root/src/factories/bk64/BKEmitText.h
blob: feab5d8c34f1d4c6f9312b078292c038f7e21bfc (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
#pragma once

#include <cctype>
#include <cstdint>
#include <cstdio>
#include <iomanip>
#include <string>
#include <yaml-cpp/yaml.h>

// Shared yaml/text emission formatters
#define YAML_HEX(num) YAML::Hex << (num) << YAML::Dec
#define FORMAT_HEX(x, w) \
    std::hex << std::uppercase << std::setfill('0') << std::setw(w) << x << std::nouppercase << std::dec

namespace BK64 {

// Emit a text string for modding yaml.
inline void EmitText(YAML::Emitter& out, const std::string& str) {
    const char* s = str.c_str();
    bool plain = true;
    for (const char* p = s; *p != '\0'; p++) {
        if (static_cast<uint8_t>(*p) < 0x20 || static_cast<uint8_t>(*p) > 0x7E || *p == '\\') {
            plain = false;
            break;
        }
    }
    if (plain) {
        out << YAML::DoubleQuoted << s;
        return;
    }
    std::string escaped;
    for (const char* p = s; *p != '\0'; p++) {
        const auto c = static_cast<uint8_t>(*p);
        if (c == '\\') {
            escaped += "\\\\";
        } else if (c < 0x20 || c > 0x7E) {
            char buf[5];
            std::snprintf(buf, sizeof(buf), "\\x%02X", c);
            escaped += buf;
        } else {
            escaped += static_cast<char>(c);
        }
    }
    out << YAML::SingleQuoted << escaped;
}

// Reverse EmitText's escapes on a string read back from modding yaml.
inline std::string DecodeText(const std::string& str) {
    std::string out;
    out.reserve(str.size());
    for (size_t i = 0; i < str.size(); i++) {
        if (str[i] == '\\' && i + 1 < str.size()) {
            if (str[i + 1] == '\\') {
                out += '\\';
                i++;
                continue;
            }
            if ((str[i + 1] == 'x' || str[i + 1] == 'X') && i + 3 < str.size() &&
                std::isxdigit(static_cast<unsigned char>(str[i + 2])) &&
                std::isxdigit(static_cast<unsigned char>(str[i + 3]))) {
                out += static_cast<char>(std::stoi(str.substr(i + 2, 2), nullptr, 16));
                i += 3;
                continue;
            }
        }
        out += str[i];
    }
    return out;
}

} // namespace BK64