AxlSidecar — JSON5 sidecar loader

Common scaffolding for JSON5 sidecar files — curated companion data shipped next to a .efi binary and loaded at startup. axl- sdk uses this for pci-ids.json5, pci-class.json5, usb-ids.json5, and jedec.json5; downstream consumers can build their own sidecars on top of the same primitives.

Three module-side concerns recur for every sidecar consumer, all provided by AxlSidecar:

  1. Open the file with a useful error-code split so the consumer can log “deployment problem” (file missing) and “authoring problem” (file present but malformed) differently.

  2. Validate the schema field — every sidecar in axl-sdk requires an explicit schema: N declaration so an old binary refuses to misparse a future-version file.

  3. Walk the typed entries into the consumer’s own table.

AxlSidecar owns concerns 1 and 2; concern 3 (schema-specific typed walk) stays with each consumer because the table shapes differ.

Internal axl-sdk modules also get a typed singleton wrapper and a hash-table foreach trampoline through axl-sidecar-internal.h (not part of the public API).

Quick start

#include <axl/axl-sidecar.h>

AxlJsonReader  r;
void          *raw;
AxlSidecarStatus rc = axl_sidecar_open_file("foo.json5", &r, &raw);
if (rc == AXL_SIDECAR_FILE_MISSING) {
    /* deployment hint */
} else if (rc == AXL_SIDECAR_PARSE_ERROR) {
    /* authoring hint */
} else {
    const uint64_t accepted[] = { 1u };
    uint64_t schema = 0;
    if (axl_sidecar_check_schema(&r, "foo", accepted, 1, &schema)
        == AXL_SIDECAR_OK)
    {
        /* schema 1 confirmed; walk fields and fill table */
    }
    axl_json_free(&r);
    axl_free(raw);
}

API Reference

Common scaffolding for JSON5 sidecar data files.

A sidecar in the axl-sdk idiom is a curated JSON5 companion file that ships next to a .efi binary (or in a known location relative to it) and provides a small lookup table the binary consults at startup. Examples that ship in the source tree:

  • share/pci-ids.json5 — PCI vendor / device / subsystem names

  • share/pci-class.json5 — PCI class-name overlay

  • share/jedec.json5 — JEDEC JEP-106 manufacturer codes

Three module-side concerns recur for every sidecar consumer:

  1. Open the file with a useful error-code split so the consumer can log “deployment problem” (file missing) and “authoring problem” (file exists but malformed) differently.

  2. Validate the schema field — every sidecar in axl-sdk requires an explicit schema: N declaration so an old binary can refuse to misparse a future-version file.

  3. Walk the typed entries into the consumer’s own table.

AxlSidecar owns concerns 1 and 2; concern 3 (schema-specific typed walk) stays with each consumer because the table shapes differ — PCI’s hierarchical vendors→devices→subsystems tree has nothing to share with SPD’s flat (code, name) list.

Internal axl-sdk modules also get a typed singleton wrapper and a hash-table foreach trampoline through axl-sidecar-internal.h (not part of the public API).

AxlJsonReader  r;
void          *raw;
AxlSidecarStatus rc = axl_sidecar_open_file("foo.json5", &r, &raw);
if (rc == AXL_SIDECAR_FILE_MISSING) { // log deployment hint
} else if (rc == AXL_SIDECAR_PARSE_ERROR) { // log authoring hint
} else {
    const uint64_t accepted[] = { 1u };
    uint64_t schema = 0;
    if (axl_sidecar_check_schema(&r, "foo", accepted,
                                 1, &schema) == AXL_SIDECAR_OK) {
        // schema 1 confirmed; walk fields and fill table
    }
    axl_json_free(&r);
    axl_free(raw);
}

Enums

enum AxlSidecarStatus

Outcome of a sidecar load / parse / schema-check call.

Numeric values are stable so legacy callers using if (rc != 0) / if (rc == -1) keep working at the ABI level — but new code (and every in-tree caller) compares against the named constants. Future code that writes -1 against a sidecar load API is wrong by construction.

The split between FILE_MISSING and PARSE_ERROR matters for diagnostics: a missing file is a deployment problem (probably fine to fall back to numeric IDs and continue silently), while a present-but-malformed file is an authoring problem worth being loud about.

Values:

enumerator AXL_SIDECAR_OK

success

enumerator AXL_SIDECAR_FILE_MISSING

file does not exist

enumerator AXL_SIDECAR_PARSE_ERROR

file exists but JSON5 / schema rejection

Functions

AxlSidecarStatus axl_sidecar_open_file(const char *path, AxlJsonReader *r, void **out_raw)

Open a JSON5 sidecar file with the standard error-code split.

Performs the same sequence axl-sdk modules previously hand-rolled: existence-check via axl_file_info (so we can distinguish “missing” from “parse failed”), then axl_json_load_file_flags with the AXL_JSON_PARSER_JSON5 grammar.

On AXL_SIDECAR_OK, the caller owns r and *out_raw and must release them with axl_json_free followed by axl_free respectively. On any error return both are left untouched (the caller does NOT free anything).

Parameters:
  • path – path to JSON5 file

  • r – [out] reader to populate

  • out_raw – [out] raw buffer the reader references; free with axl_free

Returns:

AXL_SIDECAR_OK on a successful parse, AXL_SIDECAR_FILE_MISSING if path does not exist or is unreadable, AXL_SIDECAR_PARSE_ERROR on JSON5 syntax failure.

AxlSidecarStatus axl_sidecar_open_buffer(const char *json5, size_t len, AxlJsonReader *r)

Parse a JSON5 sidecar from an in-memory buffer.

No AXL_SIDECAR_FILE_MISSING return — the buffer is the input, so “not found” doesn’t apply. Useful for embedded fixtures and unit tests.

On AXL_SIDECAR_OK, the caller owns r and must release it with axl_json_free (the buffer itself stays caller-owned — the reader references it but does not copy).

Parameters:
  • json5 – JSON5 source (no NUL required)

  • len – buffer length in bytes

  • r – [out] reader to populate

Returns:

AXL_SIDECAR_OK on a successful parse, AXL_SIDECAR_PARSE_ERROR on bad arguments or JSON5 failure.

AxlSidecarStatus axl_sidecar_check_schema(AxlJsonReader *r, const char *module_name, const uint64_t *accepted, size_t n_accepted, uint64_t *out_schema)

Read and validate the REQUIRED top-level schema field.

Every axl-sdk sidecar declares its layout version up front:

{ schema: 2, vendors: [...] }

Without this declaration, a v1 file could be silently misparsed by a v2-aware loader (or vice versa), producing entries that look present but are missing nested data. AxlSidecar requires the field; missing or unrecognized values trigger a uniform warning and an AXL_SIDECAR_PARSE_ERROR return. The warning text names module_name (e.g. “pci-ids”, “jedec”) so the operator knows which sidecar to fix.

accepted is a sorted list of the schema versions this loader knows how to parse; the consumer dispatches on *out_schema after the call returns AXL_SIDECAR_OK.

Parameters:
  • r – parsed reader at the document root

  • module_name – short tag for diagnostics (e.g. “pci-ids”)

  • accepted – array of schema versions we accept

  • n_accepted – length of accepted

  • out_schema – [out] selected schema version on OK

Returns:

AXL_SIDECAR_OK and *out_schema set on a recognized value, AXL_SIDECAR_PARSE_ERROR if the field is missing or not in accepted (with *out_schema unmodified).