#!/usr/bin/env python # -*- coding: utf-8 -*- # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab from __future__ import unicode_literals, division, absolute_import, print_function from .compatibility_utils import text_type from . import unipath from .unipath import pathof DUMP = False """ Set to True to dump all possible information. """ import os import re # note: re requites the pattern to be the exact same type as the data to be searched in python3 # but u"" is not allowed for the pattern itself only b"" import zipfile import binascii from .mobi_utils import mangle_fonts class unpackException(Exception): pass class ZipInfo(zipfile.ZipInfo): def __init__(self, *args, **kwargs): if "compress_type" in kwargs: compress_type = kwargs.pop("compress_type") super(ZipInfo, self).__init__(*args, **kwargs) self.compress_type = compress_type class fileNames: def __init__(self, infile, outdir): self.infile = infile self.outdir = outdir if not unipath.exists(self.outdir): unipath.mkdir(self.outdir) self.mobi7dir = os.path.join(self.outdir, "mobi7") if not unipath.exists(self.mobi7dir): unipath.mkdir(self.mobi7dir) self.imgdir = os.path.join(self.mobi7dir, "Images") if not unipath.exists(self.imgdir): unipath.mkdir(self.imgdir) self.hdimgdir = os.path.join(self.outdir, "HDImages") if not unipath.exists(self.hdimgdir): unipath.mkdir(self.hdimgdir) self.outbase = os.path.join( self.outdir, os.path.splitext(os.path.split(infile)[1])[0] ) def getInputFileBasename(self): return os.path.splitext(os.path.basename(self.infile))[0] def makeK8Struct(self): self.k8dir = os.path.join(self.outdir, "mobi8") if not unipath.exists(self.k8dir): unipath.mkdir(self.k8dir) self.k8metainf = os.path.join(self.k8dir, "META-INF") if not unipath.exists(self.k8metainf): unipath.mkdir(self.k8metainf) self.k8oebps = os.path.join(self.k8dir, "OEBPS") if not unipath.exists(self.k8oebps): unipath.mkdir(self.k8oebps) self.k8images = os.path.join(self.k8oebps, "Images") if not unipath.exists(self.k8images): unipath.mkdir(self.k8images) self.k8fonts = os.path.join(self.k8oebps, "Fonts") if not unipath.exists(self.k8fonts): unipath.mkdir(self.k8fonts) self.k8styles = os.path.join(self.k8oebps, "Styles") if not unipath.exists(self.k8styles): unipath.mkdir(self.k8styles) self.k8text = os.path.join(self.k8oebps, "Text") if not unipath.exists(self.k8text): unipath.mkdir(self.k8text) # recursive zip creation support routine def zipUpDir(self, myzip, tdir, localname): currentdir = tdir if localname != "": currentdir = os.path.join(currentdir, localname) list = unipath.listdir(currentdir) for file in list: afilename = file localfilePath = os.path.join(localname, afilename) realfilePath = os.path.join(currentdir, file) if unipath.isfile(realfilePath): myzip.write( pathof(realfilePath), pathof(localfilePath), zipfile.ZIP_DEFLATED ) elif unipath.isdir(realfilePath): self.zipUpDir(myzip, tdir, localfilePath) def makeEPUB(self, usedmap, obfuscate_data, uid): bname = os.path.join(self.k8dir, self.getInputFileBasename() + ".epub") # Create an encryption key for Adobe font obfuscation # based on the epub's uid if isinstance(uid, text_type): uid = uid.encode("ascii") if obfuscate_data: key = re.sub(br"[^a-fA-F0-9]", b"", uid) key = binascii.unhexlify((key + key)[:32]) # copy over all images and fonts that are actually used in the ebook # and remove all font files from mobi7 since not supported imgnames = unipath.listdir(self.imgdir) for name in imgnames: if usedmap.get(name, "not used") == "used": filein = os.path.join(self.imgdir, name) if name.endswith(".ttf"): fileout = os.path.join(self.k8fonts, name) elif name.endswith(".otf"): fileout = os.path.join(self.k8fonts, name) elif name.endswith(".failed"): fileout = os.path.join(self.k8fonts, name) else: fileout = os.path.join(self.k8images, name) data = b"" with open(pathof(filein), "rb") as f: data = f.read() if obfuscate_data: if name in obfuscate_data: data = mangle_fonts(key, data) open(pathof(fileout), "wb").write(data) if name.endswith(".ttf") or name.endswith(".otf"): os.remove(pathof(filein)) # opf file name hard coded to "content.opf" container = '\n' container += '\n' container += " \n" container += '' container += " \n\n" fileout = os.path.join(self.k8metainf, "container.xml") with open(pathof(fileout), "wb") as f: f.write(container.encode("utf-8")) if obfuscate_data: encryption = '\n' for font in obfuscate_data: encryption += " \n" encryption += ' \n' encryption += " \n" encryption += ( ' \n' ) encryption += " \n" encryption += " \n" encryption += "\n" fileout = os.path.join(self.k8metainf, "encryption.xml") with open(pathof(fileout), "wb") as f: f.write(encryption.encode("utf-8")) # ready to build epub self.outzip = zipfile.ZipFile(pathof(bname), "w") # add the mimetype file uncompressed mimetype = b"application/epub+zip" fileout = os.path.join(self.k8dir, "mimetype") with open(pathof(fileout), "wb") as f: f.write(mimetype) nzinfo = ZipInfo("mimetype", compress_type=zipfile.ZIP_STORED) nzinfo.external_attr = 0o600 << 16 # make this a normal file self.outzip.writestr(nzinfo, mimetype) self.zipUpDir(self.outzip, self.k8dir, "META-INF") self.zipUpDir(self.outzip, self.k8dir, "OEBPS") self.outzip.close()