blob: 08b13beec806d574603b512a3d7acdb76b0f9d23 [file] [log] [blame]
"""Conversion utility from flatbuffer JSON files to binary and the reverse."""
# Copyright (c) 2021-2023, ARM Limited.
# SPDX-License-Identifier: Apache-2.0
import re
from pathlib import Path
from typing import Optional
from runner.run_command import run_sh_command
from runner.run_command import RunShCommandError
MAX_LINE_LEN = 120
MAX_INDENT_LEN = 20
def json_squeeze(json_path: Path):
"""File compression for JSONs, reducing spaces used for number lists."""
# Move existing file to a new name
temp_path = json_path.with_suffix(".json_unsqueezed")
json_path.rename(temp_path)
# Now read the original file and write a smaller output with less new lines/spaces
with temp_path.open("r") as tfd:
with json_path.open("w") as jfd:
found = False
for line in tfd:
# Find lines that are part of number lists
match = re.match(r"(\s+)(-?[0-9]+),?", line)
if match:
# Found a line with just a number on it (and optional comma)
if not found:
# New list of numbers
numbers = []
# Save indent (upto maximum)
indent = match.group(1)[0:MAX_INDENT_LEN]
found = True
numbers.append(match.group(2))
else:
# Found a line without just a number
if found:
# Format the list of numbers recorded into a concise output
# with multiple numbers on a single line, rather than one per line
numbers_str = indent
for num in numbers:
nums = f"{num},"
if len(numbers_str) + len(nums) > MAX_LINE_LEN:
print(numbers_str, file=jfd)
numbers_str = indent
numbers_str += nums
# print all but the last comma
print(numbers_str[:-1], file=jfd)
found = False
# print the line we just read (that wasn't just a number)
print(line, file=jfd, end="")
# Remove the uncompressed version
temp_path.unlink()
def fbbin_to_json(
flatc: Path,
fbs: Path,
t_path: Path,
o_path: Optional[Path] = None,
squeeze: Optional[bool] = True,
):
"""Convert the binary flatbuffer to JSON.
flatc: the Path to the flatc compiler program
fbs: the Path to the fbs (flatbuffer schema) file
t_path: the Path to the binary flatbuffer file
o_path: the output Path where JSON file will be put, if None, it is same as t_path
"""
if o_path is None:
o_path = t_path.parent
cmd = [
str(flatc.absolute()),
"-o",
str(o_path.absolute()),
"--json",
"--strict-json",
"--defaults-json",
"--raw-binary",
str(fbs.absolute()),
"--",
str(t_path.absolute()),
]
run_sh_command(verbose=False, full_cmd=cmd)
if squeeze:
json_path = (o_path / t_path.name).with_suffix(".json")
json_squeeze(json_path)
def json_to_fbbin(flatc: Path, fbs: Path, j_path: Path, o_path: Optional[Path] = None):
"""Convert JSON flatbuffer to binary.
flatc: the Path to the flatc compiler program
fbs: the Path to the fbs (flatbuffer schema) file
j_path: the Path to the JSON flatbuffer file
o_path: the output Path where JSON file will be put, if None, it is same as j_path
"""
if o_path is None:
o_path = j_path.parent
cmd = [
str(flatc.absolute()),
"-o",
str(o_path.absolute()),
"--binary",
str(fbs.absolute()),
str(j_path.absolute()),
]
run_sh_command(verbose=False, full_cmd=cmd)
# ------------------------------------------------------------------------------
def main(argv=None):
"""Load and convert supplied file based on file suffix."""
import argparse
parser = argparse.ArgumentParser()
parser.add_argument(
"--no-squeeze", action="store_true", help="no compression of json output"
)
parser.add_argument(
"--flatc",
type=Path,
default=(
"reference_model/build/thirdparty/serialization_lib/"
"third_party/flatbuffers/flatc"
),
help="the path to the flatc compiler program",
)
parser.add_argument(
"--fbs",
type=Path,
default="conformance_tests/third_party/serialization_lib/schema/tosa.fbs",
help="the path to the flatbuffer schema",
)
parser.add_argument("path", type=Path, help="the path to the file to convert")
args = parser.parse_args(argv)
path = args.path
if not path.is_file():
print(f"Invalid file to convert - {path}")
return 2
if not args.flatc.is_file():
print(f"Invalid flatc compiler - {args.flatc}")
return 2
if not args.fbs.is_file():
print(f"Invalid flatbuffer schema - {args.fbs}")
return 2
try:
if path.suffix == ".json":
json_to_fbbin(args.flatc, args.fbs, path)
else:
# Have to assume this is a binary flatbuffer file as could have any suffix
fbbin_to_json(args.flatc, args.fbs, path, squeeze=(not args.no_squeeze))
except RunShCommandError as e:
print(e)
return 1
return 0
if __name__ == "__main__":
exit(main())