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
JsonOptswith alogarray to collect parser messages with row and column data. - Null handling: strings, containers, binary values, and struct-pointer members can be cleared by JSON
nullif DBind allows it. - Enums: JSON writes enum aliases, not raw integer ordinals.