Services and Tools

Encode API Examples

These examples are taken from the actual repo usage patterns in demo/htjson and the public encode headers. They show the intended way to use Base64 helpers, DBind-backed JSON, and the URL parser.

Relevant Source Files

1. Startup Choice Depends On The Types You Serialize

For pure Base64, JSON, and URL parsing, encode_start() / encode_finish() is the right lifecycle pair. The htjson demo starts draw2d instead because it also serializes an Image, and that type's DBind registration lives in the graphics stack.

encode_start();
/* Base64 / JSON / URL work here */
encode_finish();

2. Base64 Encode And Decode

The repo exposes both raw-size helpers and high-level convenience wrappers. In normal application code, the wrapper forms are simpler.

String *b64 = b64_encode_from_cstr("hello");
Buffer *raw = b64_decode_from_str(b64);

/* use buffer_data(raw) / buffer_size(raw) */

buffer_destroy(&raw);
str_destroy(&b64);

There are equivalent wrappers for files, streams, raw byte arrays, and NAppGUI String values.

3. JSON Read And Write For Primitive Types

json_read(...) allocates the target value and returns a typed pointer. That is why even scalar values in demo/htjson are read as bool_t *, uint16_t *, and so on, then released with json_destroy(...).

Stream *stm = stm_from_block((const byte_t *)"true", 4);
bool_t *value = json_read(stm, NULL, bool_t);

/* *value == TRUE */

json_destroy(&value, bool_t);
stm_close(&stm);

4. DBind-Registered Structs

Structured JSON only works after the type has been described through DBind. That registration step is not optional; it is the schema the JSON layer uses at runtime.

typedef struct _product_t Product;
typedef struct _products_t Products;

struct _product_t {
    String *description;
    real32_t price;
};

struct _products_t {
    uint32_t size;
    ArrSt(Product) *data;
};

DeclSt(Product);

dbind(Product, String *, description);
dbind(Product, real32_t, price);
dbind(Products, uint32_t, size);
dbind(Products, ArrSt(Product) *, data);

Products *products = json_read(stm, NULL, Products);
json_destroy(&products, Products);

The same DBind metadata also drives json_write(...), so reading and writing stay symmetric.

5. Binary And Image Values Travel As Base64 Strings

The JSON implementation treats binary DBind values as Base64 strings. The htjson demo uses that path to round-trip an Image resource through JSON after starting draw2d.

ResPack *pack = res_htjson_respack("");
const byte_t *data = respack_file(pack, JSON_B64_IMAGE_TXT, &size);
Stream *stm = stm_from_block(data, size);

Image *image = json_read(stm, NULL, Image);

json_destroy(&image, Image);
stm_close(&stm);
respack_destroy(&pack);

6. Writing Directly To A String

If the caller wants the serialized payload as a NAppGUI string instead of a stream, use json_write_str(...).

String *json = json_write_str(products, NULL, Products);
/* use tc(json) */
str_destroy(&json);

7. URL Parsing And Resource Extraction

url_parse(...) is a structural splitter. It is most useful when you need the host/port plus the request resource path exactly the way inet expects it.

Url *url = url_parse("https://user:pass@example.com:8443/api/items?q=cpu#top");
String *resource = url_resource(url);

/* url_host(url)      -> "example.com" */
/* url_port(url)      -> 8443          */
/* tc(resource)       -> "/api/items?q=cpu#top" */

str_destroy(&resource);
url_destroy(&url);

Practical Notes

  • Unknown JSON object members: they are skipped, not treated as fatal schema errors.
  • Error logging: pass a JsonOpts with a log array to collect parser messages with row and column data.
  • Null handling: strings, containers, binary values, and struct-pointer members can be cleared by JSON null if DBind allows it.
  • Enums: JSON writes enum aliases, not raw integer ordinals.