From 3045e23d23944d4d89be015fd832ddbba8548918 Mon Sep 17 00:00:00 2001 From: Artem Baguinski Date: Wed, 2 Apr 2008 11:10:05 +0200 Subject: [PATCH] Field is a composite object with a factory --- shuffle.py | 139 ++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 82 insertions(+), 57 deletions(-) diff --git a/shuffle.py b/shuffle.py index 787612b..0566a5b 100644 --- a/shuffle.py +++ b/shuffle.py @@ -44,31 +44,77 @@ def unpack_int24(s,bigendian): return u class Skip(object): - def __init__(self, n): self.size = n + def __init__(self, n): + self.size = n + def skip(self, file): + file.seek(self.size, os.SEEK_CUR) + def read(self, file, dict): + self.skip(file) + def write(self, file, dict): + self.skip(file) + def set_bigendian(self, ignore): + pass + +class Field: + class Named: + def __init__(self, name): + self.name = name + def get(self, dict): + return dict[self.name] + def put(self, dict, value): + dict[self.name] = value + + class Const: + def __init__(self, const, check): + self.const = const + self.check = check + def get(self, dict): + return self.const + def put(self, dict, value): + if self.check and value != self.const: + raise "Format error" + + def __init__(self, packer, name=None, const=None, check = False): + self.packer = packer + if name is not None and const is None: + self.value_handler = Field.Named(name) + elif name is None and const is not None: + self.value_handler = Field.Const(const, check) + + def read(self, file, dict): + self.put(dict, self.unpack( file.read( self.packer.size ))) + def write(self, file, dict): + file.write( self.pack( self.value_handler.get(dict) )) + def put(self, dict, val): + self.value_handler.put(dict, val) + def get(self, dict): + return self.value_handler.get(dict) + def unpack(self, str): + return self.packer.unpack(str) + def pack(self, val): + return self.packer.pack(val) + def set_bigendian(self, bigendian): + self.packer.bigendian = bigendian class SimpleField: - def __init__(self, name, fmt): - self.name = name + def __init__(self, fmt): self.fmt = fmt self.size = struct.calcsize(fmt) - def pack(self,val): return struct.pack(self.fmt,val) - def unpack(self,str): return struct.unpack(self.fmt,str)[0] class Uint8(SimpleField): - def __init__(self,name): SimpleField.__init__(self,name,"B") + def __init__(self): SimpleField.__init__(self,"B") class Bool8(Uint8): - def __init__(self, name): Uint8.__init__(self, name) + def __init__(self): Uint8.__init__(self) def pack(self, val): return Uint8.pack(self, (1 if val else 0)) def unpack(self, str): return Uint8.unpack(self, str) != 0 class Uint24: - def __init__(self, name, bigendian = LITTLE_ENDIAN): - self.name = name + def __init__(self, bigendian = LITTLE_ENDIAN): self.size = 3 self.bigendian = bigendian def pack(self, val): @@ -77,8 +123,7 @@ class Uint24: return unpack_uint24(str, self.bigendian) class Int24: - def __init__(self, name, bigendian = LITTLE_ENDIAN): - self.name = name + def __init__(self, bigendian = LITTLE_ENDIAN): self.size = 3 self.bigendian = bigendian def pack(self, val): @@ -87,14 +132,12 @@ class Int24: return unpack_int24(str, self.bigendian) class Bool24(Int24): - def __init__(self, name): - Int24.__init__(self, name) + def __init__(self): Int24.__init__(self) def pack(self, val): return Int24.pack(self, (-1 if val else 0)) def unpack(self, str): return Int24.unpack(self, str) != 0 class ZeroPaddedString: - def __init__(self, name, len, enc): - self.name = name + def __init__(self, len, enc): self.size = len self.enc = enc def pack(self, val): @@ -105,29 +148,16 @@ class ZeroPaddedString: class Record: def __init__(self, fields, bigendian): for f in fields: - f.bigendian = bigendian + f.set_bigendian(bigendian) self.fields = fields - @staticmethod - def _read_field(field, file, dict): - dict[field.name] = field.unpack( file.read( field.size )) - - @staticmethod - def _write_field(field, file, dict): - file.write( field.pack( dict[ field.name ])) - - def _read(self, file, dict): - self._rw(file, dict, Record._read_field) - - def _write(self, file, dict): - self._rw(file, dict, Record._write_field) + def read(self, file, dict): + for f in self.fields: + f.read(file, dict) - def _rw(self, file, dict, handle_field): + def write(self, file, dict): for f in self.fields: - if type(f) == Skip: - file.seek(f.size, os.SEEK_CUR) - else: - handle_field(f,file,dict) + f.write(file, dict) class Track: supported_file_types = (".mp3", ".aa", ".m4a", ".m4b", ".m4p", ".wav") @@ -289,36 +319,31 @@ class ShuffleDB: def close_file(self): self.open_file(None, BIG_ENDIAN) - def write_iTunesSD(self, tracks): - self.open_file('iTunesSD', BIG_ENDIAN, WRITE) - self.write_u24(len(tracks)) - self.write_u24(0x010800) # like iTunes 7.2 does - self.write_u24(18) # header size - self.skip(9) - for t in tracks: - self.write_iTunesSD_track(t) - self.close_file() - iTunesSD_track = Record([ - Uint24('reclen'), + Field(Uint24(), const=558, check=True), Skip(3), - Uint24('starttime'), + Field(Uint24(), 'starttime'), Skip(6), - Uint24( 'stoptime'), + Field(Uint24(), 'stoptime'), Skip(6), - Uint24( 'volume'), - Uint24( 'file_type'), + Field(Uint24(), 'volume'), + Field(Uint24(), 'file_type'), Skip(3), - ZeroPaddedString( 'filename', 522, 'UTF-16-LE'), - Bool8( 'shuffleflag'), - Bool8( 'bookmarkflag'), + Field(ZeroPaddedString(522, 'UTF-16-LE'), 'filename'), + Field(Bool8(), 'shuffleflag'), + Field(Bool8(), 'bookmarkflag'), Skip(1)], BIG_ENDIAN) - def write_iTunesSD_track(self, t): - t.reclen = 558 # FIXME!!! - self.iTunesSD_track._write(self.file, t.__dict__) - return + def write_iTunesSD(self, tracks): + self.open_file('iTunesSD', BIG_ENDIAN, WRITE) + self.write_u24(len(tracks)) + self.write_u24(0x010800) # like iTunes 7.2 does + self.write_u24(18) # header size + self.skip(9) + for t in tracks: + self.iTunesSD_track.write(self.file, t.__dict__) + self.close_file() def read_iTunesSD(self): self.open_file('iTunesSD', BIG_ENDIAN) @@ -327,7 +352,7 @@ class ShuffleDB: tracks = [] for n in xrange(0, num_tracks): t = Track() - self.iTunesSD_track._read(self.file, t.__dict__ ) + self.iTunesSD_track.read(self.file, t.__dict__ ) tracks.append( t ) self.close_file() return tracks -- 2.11.4.GIT