libebml_ng
Data Type Templates: Creating Custom EBML Data Types

This page describes how to implement a custom EBML data type using the provided CRTP templates, along with the helper functions such as ebml::size(), ebml::pack(), ebml::unpack() and ebml::repr(). These templates serve as the basis for the concrete type and element instances used in encoding and decoding EBML data.

Overview

The EBML library employs the CRTP (Curiously Recurring Template Pattern) (The CRTP Design Pattern) to simplify the process of subclassing ebml::ebmlElementType and ebml::ebmlElement. In particular, the templates:

Template instances for the following types are already provided:

To create a custom data type instance for EBML, you must provide implementations for the following template functions:

These functions are typically defined in the struct.h and repr.h and implemented in struct.tpp and repr.tpp.

Note
When implementing specializations for ebml::size(), ebml::pack and ebml::unpack, it is important that these specializations are declared before including struct.tpp.

Implementing a Custom EBML Data Type

To implement a custom EBML data type using these templates, follow these steps:

  1. Implement Template Functions
    Provide implementations (or overloads) for the functions:

    For example, the implementation of these functions for T = long long is provided in the file ll.h.

  2. Define a default value. Provide a value for T ebml::ebmlDataType<T>::defaultdefault. This can be done using the INST_EBML_CLS(T, defaultval) macro.
  3. Define the Data Type and Data Element Subclasses
    Use the provided CRTP templates to create your custom data type:
    • Define your data type by instantiating:

      ```c++ typedef ebml::ebmlDataType<long long> ebmlSignedIntegerType; ```

    • Define the corresponding element instance type:

      ```c++ typedef ebml::ebmlDataElement<long long> ebmlSignedInteger; ```

  1. Instantiate and Use Your Custom Type
    Once your functions are in place and the template classes are specialized (you can use macros like DECL_DATA_CLS(T) and INST_EBML_CLS(T, defaultval) to assist with declarations and instantiations), you can create and manipulate EBML elements of your custom type.

    Example:

{c++}
// Create an instance of the EBML type for signed integers.
ebmlSignedIntegerType myIntegerType(0x01, L"TestSignedInteger", -42);
// Use the type as a factory to create an element instance.
auto element = myIntegerType(-100);
// Encode the element into a raw data string.
std::string encoded = element->encode();
// Decode the raw data back into an element instance.
auto decodedElement = myIntegerType.decode(encoded);
// Retrieve the long long value from the element.
long long value = ebml::data<long long>(decodedElement);

Summary

The approach using CRTP templates in ebmlDataType<T> and ebmlDataElement<T> allows you to consistently implement new EBML data types. By implementing the helper functions (size(), pack(), and unpack()) for your particular data type, you integrate with the EBML framework, which then provides you with standardized methods for element creation, encoding/decoding, cloning, and representation.

This design enables a uniform, type-safe interface for working with EBML documents and simplifies the development of new EBML data types. /