1# -*- coding: utf-8 -*-
2
3
4__license__ = 'GPL 3'
5__copyright__ = '2010, Li Fanxi <lifanxi@freemindworld.com>'
6__docformat__ = 'restructuredtext en'
7
8import os
9
10from calibre.customize.conversion import InputFormatPlugin
11from calibre.ptempfile import TemporaryDirectory
12from calibre.utils.filenames import ascii_filename
13
14HTML_TEMPLATE = '<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><title>%s</title></head><body>\n%s\n</body></html>'
15
16
17def html_encode(s):
18    return s.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;').replace("'", '&apos;').replace('\n', '<br/>').replace(' ', '&nbsp;')  # noqa
19
20
21class SNBInput(InputFormatPlugin):
22
23    name        = 'SNB Input'
24    author      = 'Li Fanxi'
25    description = _('Convert SNB files to OEB')
26    file_types  = {'snb'}
27    commit_name = 'snb_input'
28
29    options = set()
30
31    def convert(self, stream, options, file_ext, log,
32                accelerators):
33        import uuid
34
35        from calibre.ebooks.oeb.base import DirContainer
36        from calibre.ebooks.snb.snbfile import SNBFile
37        from calibre.utils.xml_parse import safe_xml_fromstring
38
39        log.debug("Parsing SNB file...")
40        snbFile = SNBFile()
41        try:
42            snbFile.Parse(stream)
43        except:
44            raise ValueError("Invalid SNB file")
45        if not snbFile.IsValid():
46            log.debug("Invalid SNB file")
47            raise ValueError("Invalid SNB file")
48        log.debug("Handle meta data ...")
49        from calibre.ebooks.conversion.plumber import create_oebbook
50        oeb = create_oebbook(log, None, options,
51                encoding=options.input_encoding, populate=False)
52        meta = snbFile.GetFileStream('snbf/book.snbf')
53        if meta is not None:
54            meta = safe_xml_fromstring(meta)
55            l = {'title'    : './/head/name',
56                  'creator'  : './/head/author',
57                  'language' : './/head/language',
58                  'generator': './/head/generator',
59                  'publisher': './/head/publisher',
60                  'cover'    : './/head/cover', }
61            d = {}
62            for item in l:
63                node = meta.find(l[item])
64                if node is not None:
65                    d[item] = node.text if node.text is not None else ''
66                else:
67                    d[item] = ''
68
69            oeb.metadata.add('title', d['title'])
70            oeb.metadata.add('creator', d['creator'], attrib={'role':'aut'})
71            oeb.metadata.add('language', d['language'].lower().replace('_', '-'))
72            oeb.metadata.add('generator', d['generator'])
73            oeb.metadata.add('publisher', d['publisher'])
74            if d['cover'] != '':
75                oeb.guide.add('cover', 'Cover', d['cover'])
76
77        bookid = str(uuid.uuid4())
78        oeb.metadata.add('identifier', bookid, id='uuid_id', scheme='uuid')
79        for ident in oeb.metadata.identifier:
80            if 'id' in ident.attrib:
81                oeb.uid = oeb.metadata.identifier[0]
82                break
83
84        with TemporaryDirectory('_snb2oeb', keep=True) as tdir:
85            log.debug('Process TOC ...')
86            toc = snbFile.GetFileStream('snbf/toc.snbf')
87            oeb.container = DirContainer(tdir, log)
88            if toc is not None:
89                toc = safe_xml_fromstring(toc)
90                i = 1
91                for ch in toc.find('.//body'):
92                    chapterName = ch.text
93                    chapterSrc = ch.get('src')
94                    fname = 'ch_%d.htm' % i
95                    data = snbFile.GetFileStream('snbc/' + chapterSrc)
96                    if data is None:
97                        continue
98                    snbc = safe_xml_fromstring(data)
99                    lines = []
100                    for line in snbc.find('.//body'):
101                        if line.tag == 'text':
102                            lines.append('<p>%s</p>' % html_encode(line.text))
103                        elif line.tag == 'img':
104                            lines.append('<p><img src="%s" /></p>' % html_encode(line.text))
105                    with open(os.path.join(tdir, fname), 'wb') as f:
106                        f.write((HTML_TEMPLATE % (chapterName, '\n'.join(lines))).encode('utf-8', 'replace'))
107                    oeb.toc.add(ch.text, fname)
108                    id, href = oeb.manifest.generate(id='html',
109                        href=ascii_filename(fname))
110                    item = oeb.manifest.add(id, href, 'text/html')
111                    item.html_input_href = fname
112                    oeb.spine.add(item, True)
113                    i = i + 1
114                imageFiles = snbFile.OutputImageFiles(tdir)
115                for f, m in imageFiles:
116                    id, href = oeb.manifest.generate(id='image',
117                        href=ascii_filename(f))
118                    item = oeb.manifest.add(id, href, m)
119                    item.html_input_href = f
120
121        return oeb
122