Skip to content

Commit

Permalink
byml: Add support for v4 Binary nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
leoetlino committed Mar 21, 2020
1 parent 09e4e7d commit 09aaab1
Show file tree
Hide file tree
Showing 6 changed files with 622 additions and 10 deletions.
33 changes: 26 additions & 7 deletions src/byml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ static_assert(sizeof(ResHeader) == 0x10);

enum class NodeType : u8 {
String = 0xa0,
Binary = 0xa1,
Array = 0xc0,
Hash = 0xc1,
StringTable = 0xc2,
Expand All @@ -70,9 +71,9 @@ enum class NodeType : u8 {

constexpr NodeType GetNodeType(Byml::Type type) {
constexpr std::array map{
NodeType::Null, NodeType::String, NodeType::Array, NodeType::Hash,
NodeType::Bool, NodeType::Int, NodeType::Float, NodeType::UInt,
NodeType::Int64, NodeType::UInt64, NodeType::Double,
NodeType::Null, NodeType::String, NodeType::Binary, NodeType::Array,
NodeType::Hash, NodeType::Bool, NodeType::Int, NodeType::Float,
NodeType::UInt, NodeType::Int64, NodeType::UInt64, NodeType::Double,
};
return map[u8(type)];
}
Expand All @@ -89,7 +90,7 @@ constexpr bool IsLongType(T type) {

template <typename T = NodeType>
constexpr bool IsNonInlineType(T type) {
return IsContainerType(type) || IsLongType(type);
return IsContainerType(type) || IsLongType(type) || type == T::Binary;
}

constexpr bool IsValidVersion(int version) {
Expand Down Expand Up @@ -177,6 +178,12 @@ class Parser {
switch (type) {
case NodeType::String:
return m_string_table.GetString(m_reader, *raw);
case NodeType::Binary: {
const u32 data_offset = *raw;
const u32 size = m_reader.Read<u32>(data_offset).value();
return Byml{std::vector<u8>(m_reader.span().begin() + data_offset + 4,
m_reader.span().begin() + data_offset + 4 + size)};
}
case NodeType::Bool:
return *raw != 0;
case NodeType::Int:
Expand Down Expand Up @@ -296,6 +303,10 @@ struct WriteContext {
return writer.Write<u32>(0);
case Byml::Type::String:
return writer.Write<u32>(string_table.GetIndex(data.GetString()));
case Byml::Type::Binary:
writer.Write(static_cast<u32>(data.GetBinary().size()));
writer.WriteBytes(data.GetBinary());
return;
case Byml::Type::Bool:
return writer.Write<u32>(data.GetBool());
case Byml::Type::Int:
Expand Down Expand Up @@ -369,10 +380,10 @@ struct WriteContext {
const size_t offset = writer.Tell();
writer.RunAt(node.offset_in_container, [&](size_t) { writer.Write<u32>(offset); });
non_inline_node_data.emplace(*node.data, offset);
if (IsLongType(node.data->GetType()))
WriteValueNode(*node.data);
else
if (IsContainerType(node.data->GetType()))
WriteContainerNode(*node.data);
else
WriteValueNode(*node.data);
}
}
}
Expand Down Expand Up @@ -472,6 +483,10 @@ Byml::String& Byml::GetString() {
return Get<Type::String>();
}

std::vector<u8>& Byml::GetBinary() {
return Get<Type::Binary>();
}

const Byml::Hash& Byml::GetHash() const {
return Get<Type::Hash>();
}
Expand All @@ -484,6 +499,10 @@ const Byml::String& Byml::GetString() const {
return Get<Type::String>();
}

const std::vector<u8>& Byml::GetBinary() const {
return Get<Type::Binary>();
}

bool Byml::GetBool() const {
return Get<Type::Bool>();
}
Expand Down
22 changes: 21 additions & 1 deletion src/byml_text.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/

#include <absl/algorithm/container.h>
#include <absl/strings/escaping.h>
#include <absl/strings/str_format.h>

#include <c4/std/string.hpp>
Expand All @@ -33,19 +34,33 @@
namespace oead {

namespace byml {
static bool IsBinaryTag(std::string_view tag) {
return util::IsAnyOf(tag, "tag:yaml.org,2002:binary", "!!binary");
}

static std::optional<yml::TagBasedType> RecognizeTag(const std::string_view tag) {
if (util::IsAnyOf(tag, "!f64"))
return yml::TagBasedType::Float;
if (util::IsAnyOf(tag, "!u", "!l", "!ul"))
return yml::TagBasedType::Int;
if (IsBinaryTag(tag))
return yml::TagBasedType::Str;
return std::nullopt;
}

static Byml ScalarToValue(std::string_view tag, yml::Scalar&& scalar) {
return util::Match(
std::move(scalar), [](std::nullptr_t) -> Byml { return Byml::Null{}; },
[](bool value) -> Byml { return value; },
[](std::string&& value) -> Byml { return std::move(value); },
[&](std::string&& value) -> Byml {
if (IsBinaryTag(tag)) {
std::string decoded;
if (!absl::Base64Unescape(value, &decoded))
throw InvalidDataError("Invalid base64-encoded data");
return Byml{std::vector<u8>(decoded.begin(), decoded.end())};
}
return Byml{std::move(value)};
},
[&](u64 value) -> Byml {
if (tag == "!u")
return U32(value);
Expand Down Expand Up @@ -126,6 +141,11 @@ std::string Byml::ToText() const {
util::Match(
node.GetVariant().v, [&](Null) { emitter.EmitNull(); },
[&](const String& v) { emitter.EmitString(v); },
[&](const std::vector<u8>& v) {
const std::string encoded =
absl::Base64Escape(std::string_view((const char*)v.data(), v.size()));
emitter.EmitString(encoded, "tag:yaml.org,2002:binary");
},
[&](const Array& v) {
yaml_event_t event;
const auto style = byml::ShouldUseInlineYamlStyle(v) ? YAML_FLOW_SEQUENCE_STYLE :
Expand Down
8 changes: 6 additions & 2 deletions src/include/oead/byml.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class Byml {
enum class Type {
Null = 0,
String,
Binary,
Array,
Hash,
Bool,
Expand All @@ -59,8 +60,9 @@ class Byml {
using Array = std::vector<Byml>;
using Hash = absl::btree_map<std::string, Byml>;

using Value = util::Variant<Type, Null, std::unique_ptr<String>, std::unique_ptr<Array>,
std::unique_ptr<Hash>, bool, S32, F32, U32, S64, U64, F64>;
using Value = util::Variant<Type, Null, std::unique_ptr<String>, std::unique_ptr<std::vector<u8>>,
std::unique_ptr<Array>, std::unique_ptr<Hash>, bool, S32, F32, U32,
S64, U64, F64>;

Byml() = default;
Byml(const Byml& other) { *this = other; }
Expand Down Expand Up @@ -137,9 +139,11 @@ class Byml {
Hash& GetHash();
Array& GetArray();
String& GetString();
std::vector<u8>& GetBinary();
const Hash& GetHash() const;
const Array& GetArray() const;
const String& GetString() const;
const std::vector<u8>& GetBinary() const;
bool GetBool() const;
s32 GetInt() const;
u32 GetUInt() const;
Expand Down
1 change: 1 addition & 0 deletions src/yaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ void InitRymlIfNeeded() {
LibyamlEmitter::LibyamlEmitter() {
yaml_emitter_initialize(&m_emitter);
yaml_emitter_set_unicode(&m_emitter, 1);
yaml_emitter_set_width(&m_emitter, 120);
}

LibyamlEmitter::~LibyamlEmitter() {
Expand Down
Binary file added test/byml/files/Preset0_Field.byml
Binary file not shown.
Loading

0 comments on commit 09aaab1

Please sign in to comment.