25
22
import calibre.ebooks.lit.maps as maps
26
23
from calibre.ebooks.oeb.base import OEB_DOCS, XHTML_MIME, OEB_STYLES, \
27
24
CSS_MIME, OPF_MIME, XML_NS, XML
28
from calibre.ebooks.oeb.base import namespace, barename, prefixname, \
30
from calibre.ebooks.oeb.base import Logger, OEBBook
31
from calibre.ebooks.oeb.profile import Context
25
from calibre.ebooks.oeb.base import prefixname, \
32
27
from calibre.ebooks.oeb.stylizer import Stylizer
33
from calibre.ebooks.oeb.transforms.flatcss import CSSFlattener
34
from calibre.ebooks.oeb.transforms.rasterize import SVGRasterizer
35
from calibre.ebooks.oeb.transforms.trimmanifest import ManifestTrimmer
36
from calibre.ebooks.oeb.transforms.htmltoc import HTMLTOCAdder
37
from calibre.ebooks.oeb.transforms.manglecase import CaseMangler
38
28
from calibre.ebooks.lit.lzx import Compressor
40
30
from calibre import plugins
41
31
msdes, msdeserror = plugins['msdes']
42
32
import calibre.ebooks.lit.mssha1 as mssha1
43
from calibre.customize.ui import run_plugins_on_postprocess
45
34
__all__ = ['LitWriter']
169
158
def is_block(self, style):
170
159
return style['display'] not in ('inline', 'inline-block')
172
161
def tree_to_binary(self, elem, nsrmap=NSRMAP, parents=[],
173
162
inhead=False, preserve=False):
174
163
if not isinstance(elem.tag, basestring):
175
self.write(etree.tostring(elem))
164
# Don't emit any comments or raw entities
177
166
nsrmap = copy.copy(nsrmap)
178
167
attrib = dict(elem.attrib)
278
267
def build_ahc(self):
279
268
if len(self.anchors) > 6:
280
self.logger.log_warn("More than six anchors in file %r. " \
269
self.logger.warn("More than six anchors in file %r. " \
281
270
"Some links may not work properly." % self.item.href)
282
271
data = StringIO()
283
272
data.write(unichr(len(self.anchors)).encode('utf-8'))
309
298
def _litize_oeb(self):
311
oeb.metadata.add('calibre-oeb2lit-version', calibre.__version__)
300
oeb.metadata.add('calibre-version', calibre.__version__)
313
302
if oeb.metadata.cover:
314
id = str(oeb.metadata.cover[0])
315
cover = oeb.manifest[id]
303
id = unicode(oeb.metadata.cover[0])
304
cover = oeb.manifest.ids[id]
316
305
for type, title in ALL_MS_COVER_TYPES:
317
306
if type not in oeb.guide:
318
307
oeb.guide.add(type, title, cover.href)
320
309
self._logger.warn('No suitable cover image found.')
322
def dump(self, oeb, path):
311
def __call__(self, oeb, path):
323
312
if hasattr(path, 'write'):
324
313
return self._dump_stream(oeb, path)
325
314
with open(path, 'w+b') as stream:
326
315
return self._dump_stream(oeb, stream)
328
317
def _dump_stream(self, oeb, stream):
330
319
self._logger = oeb.logger
414
403
self._write(cchunk, filler, pack('<H', len(dcounts)))
415
404
self._writeat(pieces[2], pack('<QQ',
416
405
piece2_offset, self._tell() - piece2_offset))
418
407
# Piece #3: GUID3
419
408
piece3_offset = self._tell()
420
409
self._write(packguid(PIECE3_GUID))
421
410
self._writeat(pieces[3], pack('<QQ',
422
411
piece3_offset, self._tell() - piece3_offset))
424
413
# Piece #4: GUID4
425
414
piece4_offset = self._tell()
426
415
self._write(packguid(PIECE4_GUID))
468
457
self._add_folder('/data')
469
458
for item in self._oeb.manifest.values():
470
459
if item.media_type not in LIT_MIMES:
471
self._logger.log_warn("File %r of unknown media-type %r " \
460
self._logger.warn("File %r of unknown media-type %r " \
472
461
"excluded from output." % (item.href, item.media_type))
474
463
name = '/data/' + item.id
486
475
elif isinstance(data, unicode):
487
476
data = data.encode('utf-8')
477
elif hasattr(data, 'cssText'):
488
479
self._add_file(name, data, secnum)
489
480
item.size = len(data)
561
552
self._add_file('/pb1', pb1.getvalue(), 0)
562
553
self._add_file('/pb2', pb2.getvalue(), 0)
563
554
self._add_file('/pb3', pb3.getvalue(), 0)
565
556
def _build_meta(self):
566
557
_, meta = self._oeb.to_opf1()[OPF_MIME]
567
558
meta.attrib['ms--minimum_level'] = '0'
658
649
for i in xrange(0, len(digest)):
659
650
key[i % 8] ^= ord(digest[i])
660
651
return ''.join(chr(x) for x in key)
662
653
def _build_dchunks(self):
664
655
directory = list(self._directory)
718
709
ichunk = ''.join(['AOLI', pack('<IQ', rem, len(dchunks)),
719
710
ichunk.getvalue(), ('\0' * pad), pack('<H', len(dchunks))])
720
711
return dcounts, dchunks, ichunk
724
from calibre.utils.config import OptionParser
725
parser = OptionParser(usage=_('%prog [options] OPFFILE'))
727
'-o', '--output', default=None,
728
help=_('Output file. Default is derived from input filename.'))
730
'-v', '--verbose', default=0, action='count',
731
help=_('Useful for debugging.'))
734
def oeb2lit(opts, inpath):
735
logger = Logger(logging.getLogger('oeb2lit'))
736
logger.setup_cli_handler(opts.verbose)
737
outpath = opts.output
739
outpath = os.path.basename(inpath)
740
outpath = os.path.splitext(outpath)[0] + '.lit'
741
outpath = os.path.abspath(outpath)
742
context = Context('Browser', 'MSReader')
743
oeb = OEBBook(inpath, logger=logger)
744
tocadder = HTMLTOCAdder()
745
tocadder.transform(oeb, context)
746
mangler = CaseMangler()
747
mangler.transform(oeb, context)
748
fbase = context.dest.fbase
749
flattener = CSSFlattener(fbase=fbase, unfloat=True, untable=True)
750
flattener.transform(oeb, context)
751
rasterizer = SVGRasterizer()
752
rasterizer.transform(oeb, context)
753
trimmer = ManifestTrimmer()
754
trimmer.transform(oeb, context)
756
lit.dump(oeb, outpath)
757
run_plugins_on_postprocess(outpath, 'lit')
758
logger.info(_('Output written to ') + outpath)
761
def main(argv=sys.argv):
762
parser = option_parser()
763
opts, args = parser.parse_args(argv[1:])
768
oeb2lit(opts, inpath)
771
if __name__ == '__main__':