Working with YAML Binary Data and Base64 Encoding in yaml-cpp

yaml-cpp automatically handles binary data by encoding it as Base64 strings using the YAML::Binary class, enabling seamless serialization and deserialization of raw byte sequences through the public Node and Emitter APIs.

When working with the jbeder/yaml-cpp library, handling raw binary data requires special consideration since YAML is a text-based format. The library provides first-class support for binary blobs through the YAML::Binary class, which automatically manages Base64 encoding during emission and decoding during parsing. This integration allows you to work with binary data as naturally as you would with strings or integers.

Understanding the YAML::Binary Class

Located in include/yaml-cpp/binary.h, the YAML::Binary class serves as the primary container for binary data. It can hold either owned data via std::vector<unsigned char> or maintain a reference to unowned data through a pointer and size pair. The class provides essential methods including size(), data(), and swap(), along with equality comparison operators and copy utilities.

How Base64 Encoding and Decoding Works

The actual Base64 implementation resides in src/binary.cpp. The EncodeBase64 function (lines 9-44) processes the byte stream by mapping every 3-byte chunk to 4 Base64 characters, implementing the standard RFC 4648 encoding. For decoding, DecodeBase64 (lines 68-106) validates padding characters, skips whitespace, and reconstructs the original byte sequence. These functions are pure C++ implementations used internally by the conversion and emitter systems.

Emitting Binary Data with the Emitter

When emitting binary data, the Emitter class (defined in include/yaml-cpp/emitter.h) provides the Write(const Binary&) method and stream operator overloads. These forward to low-level utilities in src/emitterutils.cpp such as WriteBinary, WriteLiteralBinary, and WriteSingleQuotedBinary. These helpers invoke EncodeBase64 and automatically apply the !!binary tag to the output scalar, ensuring standards-compliant YAML output.

Parsing Binary Scalars from Nodes

The integration with the Node API happens through the convert<Binary> specialization in include/yaml-cpp/node/convert.h (lines 94-103). When you call Node::as<YAML::Binary>(), the conversion specialization reads the scalar value, passes it to DecodeBase64, and swaps the resulting vector into the Binary object. This allows automatic decoding of Base64 strings back into raw bytes without manual intervention.

Complete Code Examples

Emitting Binary Data

#include <yaml-cpp/yaml.h>
#include <iostream>

int main() {
    // Sample binary payload
    const unsigned char payload[] = {0x48, 0x65, 0x6c, 0x6c, 0x6f}; // "Hello"

    YAML::Binary bin(payload, sizeof(payload));

    YAML::Emitter out;
    out << YAML::BeginMap
        << YAML::Key << "greeting"
        << YAML::Value << bin          // <-- binary is emitted as Base64
        << YAML::EndMap;

    std::cout << out.c_str() << std::endl;
    /* Output:
       greeting: !!binary |
         SGVsbG8=
    */
}

The emitter automatically adds the !!binary tag and encodes the payload using the implementation in src/emitterutils.cpp.

Parsing Base64-Encoded Scalars

#include <yaml-cpp/yaml.h>
#include <iostream>

int main() {
    const std::string yaml = R"(
        picture: !!binary |
          iVBORw0KGgoAAAANSUhEUgAAAAUA
          AAAFCAYAAACNbyblAAAAHElEQVQI12P4
          //8/w38GIAXDIBKE0DHxgljNBAAO
          9TXL0Y4OHwAAAABJRU5ErkJggg==
    )";

    YAML::Node root = YAML::Load(yaml);
    YAML::Binary bin = root["picture"].as<YAML::Binary>(); // <-- decoded automatically

    // Access raw bytes
    const unsigned char* data = bin.data();
    std::size_t size = bin.size();

    std::cout << "Decoded " << size << " bytes.\n";
}

The as<YAML::Binary>() call triggers convert<Binary>::decode, which internally runs DecodeBase64 from src/binary.cpp.

Mixing Binary with Other Types

YAML::Emitter out;
out << YAML::BeginSeq
    << "plain text"
    << YAML::Binary("\x01\x02\x03", 3)  // will be emitted as base64
    << 42
    << YAML::EndSeq;

The emitter detects the type at compile-time and selects the appropriate Write...Binary helper from src/emitterutils.cpp.

Summary

  • The YAML::Binary class in include/yaml-cpp/binary.h encapsulates binary data as either owned or unowned byte sequences.
  • Base64 encoding and decoding are implemented in src/binary.cpp via EncodeBase64 (lines 9-44) and DecodeBase64 (lines 68-106).
  • The convert<Binary> specialization in include/yaml-cpp/node/convert.h enables automatic conversion between YAML nodes and binary data.
  • The Emitter class automatically applies the !!binary tag and handles Base64 encoding when writing binary scalars.
  • Binary data can be mixed seamlessly with other YAML types in sequences and mappings.

Frequently Asked Questions

How does yaml-cpp store binary data internally?

According to the source code in include/yaml-cpp/binary.h, the YAML::Binary class stores binary data as a std::vector<unsigned char> for owned data, or maintains a pointer and size for unowned data references. This dual approach allows efficient handling of both standalone binary objects and views into existing memory buffers without unnecessary copying.

What Base64 variant does yaml-cpp use?

The implementation in src/binary.cpp uses standard Base64 encoding with padding characters as defined in RFC 4648. The EncodeBase64 function maps 3-byte input chunks to 4-character output blocks, while DecodeBase64 validates padding and skips whitespace during parsing, ensuring compatibility with standard YAML binary scalars.

Can I decode Base64 strings manually without using YAML::Binary?

The DecodeBase64 function in src/binary.cpp is an internal implementation detail. The recommended approach is to use YAML::Load to parse the YAML document and then call Node::as<YAML::Binary>() to trigger the conversion specialization in include/yaml-cpp/node/convert.h, which handles the decoding automatically through the convert<Binary> template.

Does yaml-cpp support other binary encodings besides Base64?

The source code analysis shows that yaml-cpp specifically implements Base64 encoding for binary data to comply with the YAML 1.2 specification. The !!binary tag automatically triggers Base64 processing, and there is no built-in support for alternative encodings like hexadecimal or base85 in the current implementation.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →