Fix Python 3 correctness bugs found in code review
Fix str/bytes and leftover-py2 defects across the plugin, several on live
decryption paths:
- erdr2pml.py: getText() footnote/sidebar handling mixed a bytes
accumulator with str literals and called ord() on a bytes element,
crashing on eReader/.pdb books that contain footnotes or sidebars.
- ion.py: readdecimal() did `[ord(x) for x in self.read(...)]` over
bytes (ord(int)), crashing KFX decryption on Ion DECIMAL values;
printlob() had the same ord()-over-bytes in its debug path.
- zipfilerugged.py: `isinstance(file, unicode)` raised NameError when a
file-like object (not a path string) was passed to the ZipFile.
- utilities.py: SafeUnbuffered.write referenced the undefined `unicode`
(same fix already applied to the obok copy).
- ineptpdf.py: ord(bookkey[0]) over an int in an error-diagnostic print.
- epubfontdecrypt.py: removed a dead py2 itertools.izip fallback.
- convert2xml.py: escapestr did bytes.replace(str, ...).
- kgenpids.py: decode() built a str result then += bytes.
Cleanups from the earlier shim removal: drop now-unused `import sys`
(alfcrypto, utilities, kgenpids); unicode_argv returns list(sys.argv) so
callers can't mutate the process-global sys.argv.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,6 @@
|
||||
# pbkdf2.py Copyright © 2009 Daniel Holth <dholth@fastmail.fm>
|
||||
# pbkdf2.py This code may be freely used and modified for any purpose.
|
||||
|
||||
import sys
|
||||
import hmac
|
||||
from struct import pack
|
||||
import hashlib
|
||||
|
||||
@@ -8,7 +8,7 @@ def unicode_argv(default_name):
|
||||
# On Python 3 sys.argv is already a list of Unicode strings on every
|
||||
# platform, so no special handling is needed.
|
||||
if len(sys.argv) > 0:
|
||||
return sys.argv
|
||||
return list(sys.argv)
|
||||
# if we don't have any arguments at all, just pass back the script name
|
||||
# this should never happen
|
||||
return [default_name]
|
||||
|
||||
@@ -124,10 +124,10 @@ class Dictionary(object):
|
||||
self.pos = 0
|
||||
|
||||
def escapestr(self, str):
|
||||
str = str.replace('&','&')
|
||||
str = str.replace('<','<')
|
||||
str = str.replace('>','>')
|
||||
str = str.replace('=','=')
|
||||
str = str.replace(b'&',b'&')
|
||||
str = str.replace(b'<',b'<')
|
||||
str = str.replace(b'>',b'>')
|
||||
str = str.replace(b'=',b'=')
|
||||
return str
|
||||
|
||||
def lookup(self,val):
|
||||
|
||||
@@ -134,12 +134,7 @@ class Decryptor(object):
|
||||
return data
|
||||
|
||||
def deobfuscate_single_data(self, key, data):
|
||||
try:
|
||||
msg = bytes([c^k for c,k in zip(data, itertools.cycle(key))])
|
||||
except TypeError:
|
||||
# Python 2
|
||||
msg = ''.join(chr(ord(c)^ord(k)) for c,k in itertools.izip(data, itertools.cycle(key)))
|
||||
return msg
|
||||
return bytes([c^k for c,k in zip(data, itertools.cycle(key))])
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -314,7 +314,7 @@ class EreaderProcessor(object):
|
||||
|
||||
# now handle footnotes pages
|
||||
if self.num_footnote_pages > 0:
|
||||
r += '\n'
|
||||
r += b'\n'
|
||||
# the record 0 of the footnote section must pass through the Xor Table to make it useful
|
||||
sect = self.section_reader(self.first_footnote_page)
|
||||
fnote_ids = deXOR(sect, 0, self.xortable)
|
||||
@@ -322,11 +322,11 @@ class EreaderProcessor(object):
|
||||
des = DES.new(fixKey(self.content_key), DES.MODE_ECB)
|
||||
for i in range(1,self.num_footnote_pages):
|
||||
logging.debug('get footnotepage %d', i)
|
||||
id_len = ord(fnote_ids[2])
|
||||
id_len = fnote_ids[2]
|
||||
id = fnote_ids[3:3+id_len]
|
||||
fmarker = '<footnote id="%s">\n' % id
|
||||
fmarker = b'<footnote id="%s">\n' % id
|
||||
fmarker += zlib.decompress(des.decrypt(self.section_reader(self.first_footnote_page + i)))
|
||||
fmarker += '\n</footnote>\n'
|
||||
fmarker += b'\n</footnote>\n'
|
||||
r += fmarker
|
||||
fnote_ids = fnote_ids[id_len+4:]
|
||||
|
||||
@@ -338,18 +338,18 @@ class EreaderProcessor(object):
|
||||
|
||||
# now handle sidebar pages
|
||||
if self.num_sidebar_pages > 0:
|
||||
r += '\n'
|
||||
r += b'\n'
|
||||
# the record 0 of the sidebar section must pass through the Xor Table to make it useful
|
||||
sect = self.section_reader(self.first_sidebar_page)
|
||||
sbar_ids = deXOR(sect, 0, self.xortable)
|
||||
# the remaining records of the sidebar sections need to be decoded with the content_key and zlib inflated
|
||||
des = DES.new(fixKey(self.content_key), DES.MODE_ECB)
|
||||
for i in range(1,self.num_sidebar_pages):
|
||||
id_len = ord(sbar_ids[2])
|
||||
id_len = sbar_ids[2]
|
||||
id = sbar_ids[3:3+id_len]
|
||||
smarker = '<sidebar id="%s">\n' % id
|
||||
smarker = b'<sidebar id="%s">\n' % id
|
||||
smarker += zlib.decompress(des.decrypt(self.section_reader(self.first_sidebar_page + i)))
|
||||
smarker += '\n</sidebar>\n'
|
||||
smarker += b'\n</sidebar>\n'
|
||||
r += smarker
|
||||
sbar_ids = sbar_ids[id_len+4:]
|
||||
|
||||
|
||||
@@ -1624,7 +1624,7 @@ class PDFDocument(object):
|
||||
print("ebx_V is %d and ebx_type is %d" % (ebx_V, ebx_type))
|
||||
print("length is %d and len(bookkey) is %d" % (length, len(bookkey)))
|
||||
if len(bookkey) > 0:
|
||||
print("bookkey[0] is %d" % ord(bookkey[0]))
|
||||
print("bookkey[0] is %d" % bookkey[0])
|
||||
if ebx_V == 3:
|
||||
V = 3
|
||||
else:
|
||||
|
||||
+2
-2
@@ -420,7 +420,7 @@ class BinaryIonParser(object):
|
||||
_assert(self.localremaining <= 8, "Decimal overflow")
|
||||
|
||||
signed = False
|
||||
b = [ord(x) for x in self.read(self.localremaining)]
|
||||
b = list(self.read(self.localremaining))
|
||||
if (b[0] & 0x80) != 0:
|
||||
b[0] = b[0] & 0x7F
|
||||
signed = True
|
||||
@@ -657,7 +657,7 @@ class BinaryIonParser(object):
|
||||
|
||||
result = ""
|
||||
for i in b:
|
||||
result += ("%02x " % ord(i))
|
||||
result += ("%02x " % i)
|
||||
|
||||
if len(result) > 0:
|
||||
result = result[:-1]
|
||||
|
||||
@@ -14,7 +14,6 @@ __version__ = '3.0'
|
||||
# 3.0 - Python 3 for calibre 5.0
|
||||
|
||||
|
||||
import sys
|
||||
import os, csv
|
||||
import binascii
|
||||
import zlib
|
||||
@@ -69,7 +68,7 @@ def encodeHash(data,map):
|
||||
|
||||
# Decode the string in data with the characters in map. Returns the decoded bytes
|
||||
def decode(data,map):
|
||||
result = ''
|
||||
result = b''
|
||||
for i in range (0,len(data)-1,2):
|
||||
high = map.find(data[i])
|
||||
low = map.find(data[i+1])
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
#@@CALIBRE_COMPAT_CODE@@
|
||||
|
||||
import sys
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
|
||||
def uStrCmp (s1, s2, caseless=False):
|
||||
@@ -29,8 +27,7 @@ class SafeUnbuffered:
|
||||
if self.encoding == None:
|
||||
self.encoding = "utf-8"
|
||||
def write(self, data):
|
||||
if isinstance(data,str) or isinstance(data,unicode):
|
||||
# str for Python3, unicode for Python2
|
||||
if isinstance(data,str):
|
||||
data = data.encode(self.encoding,"replace")
|
||||
try:
|
||||
buffer = getattr(self.stream, 'buffer', self.stream)
|
||||
|
||||
@@ -676,8 +676,7 @@ class ZipFile:
|
||||
self.comment = b''
|
||||
|
||||
# Check if we were passed a file-like object
|
||||
# "str" is python3, "unicode" is python2
|
||||
if isinstance(file, str) or isinstance(file, unicode):
|
||||
if isinstance(file, str):
|
||||
self._filePassed = 0
|
||||
self.filename = file
|
||||
modeDict = {'r' : 'rb', 'w': 'wb', 'a' : 'r+b'}
|
||||
|
||||
Reference in New Issue
Block a user