Adds the reverse conversion (sab -> sax) and makes the tools usable without remembering paths on the command line. - sax.py: decoder ported from OfflineApp.decodeAppBinary + encodeAppXml. Rebuilds the tree from the firstChild/nextSibling chain and writes XML the way XWriter does. Reproduces java.lang.Float.toString, and rounds manifest defaults to f4 before comparing them - otherwise props equal to their default (0.1) get written where sedonac omits them. - sab2sax.py: CLI dispatching on the input extension, like sedonac. sab.py still runs and hands off to it. - config.py: sedona.home lives in system.properties. If it is missing or has no manifests/, a folder chooser opens and the answer is written back. File choosers for the input, save dialogs for the output; the default output name carries a timestamp so a run never overwrites the previous one. - verify.py: checks both directions plus a sab -> sax -> sab round trip, and points at testprogram/ where the test files actually live. All three checks pass byte-identical against the checked-in sedonac output. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
66 lines
2.4 KiB
Python
66 lines
2.4 KiB
Python
"""Entry point: converts either direction, the way `sedonac.exe <file>` does --
|
|
the input's extension decides.
|
|
|
|
python sab2sax.py [in.sax|in.sab] [out]
|
|
|
|
.sax in -> .sab out (sab.encode)
|
|
.sab in -> .sax out (sax.decode)
|
|
|
|
Omit the input and a file chooser opens; omit the output and a save dialog opens
|
|
next to the input, pre-filled with a timestamped name. Sedona home comes from
|
|
system.properties (see config.py).
|
|
"""
|
|
import os, sys
|
|
import config, sab, sax
|
|
|
|
|
|
def convert(in_path, out_path=None, home=None):
|
|
"""Convert `in_path` by extension, no dialogs. Returns (out_path, bytes written).
|
|
|
|
With no `out_path`, writes a timestamped name next to the input."""
|
|
ext = os.path.splitext(in_path)[1].lower()
|
|
if ext not in (".sax", ".sab"):
|
|
raise Exception("don't know what to do with %s -- expected .sax or .sab" % in_path)
|
|
if out_path is None:
|
|
name = sab.default_sab_name(in_path) if ext == ".sax" else sax.default_sax_name(in_path)
|
|
out_path = os.path.join(os.path.dirname(os.path.abspath(in_path)), name)
|
|
if ext == ".sax":
|
|
return out_path, sab.encode(in_path, home, out_path)
|
|
return out_path, sax.decode(in_path, home, out_path)
|
|
|
|
|
|
def main(argv):
|
|
home = config.get_sedona_home()
|
|
|
|
in_path = argv[1] if len(argv) > 1 else config.choose_input_file()
|
|
if not in_path:
|
|
raise SystemExit("no input file selected")
|
|
in_path = os.path.abspath(in_path)
|
|
if not os.path.isfile(in_path):
|
|
raise SystemExit("no such file: " + in_path)
|
|
|
|
ext = os.path.splitext(in_path)[1].lower()
|
|
if ext not in (".sax", ".sab"):
|
|
raise SystemExit("don't know what to do with %s -- expected .sax or .sab" % in_path)
|
|
|
|
if len(argv) > 2:
|
|
out_path = argv[2]
|
|
elif ext == ".sax":
|
|
out_path = config.choose_sab_file(initialfile=sab.default_sab_name(in_path),
|
|
initial=os.path.dirname(in_path))
|
|
else:
|
|
out_path = config.choose_sax_output(initialfile=sax.default_sax_name(in_path),
|
|
initial=os.path.dirname(in_path))
|
|
if not out_path:
|
|
raise SystemExit("no output file selected")
|
|
|
|
if ext == ".sax":
|
|
n = sab.encode(in_path, home, out_path)
|
|
else:
|
|
n = sax.decode(in_path, home, out_path)
|
|
print("wrote %d bytes to %s" % (n, out_path))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main(sys.argv)
|