From 6faa98c32a9024ffdff4dc1536a23febe73d1e0a Mon Sep 17 00:00:00 2001 From: Relintai Date: Sun, 14 Apr 2024 17:32:05 +0200 Subject: [PATCH] Backported from godot4: Save PackedByteArrays as base64 encoded. - groud https://github.com/godotengine/godot/commit/de5073519eb8085a1b0f9736a44dfe3e4ae1c561 --- core/variant/variant_parser.cpp | 90 ++++++++++++++++++++++-- core/variant/variant_parser.h | 1 + scene/resources/resource_format_text.cpp | 5 +- 3 files changed, 87 insertions(+), 9 deletions(-) diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp index 1b79fe446..9f5ccb6eb 100644 --- a/core/variant/variant_parser.cpp +++ b/core/variant/variant_parser.cpp @@ -31,6 +31,7 @@ #include "variant_parser.h" +#include "core/crypto/crypto_core.h" #include "core/input/input_event.h" #include "core/io/resource_loader.h" #include "core/os/keyboard.h" @@ -564,6 +565,82 @@ Error VariantParser::_parse_construct(Stream *p_stream, Vector &r_construct, return OK; } +Error VariantParser::_parse_byte_array(Stream *p_stream, Vector &r_construct, int &line, String &r_err_str) { + Token token; + get_token(p_stream, token, line, r_err_str); + if (token.type != TK_PARENTHESIS_OPEN) { + r_err_str = "Expected '(' in constructor"; + return ERR_PARSE_ERROR; + } + + get_token(p_stream, token, line, r_err_str); + if (token.type == TK_STRING) { + // Base64 encoded array. + String base64_encoded_string = token.value; + int strlen = base64_encoded_string.length(); + CharString cstr = base64_encoded_string.ascii(); + + size_t arr_len = 0; + r_construct.resize(strlen / 4 * 3 + 1); + uint8_t *w = r_construct.ptrw(); + Error err = CryptoCore::b64_decode(&w[0], r_construct.size(), &arr_len, (unsigned char *)cstr.get_data(), strlen); + if (err) { + r_err_str = "Invalid base64-encoded string"; + return ERR_PARSE_ERROR; + } + r_construct.resize(arr_len); + + get_token(p_stream, token, line, r_err_str); + if (token.type != TK_PARENTHESIS_CLOSE) { + r_err_str = "Expected ')' in constructor"; + return ERR_PARSE_ERROR; + } + + } else if (token.type == TK_NUMBER || token.type == TK_IDENTIFIER) { + // Individual elements. + while (true) { + if (token.type != TK_NUMBER) { + bool valid = false; + if (token.type == TK_IDENTIFIER) { + double real = stor_fix(token.value); + if (real != -1) { + token.type = TK_NUMBER; + token.value = real; + valid = true; + } + } + if (!valid) { + r_err_str = "Expected number in constructor"; + return ERR_PARSE_ERROR; + } + } + + r_construct.push_back(token.value); + + get_token(p_stream, token, line, r_err_str); + + if (token.type == TK_COMMA) { + //do none + } else if (token.type == TK_PARENTHESIS_CLOSE) { + break; + } else { + r_err_str = "Expected ',' or ')' in constructor"; + return ERR_PARSE_ERROR; + } + + get_token(p_stream, token, line, r_err_str); + } + } else if (token.type == TK_PARENTHESIS_CLOSE) { + // Empty array. + return OK; + } else { + r_err_str = "Expected base64 string, or list of numbers in constructor"; + return ERR_PARSE_ERROR; + } + + return OK; +} + Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser) { if (token.type == TK_CURLY_BRACKET_OPEN) { Dictionary d; @@ -998,7 +1075,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } } else if (id == "PoolByteArray" || id == "ByteArray") { Vector args; - Error err = _parse_construct(p_stream, args, line, r_err_str); + Error err = _parse_byte_array(p_stream, args, line, r_err_str); if (err) { return err; } @@ -1874,12 +1951,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str int len = data.size(); PoolVector::Read r = data.read(); const uint8_t *ptr = r.ptr(); - for (int i = 0; i < len; i++) { - if (i > 0) { - p_store_string_func(p_store_string_ud, ", "); - } - - p_store_string_func(p_store_string_ud, itos(ptr[i])); + + if (data.size() > 0) { + p_store_string_func(p_store_string_ud, "\""); + p_store_string_func(p_store_string_ud, CryptoCore::b64_encode_str(ptr, len)); + p_store_string_func(p_store_string_ud, "\""); } p_store_string_func(p_store_string_ud, " )"); diff --git a/core/variant/variant_parser.h b/core/variant/variant_parser.h index b77bed5a8..86680c25e 100644 --- a/core/variant/variant_parser.h +++ b/core/variant/variant_parser.h @@ -149,6 +149,7 @@ private: template static Error _parse_construct(Stream *p_stream, Vector &r_construct, int &line, String &r_err_str); + static Error _parse_byte_array(Stream *p_stream, Vector &r_construct, int &line, String &r_err_str); static Error _parse_enginecfg(Stream *p_stream, Vector &strings, int &line, String &r_err_str); static Error _parse_dictionary(Dictionary &object, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser = nullptr); static Error _parse_array(Array &array, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser = nullptr); diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 783b840f3..3b366e108 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -36,8 +36,9 @@ #include "core/os/dir_access.h" #include "core/version.h" -//version 2: changed names for basis, aabb, poolvectors, etc. -#define FORMAT_VERSION 2 +// Version 2: changed names for basis, aabb, poolvectors, etc. +// Version 3: PoolByteArray is now stored as base64 encoded. +#define FORMAT_VERSION 3 #include "core/os/dir_access.h" #include "core/version.h"