mirror of
https://github.com/a2-4am/wozardry.git
synced 2025-01-05 15:30:07 +00:00
add import and export commands, fix spelling of Portuguese
This commit is contained in:
parent
3a0501c789
commit
6225d2f9a1
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
__pycache__
|
26
README.md
26
README.md
@ -1,5 +1,5 @@
|
||||
```
|
||||
$ ./wozardry verify -h
|
||||
$ ./wozardry.py verify -h
|
||||
usage: wozardry verify [-h] file
|
||||
|
||||
Verify file structure and metadata of a .woz disk image (produces no output
|
||||
@ -13,7 +13,7 @@ optional arguments:
|
||||
|
||||
|
||||
|
||||
$ ./wozardry dump -h
|
||||
$ ./wozardry.py dump -h
|
||||
usage: wozardry dump [-h] file
|
||||
|
||||
Print all available information and metadata in a .woz disk image
|
||||
@ -52,4 +52,26 @@ Tips:
|
||||
- Use "key:" with no value to delete a metadata field.
|
||||
- Keys are case-sensitive.
|
||||
- Some values have format restrictions; read the .woz specification.
|
||||
|
||||
$ ./wozardry export -h
|
||||
usage: wozardry export [-h] file
|
||||
|
||||
Export (as JSON) all information and metadata from a .woz disk image
|
||||
|
||||
positional arguments:
|
||||
file .woz disk image
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
|
||||
$ ./wozardry import -h
|
||||
usage: wozardry import [-h] file
|
||||
|
||||
Import JSON file to update information and metadata in a .woz disk image
|
||||
|
||||
positional arguments:
|
||||
file .woz disk image
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
```
|
||||
|
@ -7,11 +7,12 @@ import argparse
|
||||
import binascii
|
||||
import bitarray # https://pypi.org/project/bitarray/
|
||||
import collections
|
||||
import json
|
||||
import itertools
|
||||
import os
|
||||
|
||||
__version__ = "dev"
|
||||
__date__ = "2018-07-25"
|
||||
__date__ = "2018-09-06"
|
||||
__progname__ = "wozardry"
|
||||
__displayname__ = __progname__ + " " + __version__ + " by 4am (" + __date__ + ")"
|
||||
|
||||
@ -22,7 +23,7 @@ kTMAP = b"TMAP"
|
||||
kTRKS = b"TRKS"
|
||||
kMETA = b"META"
|
||||
kBitstreamLengthInBytes = 6646
|
||||
kLanguages = ("English","Spanish","French","German","Chinese","Japanese","Italian","Dutch","Portugese","Danish","Finnish","Norwegian","Swedish","Russian","Polish","Turkish","Arabic","Thai","Czech","Hungarian","Catalan","Croatian","Greek","Hebrew","Romanian","Slovak","Ukranian","Indonesian","Malay","Vietnamese","Other")
|
||||
kLanguages = ("English","Spanish","French","German","Chinese","Japanese","Italian","Dutch","Portuguese","Danish","Finnish","Norwegian","Swedish","Russian","Polish","Turkish","Arabic","Thai","Czech","Hungarian","Catalan","Croatian","Greek","Hebrew","Romanian","Slovak","Ukranian","Indonesian","Malay","Vietnamese","Other")
|
||||
kRequiresRAM = ("16K","24K","32K","48K","64K","128K","256K","512K","768K","1M","1.25M","1.5M+","Unknown")
|
||||
kRequiresMachine = ("2","2+","2e","2c","2e+","2gs","2c+","3","3+")
|
||||
|
||||
@ -306,6 +307,10 @@ class WozReader(DiskImage, WozValidator):
|
||||
list(map(self.validate_metadata_requires_machine, values))
|
||||
self.meta[key] = len(values) == 1 and values[0] or tuple(values)
|
||||
|
||||
def to_json(self):
|
||||
j = {"woz": {"info":self.info, "meta":self.meta}}
|
||||
return json.dumps(j, indent=2)
|
||||
|
||||
def seek(self, track_num):
|
||||
"""returns Track object for the given track, or None if the track is not part of this disk image. track_num can be 0..40 in 0.25 increments (0, 0.25, 0.5, 0.75, 1, &c.)"""
|
||||
if type(track_num) != float:
|
||||
@ -341,6 +346,12 @@ class WozWriter(WozValidator):
|
||||
if tmap_id < 159:
|
||||
self.tmap[tmap_id + 1] = trk_id
|
||||
|
||||
def from_json(self, json_string):
|
||||
j = json.loads(json_string)
|
||||
root = [x for x in j.keys()].pop()
|
||||
self.info.update(j[root]["info"])
|
||||
self.meta.update(j[root]["meta"])
|
||||
|
||||
def build_info(self):
|
||||
chunk = bytearray()
|
||||
chunk.extend(kINFO) # chunk ID
|
||||
@ -497,22 +508,50 @@ class CommandDump(BaseCommand):
|
||||
for value in values[1:]:
|
||||
print("META: ".ljust(self.kWidth), value)
|
||||
|
||||
class CommandEdit(BaseCommand):
|
||||
class CommandExport(BaseCommand):
|
||||
def __init__(self):
|
||||
BaseCommand.__init__(self, "edit")
|
||||
BaseCommand.__init__(self, "export")
|
||||
|
||||
def setup(self, subparser):
|
||||
BaseCommand.setup(self,
|
||||
subparser,
|
||||
description="Edit information and metadata in a .woz disk image",
|
||||
epilog="""Tips:
|
||||
BaseCommand.setup(self, subparser,
|
||||
description="Export (as JSON) all information and metadata from a .woz disk image")
|
||||
|
||||
def __call__(self, args):
|
||||
BaseCommand.__call__(self, args)
|
||||
print(self.woz_image.to_json())
|
||||
|
||||
class WriterBaseCommand(BaseCommand):
|
||||
def __call__(self, args):
|
||||
BaseCommand.__call__(self, args)
|
||||
self.args = args
|
||||
# maintain creator if there is one, otherwise use default
|
||||
self.output = WozWriter(self.woz_image.info.get("creator", __displayname__))
|
||||
self.output.tmap = self.woz_image.tmap
|
||||
self.output.tracks = self.woz_image.tracks
|
||||
self.output.info = self.woz_image.info.copy()
|
||||
self.output.meta = self.woz_image.meta.copy()
|
||||
self.update()
|
||||
tmpfile = args.file + ".ardry"
|
||||
with open(tmpfile, "wb") as f:
|
||||
self.output.write(f)
|
||||
os.rename(tmpfile, args.file)
|
||||
|
||||
class CommandEdit(WriterBaseCommand):
|
||||
def __init__(self):
|
||||
WriterBaseCommand.__init__(self, "edit")
|
||||
|
||||
def setup(self, subparser):
|
||||
WriterBaseCommand.setup(self,
|
||||
subparser,
|
||||
description="Edit information and metadata in a .woz disk image",
|
||||
epilog="""Tips:
|
||||
|
||||
- Use repeated flags to edit multiple fields at once.
|
||||
- Use "key:" with no value to delete a metadata field.
|
||||
- Keys are case-sensitive.
|
||||
- Some values have format restrictions; read the .woz specification.""",
|
||||
help=".woz disk image (modified in place)",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
help=".woz disk image (modified in place)",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
self.parser.add_argument("-i", "--info", type=str, action="append",
|
||||
help="""change information field.
|
||||
INFO format is "key:value".
|
||||
@ -525,39 +564,39 @@ META format is "key:value".
|
||||
Standard keys are title, subtitle, publisher, developer, copyright, version, language, requires_ram,
|
||||
requires_machine, notes, side, side_name, contributor, image_date. Other keys are allowed.""")
|
||||
|
||||
def __call__(self, args):
|
||||
BaseCommand.__call__(self, args)
|
||||
# maintain creator if there is one, otherwise use default
|
||||
output = WozWriter(self.woz_image.info.get("creator", __displayname__))
|
||||
output.tmap = self.woz_image.tmap
|
||||
output.tracks = self.woz_image.tracks
|
||||
output.info = self.woz_image.info.copy()
|
||||
output.meta = self.woz_image.meta.copy()
|
||||
def update(self):
|
||||
# add all new info fields
|
||||
for i in args.info or ():
|
||||
for i in self.args.info or ():
|
||||
k, v = i.split(":", 1)
|
||||
if k in ("write_protected","synchronized","cleaned"):
|
||||
v = v.lower() in ("1", "true", "yes")
|
||||
output.info[k] = v
|
||||
# add all new metadata fields
|
||||
for m in args.meta or ():
|
||||
self.output.info[k] = v
|
||||
# add all new metadata fields, and delete empty ones
|
||||
for m in self.args.meta or ():
|
||||
k, v = m.split(":", 1)
|
||||
v = v.split("|")
|
||||
if len(v) == 1:
|
||||
v = v[0]
|
||||
if v:
|
||||
output.meta[k] = v
|
||||
elif k in output.meta.keys():
|
||||
del output.meta[k]
|
||||
tmpfile = args.file + ".ardry"
|
||||
with open(tmpfile, "wb") as f:
|
||||
output.write(f)
|
||||
os.rename(tmpfile, args.file)
|
||||
self.output.meta[k] = v
|
||||
elif k in self.output.meta.keys():
|
||||
del self.output.meta[k]
|
||||
|
||||
class CommandImport(WriterBaseCommand):
|
||||
def __init__(self):
|
||||
WriterBaseCommand.__init__(self, "import")
|
||||
|
||||
def setup(self, subparser):
|
||||
WriterBaseCommand.setup(self, subparser,
|
||||
description="Import JSON file to update information and metadata in a .woz disk image")
|
||||
|
||||
def update(self):
|
||||
self.output.from_json(sys.stdin.read())
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
raise_if = lambda cond, e, s="": cond and sys.exit("%s: %s" % (e.__name__, s))
|
||||
cmds = [CommandDump(), CommandVerify(), CommandEdit()]
|
||||
cmds = [CommandDump(), CommandVerify(), CommandEdit(), CommandExport(), CommandImport()]
|
||||
parser = argparse.ArgumentParser(prog=__progname__,
|
||||
description="""A multi-purpose tool for manipulating .woz disk images.
|
||||
|
Loading…
Reference in New Issue
Block a user