mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Edit book: Fix obfuscated fonts in EPUB files not being handled correctly when editing the book (obfuscated fonts would get corrupted when making changes).
This commit is contained in:
parent
65b1c5ac57
commit
8e3c1c7425
@ -11,17 +11,18 @@ from calibre.customize.conversion import InputFormatPlugin, OptionRecommendation
|
|||||||
ADOBE_OBFUSCATION = 'http://ns.adobe.com/pdf/enc#RC'
|
ADOBE_OBFUSCATION = 'http://ns.adobe.com/pdf/enc#RC'
|
||||||
IDPF_OBFUSCATION = 'http://www.idpf.org/2008/embedding'
|
IDPF_OBFUSCATION = 'http://www.idpf.org/2008/embedding'
|
||||||
|
|
||||||
def decrypt_font(key, path, algorithm):
|
def decrypt_font_data(key, data, algorithm):
|
||||||
is_adobe = algorithm == ADOBE_OBFUSCATION
|
is_adobe = algorithm == ADOBE_OBFUSCATION
|
||||||
crypt_len = 1024 if is_adobe else 1040
|
crypt_len = 1024 if is_adobe else 1040
|
||||||
with open(path, 'rb') as f:
|
crypt = bytearray(data[:crypt_len])
|
||||||
raw = f.read()
|
|
||||||
crypt = bytearray(raw[:crypt_len])
|
|
||||||
key = cycle(iter(bytearray(key)))
|
key = cycle(iter(bytearray(key)))
|
||||||
decrypt = bytes(bytearray(x^key.next() for x in crypt))
|
decrypt = bytes(bytearray(x^key.next() for x in crypt))
|
||||||
with open(path, 'wb') as f:
|
return decrypt + data[crypt_len:]
|
||||||
f.write(decrypt)
|
|
||||||
f.write(raw[crypt_len:])
|
def decrypt_font(key, path, algorithm):
|
||||||
|
with open(path, 'r+b') as f:
|
||||||
|
data = decrypt_font_data(key, f.read(), algorithm)
|
||||||
|
f.seek(0), f.truncate(), f.write(data)
|
||||||
|
|
||||||
class EPUBInput(InputFormatPlugin):
|
class EPUBInput(InputFormatPlugin):
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ from calibre.customize.ui import (plugin_for_input_format,
|
|||||||
plugin_for_output_format)
|
plugin_for_output_format)
|
||||||
from calibre.ebooks.chardet import xml_to_unicode
|
from calibre.ebooks.chardet import xml_to_unicode
|
||||||
from calibre.ebooks.conversion.plugins.epub_input import (
|
from calibre.ebooks.conversion.plugins.epub_input import (
|
||||||
ADOBE_OBFUSCATION, IDPF_OBFUSCATION, decrypt_font)
|
ADOBE_OBFUSCATION, IDPF_OBFUSCATION, decrypt_font_data)
|
||||||
from calibre.ebooks.conversion.preprocess import HTMLPreProcessor, CSSPreProcessor as cssp
|
from calibre.ebooks.conversion.preprocess import HTMLPreProcessor, CSSPreProcessor as cssp
|
||||||
from calibre.ebooks.mobi import MobiError
|
from calibre.ebooks.mobi import MobiError
|
||||||
from calibre.ebooks.mobi.reader.headers import MetadataHeader
|
from calibre.ebooks.mobi.reader.headers import MetadataHeader
|
||||||
@ -969,27 +969,35 @@ class EpubContainer(Container):
|
|||||||
key = None
|
key = None
|
||||||
|
|
||||||
for font, alg in fonts.iteritems():
|
for font, alg in fonts.iteritems():
|
||||||
path = self.name_path_map[font]
|
|
||||||
tkey = key if alg == ADOBE_OBFUSCATION else idpf_key
|
tkey = key if alg == ADOBE_OBFUSCATION else idpf_key
|
||||||
if not tkey:
|
if not tkey:
|
||||||
raise InvalidBook('Failed to find obfuscation key')
|
raise InvalidBook('Failed to find obfuscation key')
|
||||||
decrypt_font(tkey, path, alg)
|
raw = self.raw_data(font, decode=False)
|
||||||
|
raw = decrypt_font_data(tkey, raw, alg)
|
||||||
|
with self.open(font, 'wb') as f:
|
||||||
|
f.write(raw)
|
||||||
self.obfuscated_fonts[font] = (alg, tkey)
|
self.obfuscated_fonts[font] = (alg, tkey)
|
||||||
|
|
||||||
def commit(self, outpath=None, keep_parsed=False):
|
def commit(self, outpath=None, keep_parsed=False):
|
||||||
super(EpubContainer, self).commit(keep_parsed=keep_parsed)
|
super(EpubContainer, self).commit(keep_parsed=keep_parsed)
|
||||||
|
restore_fonts = {}
|
||||||
for name in self.obfuscated_fonts:
|
for name in self.obfuscated_fonts:
|
||||||
if name not in self.name_path_map:
|
if name not in self.name_path_map:
|
||||||
continue
|
continue
|
||||||
alg, key = self.obfuscated_fonts[name]
|
alg, key = self.obfuscated_fonts[name]
|
||||||
# Decrypting and encrypting are the same operation (XOR with key)
|
# Decrypting and encrypting are the same operation (XOR with key)
|
||||||
decrypt_font(key, self.name_path_map[name], alg)
|
restore_fonts[name] = data = self.raw_data(name, decode=False)
|
||||||
|
with self.open(name, 'wb') as f:
|
||||||
|
f.write(decrypt_font_data(key, data, alg))
|
||||||
if outpath is None:
|
if outpath is None:
|
||||||
outpath = self.pathtoepub
|
outpath = self.pathtoepub
|
||||||
from calibre.ebooks.tweak import zip_rebuilder
|
from calibre.ebooks.tweak import zip_rebuilder
|
||||||
with open(join(self.root, 'mimetype'), 'wb') as f:
|
with open(join(self.root, 'mimetype'), 'wb') as f:
|
||||||
f.write(guess_type('a.epub'))
|
f.write(guess_type('a.epub'))
|
||||||
zip_rebuilder(self.root, outpath)
|
zip_rebuilder(self.root, outpath)
|
||||||
|
for name, data in restore_fonts.iteritems():
|
||||||
|
with self.open(name, 'wb') as f:
|
||||||
|
f.write(data)
|
||||||
|
|
||||||
@dynamic_property
|
@dynamic_property
|
||||||
def path_to_ebook(self):
|
def path_to_ebook(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user