# How VentoyPlugson Parses JSON Plugin Configuration Files: A Deep Dive into the Source Code

> Explore how VentoyPlugson parses JSON plugin configuration files. Learn about tokenization, JSON tree structures, and specialized handlers in this deep dive into the source code.

- Repository: [longpanda/Ventoy](https://github.com/ventoy/Ventoy)
- Tags: deep-dive
- Published: 2026-03-01

---

**VentoyPlugson parses JSON plugin configuration by loading [`ventoy.json`](https://github.com/ventoy/Ventoy/blob/main/ventoy.json) into memory, tokenizing it into a recursive `VTOY_JSON` tree structure, and dispatching top-level blocks to specialized handlers via the `ventoy_parse_json` macro that maps configuration sections to internal data structures.**

VentoyPlugson manages multiboot USB configurations through a centralized JSON-based plugin system. Understanding how VentoyPlugson parses JSON plugin configuration files reveals the architecture behind its flexible boot management and web-based configuration interface.

## Overview of the JSON Parsing Pipeline

The parsing pipeline operates through three distinct layers that transform raw disk bytes into structured configuration data.

### The Three-Layer Architecture

| Layer | Responsibility | Main Source |
|-------|----------------|-------------|
| **I/O Layer** | Locate and read [`ventoy.json`](https://github.com/ventoy/Ventoy/blob/main/ventoy.json) into memory | `ventoy_load_old_json()` in [[`Plugson/src/Web/ventoy_http.c`](https://github.com/ventoy/Ventoy/blob/main/Plugson/src/Web/ventoy_http.c)](https://github.com/ventoy/Ventoy/blob/master/Plugson/src/Web/ventoy_http.c#L5271-L5330) |
| **Tokenization Layer** | Convert raw text into a linked node tree (`VTOY_JSON`) | `vtoy_json_parse*()` in [[`Plugson/src/Core/ventoy_json.c`](https://github.com/ventoy/Ventoy/blob/main/Plugson/src/Core/ventoy_json.c)](https://github.com/ventoy/Ventoy/blob/master/Plugson/src/Core/ventoy_json.c#L3324-L3398) |
| **Domain Mapping Layer** | Walk the tree, match block names, fill internal structures | `ventoy_parse_json` macro and `ventoy_parse_*()` functions in [[`Plugson/src/Web/ventoy_http.c`](https://github.com/ventoy/Ventoy/blob/main/Plugson/src/Web/ventoy_http.c)](https://github.com/ventoy/Ventoy/blob/master/Plugson/src/Web/ventoy_http.c#L4085-L5340) and helper macros in [[`Plugson/src/Web/ventoy_http.h`](https://github.com/ventoy/Ventoy/blob/main/Plugson/src/Web/ventoy_http.h)](https://github.com/ventoy/Ventoy/blob/master/Plugson/src/Web/ventoy_http.h#L389-L406) |

## Step 1: Loading the ventoy.json File

The entry point `ventoy_load_old_json()` handles file system interaction and initial buffer preparation.

```c
int ventoy_load_old_json(const char *filename)
{
    /* read whole file → buffer */
    ventoy_read_file_to_buf(filename, 4, (void **)&buffer, &buflen);
    /* strip optional UTF‑8 BOM */
    /* … */
    /* create root node */
    json = vtoy_json_create();
    /* parse the text */
    vtoy_json_parse_ex(json, buffer + offset, buflen - offset);
    /* … iterate over children */
}

```

This function resides in [[`ventoy_http.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_http.c)](https://github.com/ventoy/Ventoy/blob/master/Plugson/src/Web/ventoy_http.c#L5271-L5311) and serves as the bridge between persistent storage and the parser.

## Step 2: JSON Tokenization and Tree Construction

Once loaded, the raw buffer undergoes recursive descent parsing to build an in-memory tree representation.

### The VTOY_JSON Node Structure

Each node in the tree is defined in [[`Plugson/src/Core/ventoy_json.h`](https://github.com/ventoy/Ventoy/blob/main/Plugson/src/Core/ventoy_json.h)](https://github.com/ventoy/Ventoy/blob/master/Plugson/src/Core/ventoy_json.h#L95-L111):

```c
typedef struct tagVTOY_JSON {
    struct tagVTOY_JSON *pstPrev, *pstNext, *pstChild;
    JSON_TYPE enDataType;                 // number, string, object, array, bool, null
    union {
        char  *pcStrVal;   // for strings
        int    iNumVal;    // for numbers (int)
        uint64_t lValue;   // for numbers (uint64)
    } unData;
    char *pcName;                         // key name (NULL for root)
} VTOY_JSON;

```

### Recursive Descent Parsing

The parser implements a hand-written recursive descent algorithm:

- **`vtoy_json_parse_value()`** dispatches based on the first character (`{`, `[`, `"`, digit, `t/f/n`) — located in [[`ventoy_json.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_json.c)](https://github.com/ventoy/Ventoy/blob/master/Plugson/src/Core/ventoy_json.c#L3324-L3379).
- **`vtoy_json_parse_object()`** handles objects (`{ … }`) by creating child nodes for each key/value pair — found in [[`ventoy_json.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_json.c)](https://github.com/ventoy/Ventoy/blob/master/Plugson/src/Core/ventoy_json.c#L3111-L3229).
- **`vtoy_json_parse_array()`** processes arrays (`[ … ]`) analogously — located in [[`ventoy_json.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_json.c)](https://github.com/ventoy/Ventoy/blob/master/Plugson/src/Core/ventoy_json.c#L2870-L2919).

## Step 3: Domain-Specific Configuration Parsing

After tokenization, the generic tree must be mapped to Ventoy's internal configuration structures.

### The ventoy_parse_json Macro Dispatcher

The mapping relies on a sophisticated macro defined in [[`Plugson/src/Web/ventoy_http.h`](https://github.com/ventoy/Ventoy/blob/main/Plugson/src/Web/ventoy_http.h)](https://github.com/ventoy/Ventoy/blob/master/Plugson/src/Web/ventoy_http.h#L389-L406):

```c
#define ventoy_parse_json(name)                           \
{                                                         \
    int __len = (int)strlen(#name);                        \
    if (strncmp(#name, node->pcName, __len) == 0) {       \
        for (__loop = 0; __loop < bios_max; __loop++) {   \
            if (strcmp(g_json_title_postfix[__loop],        \
                       node->pcName + __len) == 0) {      \
                vlog("json parse <%s>\n", node->pcName);   \
                ventoy_parse_##name(node,                \
                    g_data_##name + __loop);              \
                break;                                    \
            }                                             \
        }                                                 \
    }                                                     \
}

```

This macro performs several critical functions:

- **Stringification**: Uses `#name` to generate the block identifier (e.g., `"control"`).
- **BIOS/UEFI Variant Detection**: Compares against `g_json_title_postfix[]` (containing `"_legacy"`, `"_uefi"`, etc.) to handle mode-specific configurations.
- **Dispatch**: Calls the concrete parser `ventoy_parse_##name` (e.g., `ventoy_parse_control`) and passes the appropriate storage slot from `g_data_##name`.

### Block-Specific Handlers

Each configuration block implements a dedicated parser. For example, `ventoy_parse_control()` in [[`ventoy_http.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_http.c)](https://github.com/ventoy/Ventoy/blob/master/Plugson/src/Web/ventoy_http.c#L4108-L4249) processes the control block:

```c
static int ventoy_parse_control(VTOY_JSON *json, void *p)
{
    data_control *data = (data_control *)p;
    VTOY_JSON *node = json->pstChild;

    while (node) {
        if (strcmp(node->pcName, "VTOY_DEFAULT_MENU_MODE") == 0) {
            CONTROL_PARSE_INT_DEF_0(node, data->default_menu_mode);
        }
        /* … additional key processing … */
        node = node->pstNext;
    }
    return 0;
}

```

Helper macros like `CONTROL_PARSE_INT_DEF_0` wrap the generic JSON getters (`vtoy_json_get_int`, `vtoy_json_get_string`) to populate the internal data structures with type safety and default value handling.

## Runtime JSON Handling for Web UI

The same parsing infrastructure handles runtime configuration updates. When the Plugson web UI sends a POST request to `/vtoy/json`:

1. The server reads the POST body into `post_data_buf`.
2. Creates a fresh `VTOY_JSON` root via `vtoy_json_create()`.
3. Parses the payload using `vtoy_json_parse()`.
4. Dispatches to `ventoy_json_handler()`, which extracts the `"method"` field and routes to the appropriate API callback (e.g., `ventoy_api_save_theme`).

This ensures configuration changes made through the browser undergo the same validation and parsing as the static configuration file.

## Practical Example: Reading Configuration Values

The following standalone example demonstrates how to reuse the Ventoy JSON library to read configuration values:

```c
#include "ventoy_json.h"
#include <stdio.h>

int main(void)
{
    const char *filename = "ventoy.json";
    char *buf = NULL;
    int len, ret;
    VTOY_JSON *root = NULL;
    int timeout;

    /* 1. Load file into memory (simplified) */
    FILE *fp = fopen(filename, "rb");
    fseek(fp, 0, SEEK_END);
    len = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    buf = malloc(len + 1);
    fread(buf, 1, len, fp);
    buf[len] = '\0';
    fclose(fp);

    /* 2. Parse */
    root = vtoy_json_create();
    ret = vtoy_json_parse_ex(root, buf, len);
    if (ret != JSON_SUCCESS) {
        fprintf(stderr, "Parse error\n");
        return 1;
    }

    /* 3. Query a key inside the "control_uefi" block */
    VTOY_JSON *control = vtoy_json_find_item(root, JSON_TYPE_OBJECT, "control_uefi");
    if (control) {
        vtoy_json_get_int(control, "timeout", &timeout);
        printf("UEFI timeout = %d seconds\n", timeout);
    }

    vtoy_json_destroy(root);
    free(buf);
    return 0;
}

```

Key API functions demonstrated:
- `vtoy_json_create()` – Allocates the root node.
- `vtoy_json_parse_ex()` – Parses a raw buffer of known length.
- `vtoy_json_find_item()` – Locates a specific object by name.
- `vtoy_json_get_int()` – Extracts a numeric field.

## Summary

- **VentoyPlugson** stores configuration in a single [`ventoy.json`](https://github.com/ventoy/Ventoy/blob/main/ventoy.json) file parsed through a three-layer pipeline.
- **File I/O** is handled by `ventoy_load_old_json()` in [`Plugson/src/Web/ventoy_http.c`](https://github.com/ventoy/Ventoy/blob/main/Plugson/src/Web/ventoy_http.c), which reads the file and strips UTF-8 BOM markers.
- **Tokenization** converts raw text into a linked `VTOY_JSON` tree using recursive descent parsing in [`Plugson/src/Core/ventoy_json.c`](https://github.com/ventoy/Ventoy/blob/main/Plugson/src/Core/ventoy_json.c).
- **Domain mapping** uses the `ventoy_parse_json` macro in [`Plugson/src/Web/ventoy_http.h`](https://github.com/ventoy/Ventoy/blob/main/Plugson/src/Web/ventoy_http.h) to dispatch top-level blocks (e.g., `control_uefi`) to specialized handlers like `ventoy_parse_control()`.
- **Runtime updates** reuse the same parser for POST requests from the web UI, ensuring consistent validation between file-based and interactive configuration.

## Frequently Asked Questions

### What file format does VentoyPlugson use for configuration?

VentoyPlugson uses a single JSON file named [`ventoy.json`](https://github.com/ventoy/Ventoy/blob/main/ventoy.json) located in the Ventoy partition. This file contains top-level configuration blocks such as `control`, `theme`, `menu_alias`, and `menu_class`, with optional suffixes like `_uefi` or `_legacy` to support BIOS/UEFI-specific settings.

### How does VentoyPlugson handle different BIOS/UEFI configurations?

The parser uses the `ventoy_parse_json` macro to detect suffixes defined in `g_json_title_postfix[]` (such as `"_legacy"` and `"_uefi"`). When parsing a key like `control_uefi`, the macro strips the suffix, identifies the base block type (`control`), and dispatches to `ventoy_parse_control()` while passing the appropriate storage slot for that boot mode.

### Where is the JSON parser implementation located?

The core JSON tokenizer and tree builder reside in [`Plugson/src/Core/ventoy_json.c`](https://github.com/ventoy/Ventoy/blob/main/Plugson/src/Core/ventoy_json.c), with data structure definitions in [`Plugson/src/Core/ventoy_json.h`](https://github.com/ventoy/Ventoy/blob/main/Plugson/src/Core/ventoy_json.h). The domain-specific configuration dispatchers and block parsers are located in [`Plugson/src/Web/ventoy_http.c`](https://github.com/ventoy/Ventoy/blob/main/Plugson/src/Web/ventoy_http.c), with the dispatch macro defined in [`Plugson/src/Web/ventoy_http.h`](https://github.com/ventoy/Ventoy/blob/main/Plugson/src/Web/ventoy_http.h).

### Can the JSON parser handle malformed or incomplete configuration files?

The parser implements strict validation during the tokenization phase in `vtoy_json_parse_ex()`. If the JSON structure is malformed (missing braces, invalid escape sequences, or trailing commas), the parser returns an error code before reaching the domain-specific mapping layer. However, individual configuration blocks may use default values when specific keys are missing, handled by macros like `CONTROL_PARSE_INT_DEF_0` in the block-specific parsers.