luks: Create a very simple JSON library

LUKS version 2 uses JSON as a means of communicating the key
information. Add a simple library which can print JSON in a
human-readable format.

Note that it does not fully parse the JSON fragment. That may be
considered later, if needed.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass
2025-10-23 13:15:42 +01:00
parent 414baddf37
commit 2737bf15bf
7 changed files with 368 additions and 0 deletions

View File

@@ -976,6 +976,13 @@ config GETOPT
help
This enables functions for parsing command-line options.
config JSON
bool "Enable JSON parsing and printing"
help
This enables JSON (JavaScript Object Notation) parsing and pretty-
printing functions. JSON is used for structured data representation,
such as LUKS2 metadata.
config OF_LIBFDT
bool "Enable the FDT library"
default y if OF_CONTROL

View File

@@ -39,6 +39,7 @@ endif
obj-y += crc8.o
obj-$(CONFIG_ERRNO_STR) += errno_str.o
obj-$(CONFIG_JSON) += json.o
obj-$(CONFIG_FIT) += fdtdec_common.o
obj-$(CONFIG_TEST_FDTDEC) += fdtdec_test.o
obj-$(CONFIG_GZIP_COMPRESSED) += gzip.o

122
lib/json.c Normal file
View File

@@ -0,0 +1,122 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* JSON pretty-printer
*
* Copyright (C) 2025 Canonical Ltd
* Written by Simon Glass <simon.glass@canonical.com>
*/
#include <ctype.h>
#include <log.h>
/**
* print_indent() - Print indentation spaces
*
* @indent: Indentation level (each level is 2 spaces)
*/
static void print_indent(int indent)
{
for (int i = 0; i < indent * 2; i++)
putc(' ');
}
void json_print_pretty(const char *json, int len)
{
int indent = 0;
bool in_string = false;
bool escaped = false;
bool after_open = false;
int i;
for (i = 0; i < len && json[i]; i++) {
char c = json[i];
/* Handle escape sequences */
if (escaped) {
putc(c);
escaped = false;
continue;
}
if (c == '\\') {
putc(c);
escaped = true;
continue;
}
/* Track whether we're inside a string */
if (c == '"') {
in_string = !in_string;
if (after_open) {
print_indent(indent);
after_open = false;
}
putc(c);
continue;
}
/* Don't format inside strings */
if (in_string) {
putc(c);
continue;
}
/* Format structural characters */
switch (c) {
case '{':
case '[':
if (after_open) {
print_indent(indent);
after_open = false;
}
putc(c);
putc('\n');
indent++;
after_open = true;
break;
case '}':
case ']':
if (!after_open) {
putc('\n');
indent--;
print_indent(indent);
} else {
indent--;
}
putc(c);
after_open = false;
break;
case ',':
putc(c);
putc('\n');
print_indent(indent);
after_open = false;
break;
case ':':
putc(c);
putc(' ');
after_open = false;
break;
case ' ':
case '\t':
case '\n':
case '\r':
/* Skip whitespace outside strings */
break;
default:
if (after_open) {
print_indent(indent);
after_open = false;
}
putc(c);
break;
}
}
putc('\n');
}