aboutsummaryrefslogtreecommitdiff
path: root/rcc_format
diff options
context:
space:
mode:
authorAqua-sama <aqua@iserlohn-fortress.net>2020-03-30 14:08:41 +0300
committerAqua-sama <aqua@iserlohn-fortress.net>2020-03-30 14:17:00 +0300
commitf9ea03470e3a0bbe67ccb0a531dcf0e39aec1e90 (patch)
treea2079e6810e083ed437d2c0f1b9b1fe0bba27776 /rcc_format
parentDrop dependency on serge-sans-paille/frozen (diff)
downloadrcc-f9ea03470e3a0bbe67ccb0a531dcf0e39aec1e90.tar.xz
Move scripts/rcc to top level
- add rcc generator for use when importing as subproject
Diffstat (limited to 'rcc_format')
-rw-r--r--rcc_format/__init__.py2
-rwxr-xr-xrcc_format/gen-resources.sh9
-rw-r--r--rcc_format/util.py67
-rw-r--r--rcc_format/zstd.py43
4 files changed, 121 insertions, 0 deletions
diff --git a/rcc_format/__init__.py b/rcc_format/__init__.py
new file mode 100644
index 0000000..133bcc1
--- /dev/null
+++ b/rcc_format/__init__.py
@@ -0,0 +1,2 @@
+from rcc_format.util import *
+from rcc_format.zstd import zstd
diff --git a/rcc_format/gen-resources.sh b/rcc_format/gen-resources.sh
new file mode 100755
index 0000000..a1db9fd
--- /dev/null
+++ b/rcc_format/gen-resources.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+echo '<RCC>'
+echo ' <qresource prefix="/icons">'
+for f in $@; do
+ echo ' <file alias="'$(basename $f)'">'$f'</file>';
+done
+echo ' </qresource>'
+echo '</RCC>'
diff --git a/rcc_format/util.py b/rcc_format/util.py
new file mode 100644
index 0000000..7fcfe34
--- /dev/null
+++ b/rcc_format/util.py
@@ -0,0 +1,67 @@
+from collections import namedtuple
+import xml.etree.ElementTree as xml
+
+resource = namedtuple('resource', 'alias variable path')
+
+def to_variable_name(path):
+ name = path.replace('/', '_')
+ if name.endswith('.zstd'):
+ name = name[:-5]
+ name = name.replace('-', '_')
+ name = name.replace('.', '_')
+ return name
+
+def filelist(file):
+ root = xml.parse(file).getroot()
+ if root.tag != 'RCC':
+ return None
+
+ files = []
+ for child in root:
+ if child.tag == 'qresource':
+ prefix = child.attrib['prefix']
+ for i in child:
+ alias = prefix + '/' + i.attrib['alias']
+ variable = to_variable_name(i.text)
+ path = i.text
+ files.append(resource(alias, variable, path))
+
+ return files
+
+def write_header(file, namespace):
+ print("// Autogenerated binary file hexdump", file=file)
+ print("// This file may get overwritten by the build system\n", file=file)
+ print("#include <embed.h>\n", file=file)
+ print("namespace {} {{".format(namespace), file=file)
+
+def write_item(file, array_name, array_data):
+ line_items = 0
+
+ print("constexpr uint8_t {}[] = {{".format(array_name), file=file)
+
+ for byte in array_data[0:len(array_data)]:
+ line_items+=1
+ if line_items == 16:
+ print(" 0x{:02X},".format(byte), file=file)
+ line_items = 0
+ else:
+ print(" 0x{:02X},".format(byte), file=file, end='')
+
+
+ print("};", file=file)
+ print("constexpr size_t {}_len = {};\n".format(array_name, len(array_data)), file=file)
+
+def write_entries(file, resource_list):
+ print("constexpr std::array entries {", file=file)
+ for f in resource_list:
+ print(" \"{}\", ".format(f.alias), file=file)
+ print("};\n", file=file)
+
+ print("constexpr std::array values {", file=file)
+ for f in resource_list:
+ print(" std::span( {}, {}_len ),".format(f.variable, f.variable), file=file)
+ print("};\n", file=file)
+
+def write_footer(file, namespace):
+ print("\n}} // namespace {}".format(namespace), file=file)
+
diff --git a/rcc_format/zstd.py b/rcc_format/zstd.py
new file mode 100644
index 0000000..34eeb64
--- /dev/null
+++ b/rcc_format/zstd.py
@@ -0,0 +1,43 @@
+import subprocess
+from rcc_format.util import *
+
+def zstd(filelist, args):
+ if args.train is not None:
+ train(filelist, args.train, args.binary, args.dsize)
+ return
+
+ write_header(args.output, args.namespace)
+
+ for f in filelist:
+ with open(f.path, 'rb') as contents:
+ write_item(args.output, f.variable, compress(contents, args.binary, args.level, dictionary=args.dict))
+
+ write_entries(args.output, filelist)
+ if args.dict is not None:
+ write_item(args.output, 'dict', args.dict.read())
+ print("constexpr auto dictionary = std::span(dict, dict_len);", file=args.output)
+ else:
+ print("constexpr std::span<const uint8_t> dictionary {};", file=args.output)
+
+ print("constexpr auto compression = embed::Zstd;", file=args.output)
+
+ write_footer(args.output, args.namespace)
+
+def train(filelist, output, zstd_bin, maxdict):
+ cmd = [ zstd_bin, '--train', '--maxdict=' + str(maxdict), '-o', output.name ]
+
+ for f in filelist:
+ cmd.append(f.path)
+
+ subprocess.run(cmd)
+
+def compress(file, zstd_bin, level, dictionary=None):
+ cmd = [ zstd_bin, '--compress', '--stdout', '-' + str(level) ]
+
+ if dictionary is not None:
+ cmd.append('-D')
+ cmd.append(dictionary.name)
+
+ cmd.append(file.name)
+ return subprocess.run(cmd, capture_output=True).stdout
+