Skip to content

Instantly share code, notes, and snippets.

@cspiegel
Last active November 15, 2021 23:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cspiegel/48794734d41a2c17f53adf50a418d1e1 to your computer and use it in GitHub Desktop.
Save cspiegel/48794734d41a2c17f53adf50a418d1e1 to your computer and use it in GitHub Desktop.
Convert fdo XML to Haiku resources
resource(0, "BEOS:TYPE") #'MIMS' "application/x-vnd.Be-meta-mime";
resource(1, "META:TYPE") "application/x-adrift";
resource(2, "META:SNIFF_RULE") #'MSIG' "0.50 (\"\\074\\102\\077\\311\\152\\207\\302\\317\")";
resource(3, "META:S:DESC") #'MDSC' "Adrift game data";
resource(4, "META:EXTENS") message(234) {
"extensions" = "taf",
"type" = "application/x-adrift"
};
resource(0, "BEOS:TYPE") #'MIMS' "application/x-vnd.Be-meta-mime";
resource(1, "META:TYPE") "application/x-blorb";
resource(2, "META:SNIFF_RULE") #'MSIG' "0.50 (\"FORM\")([8] \"IFRS\")";
resource(3, "META:S:DESC") #'MDSC' "Blorb interactive fiction data";
resource(4, "META:EXTENS") message(234) {
"extensions" = "blb",
"extensions" = "blorb",
"extensions" = "gblorb",
"extensions" = "glb",
"extensions" = "zblorb",
"extensions" = "zlb",
"type" = "application/x-blorb"
};
resource(0, "BEOS:TYPE") #'MIMS' "application/x-vnd.Be-meta-mime";
resource(1, "META:TYPE") "application/x-zmachine";
resource(2, "META:S:DESC") #'MDSC' "Z-machine game data";
resource(3, "META:EXTENS") message(234) {
"extensions" = "z1",
"extensions" = "z2",
"extensions" = "z3",
"extensions" = "z4",
"extensions" = "z5",
"extensions" = "z6",
"extensions" = "z7",
"extensions" = "z8",
"type" = "application/x-zmachine"
};
#!/usr/bin/env python3
from typing import Dict, Any
import re
import sys
import xmltodict
class Error(Exception): pass
with open(sys.argv[1]) as f:
d = xmltodict.parse(f.read())
def process_mime_type(mt: Dict[str, Any], mimetype: str):
resources = {
"BEOS:TYPE": "#'MIMS' \"application/x-vnd.Be-meta-mime\";",
"META:TYPE": f"\"{mimetype}\";",
}
try:
magic = mt["magic"]
if not isinstance(magic, dict):
raise Error("Multiple matches not supported")
match = magic["match"]
priority = float(magic["@priority"])
except KeyError:
pass
else:
priority /= 100.0
# Matches can be nested to be additive so use a recursive function.
def handle_match(match):
if not isinstance(match, dict):
raise Error("Sum matches not supported")
offset = match["@offset"]
value = match["@value"]
offstr = ""
if offset != "0":
offstr = f"[{offset}] "
# Replace hex escapes with octal (is hex supported?)
def replace(match):
byte = int(match.group(1), 16)
return f"\\\\{byte:03o}"
value = re.sub(r"\\x([0-9a-fA-F][0-9a-fA-F])", replace, value)
string = f"({offstr}\\\"{value}\\\")"
try:
string += handle_match(match["match"])
except KeyError:
pass
return string
matchstr = handle_match(match)
resources["META:SNIFF_RULE"] = f"#'MSIG' \"{priority:.2f} {matchstr}\";"
try:
# There can be comments in various languages; those with lang
# attributes are dicts, so filter them out, then pick the first
# value from the result, if any.
comments = mt["comment"]
if isinstance(comments, str):
comments = [comments]
comment = next(comment for comment in comments if isinstance(comment, str))
except (KeyError, StopIteration):
pass
else:
resources["META:S:DESC"] = f"#'MDSC' \"{comment}\";"
try:
globs = mt["glob"]
except KeyError:
pass
else:
if isinstance(globs, dict):
globs = [globs]
globs = [glob["@pattern"][2:] for glob in globs]
# Hack for Z-machine
if globs == ["z[1-8]"]:
globs = [f"z{v}" for v in range(1, 9)]
extensions = "\n".join(f" \"extensions\" = \"{glob}\"," for glob in globs)
resources["META:EXTENS"] = f"""message(234) {{
{extensions}
"type" = "{mimetype}"
}};"""
with open(f"MIME/{re.sub('/', '-', mimetype)}", "w") as f:
for (i, (name, value)) in enumerate(resources.items()):
f.write(f"resource({i}, \"{name}\") {value}\n\n")
for mt in d["mime-info"]["mime-type"]:
try:
mimetype = mt["@type"]
except KeyError:
print("No MIME type given")
continue
try:
process_mime_type(mt, mimetype)
except Error as e:
print(f"Can't handle match for {mimetype}: {e}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment