diff --git a/src/calibre/ebooks/pdf/render/common.py b/src/calibre/ebooks/pdf/render/common.py index 8470a1b2db..a887e045d7 100644 --- a/src/calibre/ebooks/pdf/render/common.py +++ b/src/calibre/ebooks/pdf/render/common.py @@ -93,24 +93,44 @@ class Name(unicode): in raw] stream.write(b'/'+b''.join(buf)) +def escape_unbalanced_parantheses(bytestring): + indices = [] + bad = [] + ba = bytearray(bytestring) + for i, num in enumerate(ba): + if num == 40: # ( + indices.append(i) + elif num == 41: # ) + if indices: + indices.pop() + else: + bad.append(i) + bad = sorted(list(indices) + bad, reverse=True) + if not bad: + return bytestring + for i in bad: + ba.insert(i, 92) # \ + return bytes(ba) + + class String(unicode): def pdf_serialize(self, stream): - s = self.replace('\\', '\\\\').replace('(', r'\(').replace(')', r'\)') + s = self.replace('\\', '\\\\') try: raw = s.encode('latin1') if raw.startswith(codecs.BOM_UTF16_BE): raw = codecs.BOM_UTF16_BE + s.encode('utf-16-be') except UnicodeEncodeError: raw = codecs.BOM_UTF16_BE + s.encode('utf-16-be') - stream.write(b'('+raw+b')') + stream.write(b'('+escape_unbalanced_parantheses(raw)+b')') class UTF16String(unicode): def pdf_serialize(self, stream): - s = self.replace('\\', '\\\\').replace('(', r'\(').replace(')', r'\)') + s = self.replace('\\', '\\\\') raw = codecs.BOM_UTF16_BE + s.encode('utf-16-be') - stream.write(b'('+raw+b')') + stream.write(b'('+escape_unbalanced_parantheses(raw)+b')') class Dictionary(dict):