%PDF- %PDF-
Direktori : /usr/lib/calibre/calibre/ebooks/mobi/writer8/ |
Current File : //usr/lib/calibre/calibre/ebooks/mobi/writer8/header.py |
#!/usr/bin/env python3 __license__ = 'GPL v3' __copyright__ = '2012, Kovid Goyal <kovid@kovidgoyal.net>' __docformat__ = 'restructuredtext en' import random, numbers from io import BytesIO from collections import OrderedDict from struct import pack from calibre.ebooks.mobi.utils import align_block from polyglot.builtins import iteritems, as_bytes NULL = 0xffffffff zeroes = lambda x: b'\0'*x nulls = lambda x: b'\xff'*x short = lambda x: pack(b'>H', x) class Header(OrderedDict): HEADER_NAME = b'' DEFINITION = ''' ''' ALIGN_BLOCK = False POSITIONS = {} # Mapping of position field to field whose position should # be stored in the position field SHORT_FIELDS = set() def __init__(self): OrderedDict.__init__(self) for line in self.DEFINITION.splitlines(): line = line.strip() if not line or line.startswith('#'): continue name, val = (x.strip() for x in line.partition('=')[0::2]) if val: val = eval(val, {'zeroes':zeroes, 'NULL':NULL, 'DYN':None, 'nulls':nulls, 'short':short, 'random':random}) else: val = 0 if name in self: raise ValueError('Duplicate field in definition: %r'%name) self[name] = val @property def dynamic_fields(self): return tuple(k for k, v in iteritems(self) if v is None) def __call__(self, **kwargs): positions = {} for name, val in iteritems(kwargs): if name not in self: raise KeyError('Not a valid header field: %r'%name) self[name] = val buf = BytesIO() buf.write(as_bytes(self.HEADER_NAME)) for name, val in iteritems(self): val = self.format_value(name, val) positions[name] = buf.tell() if val is None: raise ValueError('Dynamic field %r not set'%name) if isinstance(val, numbers.Integral): fmt = b'H' if name in self.SHORT_FIELDS else b'I' val = pack(b'>'+fmt, val) buf.write(val) for pos_field, field in iteritems(self.POSITIONS): buf.seek(positions[pos_field]) buf.write(pack(b'>I', positions[field])) ans = buf.getvalue() if self.ALIGN_BLOCK: ans = align_block(ans) return ans def format_value(self, name, val): return val