py3: port use as base64 module

This commit is contained in:
Kovid Goyal 2019-03-30 12:52:32 +05:30
parent a0afe775ba
commit fcd5700306
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
32 changed files with 205 additions and 106 deletions

View File

@ -6,7 +6,6 @@ __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import os, time import os, time
from base64 import b64decode
from datetime import date from datetime import date
from calibre import prints, guess_type, isbytestring, fsync from calibre import prints, guess_type, isbytestring, fsync
@ -16,6 +15,7 @@ from calibre.constants import DEBUG, preferred_encoding
from calibre.ebooks.chardet import xml_to_unicode from calibre.ebooks.chardet import xml_to_unicode
from calibre.ebooks.metadata import authors_to_string, title_sort, \ from calibre.ebooks.metadata import authors_to_string, title_sort, \
authors_to_sort_string authors_to_sort_string
from polyglot.binary import from_base64_bytes
''' '''
cahceExt.xml cahceExt.xml
@ -380,8 +380,8 @@ class XMLCache(object):
'descendant::*[local-name()="png"]'): 'descendant::*[local-name()="png"]'):
if img.text: if img.text:
try: try:
raw = b64decode(img.text.strip()) raw = from_base64_bytes(img.text.strip())
except: except Exception:
continue continue
book.thumbnail = raw book.thumbnail = raw
break break

View File

@ -10,12 +10,12 @@ __docformat__ = 'restructuredtext en'
def base64_decode(raw): def base64_decode(raw):
from io import BytesIO from io import BytesIO
from base64 import b64decode from polyglot.binary import from_base64_bytes
# First try the python implementation as it is faster # First try the python implementation as it is faster
try: try:
return b64decode(raw) return from_base64_bytes(raw)
except TypeError: except Exception:
pass pass
# Try a more robust version (adapted from FBReader sources) # Try a more robust version (adapted from FBReader sources)
@ -49,5 +49,3 @@ def base64_decode(raw):
tot >>= 8 tot >>= 8
out.write(bytes(triple)) out.write(bytes(triple))
return out.getvalue() return out.getvalue()

View File

@ -9,7 +9,6 @@ Transform OEB content into FB2 markup
''' '''
import re, textwrap, uuid import re, textwrap, uuid
from base64 import b64encode
from datetime import datetime from datetime import datetime
from lxml import etree from lxml import etree
@ -20,6 +19,7 @@ from calibre.utils.localization import lang_as_iso639_1
from calibre.utils.img import save_cover_data_to from calibre.utils.img import save_cover_data_to
from calibre.ebooks.oeb.base import urlnormalize from calibre.ebooks.oeb.base import urlnormalize
from polyglot.builtins import unicode_type, string_or_bytes from polyglot.builtins import unicode_type, string_or_bytes
from polyglot.binary import as_base64_unicode
class FB2MLizer(object): class FB2MLizer(object):
@ -308,9 +308,9 @@ class FB2MLizer(object):
try: try:
if item.media_type != 'image/jpeg': if item.media_type != 'image/jpeg':
imdata = save_cover_data_to(item.data, compression_quality=70) imdata = save_cover_data_to(item.data, compression_quality=70)
raw_data = b64encode(imdata) raw_data = as_base64_unicode(imdata)
else: else:
raw_data = b64encode(item.data) raw_data = as_base64_unicode(item.data)
# Don't put the encoded image on a single line. # Don't put the encoded image on a single line.
data = '' data = ''
col = 1 col = 1

View File

@ -5,7 +5,6 @@ Created on 4 Jun 2010
''' '''
from __future__ import print_function from __future__ import print_function
from base64 import b64encode, b64decode
import json, traceback import json, traceback
from datetime import datetime, time from datetime import datetime, time
@ -14,6 +13,7 @@ from calibre.constants import filesystem_encoding, preferred_encoding
from calibre.library.field_metadata import FieldMetadata from calibre.library.field_metadata import FieldMetadata
from calibre import isbytestring from calibre import isbytestring
from polyglot.builtins import iteritems, itervalues from polyglot.builtins import iteritems, itervalues
from polyglot.binary import as_base64_unicode, from_base64_bytes
# Translate datetimes to and from strings. The string form is the datetime in # Translate datetimes to and from strings. The string form is the datetime in
# UTC. The returned date is also UTC # UTC. The returned date is also UTC
@ -57,7 +57,7 @@ def encode_thumbnail(thumbnail):
thumbnail = (width, height, thumbnail) thumbnail = (width, height, thumbnail)
except Exception: except Exception:
return None return None
return (thumbnail[0], thumbnail[1], b64encode(str(thumbnail[2]))) return (thumbnail[0], thumbnail[1], as_base64_unicode(thumbnail[2]))
def decode_thumbnail(tup): def decode_thumbnail(tup):
@ -66,7 +66,7 @@ def decode_thumbnail(tup):
''' '''
if tup is None: if tup is None:
return None return None
return (tup[0], tup[1], b64decode(tup[2])) return (tup[0], tup[1], from_base64_bytes(tup[2]))
def object_to_unicode(obj, enc=preferred_encoding): def object_to_unicode(obj, enc=preferred_encoding):

View File

@ -4,13 +4,13 @@
from __future__ import absolute_import, division, print_function, unicode_literals from __future__ import absolute_import, division, print_function, unicode_literals
import base64
from calibre.constants import preferred_encoding from calibre.constants import preferred_encoding
from calibre.ebooks.metadata.book import SERIALIZABLE_FIELDS from calibre.ebooks.metadata.book import SERIALIZABLE_FIELDS
from calibre.ebooks.metadata.book.base import Metadata from calibre.ebooks.metadata.book.base import Metadata
from calibre.utils.imghdr import what from calibre.utils.imghdr import what
from polyglot.builtins import iteritems, unicode_type from polyglot.builtins import iteritems, unicode_type
from polyglot.binary import as_base64_unicode
def ensure_unicode(obj, enc=preferred_encoding): def ensure_unicode(obj, enc=preferred_encoding):
@ -52,7 +52,7 @@ def metadata_as_dict(mi, encode_cover_data=False):
ans[field] = ensure_unicode(val) ans[field] = ensure_unicode(val)
if mi.cover_data and mi.cover_data[1]: if mi.cover_data and mi.cover_data[1]:
if encode_cover_data: if encode_cover_data:
ans['cover_data'] = [mi.cover_data[0], base64.standard_b64encode(bytes(mi.cover_data[1]))] ans['cover_data'] = [mi.cover_data[0], as_base64_unicode(mi.cover_data[1])]
else: else:
ans['cover_data'] = mi.cover_data ans['cover_data'] = mi.cover_data
um = mi.get_all_user_metadata(False) um = mi.get_all_user_metadata(False)

View File

@ -8,7 +8,6 @@ __copyright__ = '2011, Roman Mukhin <ramses_ru at hotmail.com>, '\
import os, random import os, random
from functools import partial from functools import partial
from string import ascii_letters, digits from string import ascii_letters, digits
from base64 import b64encode
from lxml import etree from lxml import etree
@ -19,6 +18,7 @@ from calibre import guess_type, guess_all_extensions, prints, force_unicode
from calibre.ebooks.metadata import MetaInformation, check_isbn from calibre.ebooks.metadata import MetaInformation, check_isbn
from calibre.ebooks.chardet import xml_to_unicode from calibre.ebooks.chardet import xml_to_unicode
from polyglot.builtins import unicode_type from polyglot.builtins import unicode_type
from polyglot.binary import as_base64_unicode
NAMESPACES = { NAMESPACES = {
@ -383,7 +383,7 @@ def _rnd_pic_file_name(prefix='calibre_cover_', size=32, ext='jpg'):
def _encode_into_jpeg(data): def _encode_into_jpeg(data):
data = save_cover_data_to(data) data = save_cover_data_to(data)
return b64encode(data) return as_base64_unicode(data)
def _set_cover(title_info, mi, ctx): def _set_cover(title_info, mi, ctx):

View File

@ -8,7 +8,7 @@ from __future__ import (unicode_literals, division, absolute_import,
# Based on work of John Howell reversing the KFX format # Based on work of John Howell reversing the KFX format
# https://www.mobileread.com/forums/showpost.php?p=3176029&postcount=89 # https://www.mobileread.com/forums/showpost.php?p=3176029&postcount=89
import struct, sys, base64, re import struct, sys, re
from collections import defaultdict from collections import defaultdict
from calibre.ebooks.metadata.book.base import Metadata from calibre.ebooks.metadata.book.base import Metadata
@ -19,6 +19,7 @@ from calibre.utils.date import parse_only_date
from calibre.utils.localization import canonicalize_lang from calibre.utils.localization import canonicalize_lang
from calibre.utils.imghdr import identify from calibre.utils.imghdr import identify
from polyglot.builtins import unicode_type from polyglot.builtins import unicode_type
from polyglot.binary import as_base64_bytes, from_base64_bytes
class InvalidKFX(ValueError): class InvalidKFX(ValueError):
@ -155,7 +156,7 @@ class Entity(PackedBlock):
if PackedData(self.entity_data).unpack_one('4s') == ION_MAGIC: if PackedData(self.entity_data).unpack_one('4s') == ION_MAGIC:
entity_value = PackedIon(self.entity_data).decode() entity_value = PackedIon(self.entity_data).decode()
else: else:
entity_value = base64.b64encode(self.entity_data) entity_value = as_base64_bytes(self.entity_data)
return (property_name(self.entity_type), property_name(self.entity_id), entity_value) return (property_name(self.entity_type), property_name(self.entity_id), entity_value)
@ -343,8 +344,8 @@ def read_metadata_kfx(stream, read_cover=True):
mi.publisher = get('publisher') mi.publisher = get('publisher')
if read_cover and m[COVER_KEY]: if read_cover and m[COVER_KEY]:
try: try:
data = base64.standard_b64decode(m[COVER_KEY]) data = from_base64_bytes(m[COVER_KEY])
fmt, w, h = identify(bytes(data)) fmt, w, h = identify(data)
except Exception: except Exception:
w, h, fmt = 0, 0, None w, h, fmt = 0, 0, None
if fmt and w > -1 and h > -1: if fmt and w > -1 and h > -1:

View File

@ -10,7 +10,6 @@ import os
import posixpath import posixpath
import re import re
import shutil import shutil
from base64 import standard_b64decode
from collections import defaultdict from collections import defaultdict
from contextlib import closing from contextlib import closing
from functools import partial from functools import partial
@ -25,6 +24,7 @@ from calibre.ptempfile import TemporaryDirectory
from calibre.web import get_download_filename_from_response from calibre.web import get_download_filename_from_response
from polyglot.builtins import iteritems from polyglot.builtins import iteritems
from polyglot.urllib import urlopen, urlparse from polyglot.urllib import urlopen, urlparse
from polyglot.binary import from_base64_bytes
def is_external(url): def is_external(url):
@ -117,7 +117,7 @@ def download_one(tdir, timeout, progress_report, data_uri_map, url):
parts = prefix.split(';') parts = prefix.split(';')
if parts and parts[-1].lower() == 'base64': if parts and parts[-1].lower() == 'base64':
payload = re.sub(r'\s+', '', payload) payload = re.sub(r'\s+', '', payload)
payload = standard_b64decode(payload) payload = from_base64_bytes(payload)
else: else:
payload = payload.encode('utf-8') payload = payload.encode('utf-8')
seen_before = data_uri_map.get(payload) seen_before = data_uri_map.get(payload)

View File

@ -28,9 +28,9 @@ class DataURL(object):
continue continue
if ';base64' in header: if ';base64' in header:
data = re.sub(r'\s+', '', data) data = re.sub(r'\s+', '', data)
from base64 import b64decode from polyglot.binary import from_base64_bytes
try: try:
data = b64decode(data) data = from_base64_bytes(data)
except Exception: except Exception:
self.log.error('Found invalid base64 encoded data URI, ignoring it') self.log.error('Found invalid base64 encoded data URI, ignoring it')
continue continue

View File

@ -6,7 +6,7 @@ __license__ = 'GPL 3'
__copyright__ = '2011, John Schember <john@nachtimwald.com>' __copyright__ = '2011, John Schember <john@nachtimwald.com>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import traceback, base64 import traceback
from contextlib import closing from contextlib import closing
from threading import Thread from threading import Thread
@ -15,6 +15,7 @@ from calibre.constants import DEBUG
from calibre.utils.img import scale_image from calibre.utils.img import scale_image
from polyglot.builtins import range from polyglot.builtins import range
from polyglot.queue import Queue from polyglot.queue import Queue
from polyglot.binary import from_base64_bytes
class GenericDownloadThreadPool(object): class GenericDownloadThreadPool(object):
@ -143,7 +144,7 @@ class CoverThreadPool(GenericDownloadThreadPool):
def decode_data_url(url): def decode_data_url(url):
return base64.standard_b64decode(url.partition(',')[2]) return from_base64_bytes(url.partition(',')[2])
class CoverThread(Thread): class CoverThread(Thread):

View File

@ -24,6 +24,15 @@ from calibre.gui2.store.search_result import SearchResult
from calibre.gui2.store.web_store_dialog import WebStoreDialog from calibre.gui2.store.web_store_dialog import WebStoreDialog
def as_base64(data):
if not isinstance(data, bytes):
data = data.encode('utf-8')
ans = b64encode(data)
if isinstance(ans, bytes):
ans = ans.decode('ascii')
return ans
class EbookpointStore(BasicStoreConfig, StorePlugin): class EbookpointStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
@ -31,11 +40,11 @@ class EbookpointStore(BasicStoreConfig, StorePlugin):
url = 'http://ebookpoint.pl/' url = 'http://ebookpoint.pl/'
aff_url = aff_root + str(b64encode(url)) aff_url = aff_root + as_base64(url)
detail_url = None detail_url = None
if detail_item: if detail_item:
detail_url = aff_root + str(b64encode(detail_item)) detail_url = aff_root + as_base64(detail_item)
if external or self.config.get('open_external', False): if external or self.config.get('open_external', False):
open_url(QUrl(url_slash_cleaner(detail_url if detail_url else aff_url))) open_url(QUrl(url_slash_cleaner(detail_url if detail_url else aff_url)))

View File

@ -24,6 +24,15 @@ from calibre.gui2.store.search_result import SearchResult
from calibre.gui2.store.web_store_dialog import WebStoreDialog from calibre.gui2.store.web_store_dialog import WebStoreDialog
def as_base64(data):
if not isinstance(data, bytes):
data = data.encode('utf-8')
ans = b64encode(data)
if isinstance(ans, bytes):
ans = ans.decode('ascii')
return ans
class EmpikStore(BasicStoreConfig, StorePlugin): class EmpikStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
@ -31,11 +40,11 @@ class EmpikStore(BasicStoreConfig, StorePlugin):
url = 'http://www.empik.com/ebooki' url = 'http://www.empik.com/ebooki'
aff_url = aff_root + str(b64encode(url)) aff_url = aff_root + as_base64(url)
detail_url = None detail_url = None
if detail_item: if detail_item:
detail_url = aff_root + str(b64encode(detail_item)) detail_url = aff_root + as_base64(detail_item)
if external or self.config.get('open_external', False): if external or self.config.get('open_external', False):
open_url(QUrl(url_slash_cleaner(detail_url if detail_url else aff_url))) open_url(QUrl(url_slash_cleaner(detail_url if detail_url else aff_url)))
@ -82,4 +91,3 @@ class EmpikStore(BasicStoreConfig, StorePlugin):
s.formats = formats.upper().strip() s.formats = formats.upper().strip()
yield s yield s

View File

@ -52,7 +52,7 @@ def search(query, max_results=10, timeout=60, write_raw_to=None):
# We could use the <link rel="alternate" type="text/html" ...> tag from the # We could use the <link rel="alternate" type="text/html" ...> tag from the
# detail odps page but this is easier. # detail odps page but this is easier.
id = fix_url(''.join(data.xpath('./*[local-name() = "id"]/text()')).strip()) id = fix_url(''.join(data.xpath('./*[local-name() = "id"]/text()')).strip())
s.detail_item = url_slash_cleaner('%s/ebooks/%s' % (web_url, re.sub('[^\d]', '', id))) s.detail_item = url_slash_cleaner('%s/ebooks/%s' % (web_url, re.sub(r'[^\d]', '', id)))
s.title = ' '.join(data.xpath('./*[local-name() = "title"]//text()')).strip() s.title = ' '.join(data.xpath('./*[local-name() = "title"]//text()')).strip()
s.author = ', '.join(data.xpath('./*[local-name() = "content"]//text()')).strip() s.author = ', '.join(data.xpath('./*[local-name() = "content"]//text()')).strip()
if not s.title or not s.author: if not s.title or not s.author:
@ -83,7 +83,10 @@ def search(query, max_results=10, timeout=60, write_raw_to=None):
href = fix_url(href) href = fix_url(href)
if rel in ('http://opds-spec.org/thumbnail', 'http://opds-spec.org/image/thumbnail'): if rel in ('http://opds-spec.org/thumbnail', 'http://opds-spec.org/image/thumbnail'):
if href.startswith('data:image/png;base64,'): if href.startswith('data:image/png;base64,'):
s.cover_data = base64.b64decode(href.replace('data:image/png;base64,', '')) cdata = href.replace('data:image/png;base64,', '')
if not isinstance(cdata, bytes):
cdata = cdata.encode('ascii')
s.cover_data = base64.b64decode(cdata)
yield s yield s
@ -123,6 +126,7 @@ class GutenbergStore(BasicStoreConfig, OpenSearchOPDSStore):
for result in search(query, max_results, timeout): for result in search(query, max_results, timeout):
yield result yield result
if __name__ == '__main__': if __name__ == '__main__':
import sys import sys
for result in search(' '.join(sys.argv[1:]), write_raw_to='/t/gutenberg.html'): for result in search(' '.join(sys.argv[1:]), write_raw_to='/t/gutenberg.html'):

View File

@ -24,6 +24,15 @@ from calibre.gui2.store.search_result import SearchResult
from calibre.gui2.store.web_store_dialog import WebStoreDialog from calibre.gui2.store.web_store_dialog import WebStoreDialog
def as_base64(data):
if not isinstance(data, bytes):
data = data.encode('utf-8')
ans = b64encode(data)
if isinstance(ans, bytes):
ans = ans.decode('ascii')
return ans
class LegimiStore(BasicStoreConfig, StorePlugin): class LegimiStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
@ -31,11 +40,11 @@ class LegimiStore(BasicStoreConfig, StorePlugin):
url = 'https://www.legimi.pl/ebooki/' url = 'https://www.legimi.pl/ebooki/'
aff_url = aff_root + str(b64encode(url)) aff_url = aff_root + as_base64(url)
detail_url = None detail_url = None
if detail_item: if detail_item:
detail_url = aff_root + str(b64encode(detail_item)) detail_url = aff_root + as_base64(detail_item)
if external or self.config.get('open_external', False): if external or self.config.get('open_external', False):
open_url(QUrl(url_slash_cleaner(detail_url if detail_url else aff_url))) open_url(QUrl(url_slash_cleaner(detail_url if detail_url else aff_url)))

View File

@ -23,17 +23,26 @@ from calibre.gui2.store.search_result import SearchResult
from calibre.gui2.store.web_store_dialog import WebStoreDialog from calibre.gui2.store.web_store_dialog import WebStoreDialog
def as_base64(data):
if not isinstance(data, bytes):
data = data.encode('utf-8')
ans = b64encode(data)
if isinstance(ans, bytes):
ans = ans.decode('ascii')
return ans
class PublioStore(BasicStoreConfig, StorePlugin): class PublioStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
aff_root = 'https://www.a4b-tracking.com/pl/stat-click-text-link/29/58/' aff_root = 'https://www.a4b-tracking.com/pl/stat-click-text-link/29/58/'
url = 'http://www.publio.pl/' url = 'http://www.publio.pl/'
aff_url = aff_root + str(b64encode(url)) aff_url = aff_root + as_base64(url)
detail_url = None detail_url = None
if detail_item: if detail_item:
detail_url = aff_root + str(b64encode(detail_item)) detail_url = aff_root + as_base64(detail_item)
if external or self.config.get('open_external', False): if external or self.config.get('open_external', False):
open_url(QUrl(url_slash_cleaner(detail_url if detail_url else aff_url))) open_url(QUrl(url_slash_cleaner(detail_url if detail_url else aff_url)))

View File

@ -23,6 +23,15 @@ from calibre.gui2.store.search_result import SearchResult
from calibre.gui2.store.web_store_dialog import WebStoreDialog from calibre.gui2.store.web_store_dialog import WebStoreDialog
def as_base64(data):
if not isinstance(data, bytes):
data = data.encode('utf-8')
ans = b64encode(data)
if isinstance(ans, bytes):
ans = ans.decode('ascii')
return ans
class SwiatEbookowStore(BasicStoreConfig, StorePlugin): class SwiatEbookowStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
@ -30,11 +39,11 @@ class SwiatEbookowStore(BasicStoreConfig, StorePlugin):
url = 'https://www.swiatebookow.pl/' url = 'https://www.swiatebookow.pl/'
aff_url = aff_root + str(b64encode(url)) aff_url = aff_root + as_base64(url)
detail_url = None detail_url = None
if detail_item: if detail_item:
detail_url = aff_root + str(b64encode(detail_item)) detail_url = aff_root + as_base64(detail_item)
if external or self.config.get('open_external', False): if external or self.config.get('open_external', False):
open_url(QUrl(url_slash_cleaner(detail_url if detail_url else aff_url))) open_url(QUrl(url_slash_cleaner(detail_url if detail_url else aff_url)))

View File

@ -24,6 +24,15 @@ from calibre.gui2.store.search_result import SearchResult
from calibre.gui2.store.web_store_dialog import WebStoreDialog from calibre.gui2.store.web_store_dialog import WebStoreDialog
def as_base64(data):
if not isinstance(data, bytes):
data = data.encode('utf-8')
ans = b64encode(data)
if isinstance(ans, bytes):
ans = ans.decode('ascii')
return ans
class VirtualoStore(BasicStoreConfig, StorePlugin): class VirtualoStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False): def open(self, parent=None, detail_item=None, external=False):
@ -31,11 +40,11 @@ class VirtualoStore(BasicStoreConfig, StorePlugin):
url = 'http://virtualo.pl/ebook/c2/' url = 'http://virtualo.pl/ebook/c2/'
aff_url = aff_root + str(b64encode(url)) aff_url = aff_root + as_base64(url)
detail_url = None detail_url = None
if detail_item: if detail_item:
detail_url = aff_root + str(b64encode(detail_item)) detail_url = aff_root + as_base64(detail_item)
if external or self.config.get('open_external', False): if external or self.config.get('open_external', False):
open_url(QUrl(url_slash_cleaner(detail_url if detail_url else aff_url))) open_url(QUrl(url_slash_cleaner(detail_url if detail_url else aff_url)))
@ -75,7 +84,7 @@ class VirtualoStore(BasicStoreConfig, StorePlugin):
s.cover_url = cover_url s.cover_url = cover_url
s.title = title.strip() s.title = title.strip()
s.author = author.strip() s.author = author.strip()
s.price = re.sub('\.',',',price.strip()) s.price = re.sub(r'\.',',',price.strip())
s.detail_item = id s.detail_item = id
s.formats = ', '.join(formats).upper() s.formats = ', '.join(formats).upper()
s.drm = SearchResult.DRM_UNLOCKED if nodrm else SearchResult.DRM_LOCKED s.drm = SearchResult.DRM_UNLOCKED if nodrm else SearchResult.DRM_LOCKED

View File

@ -23,6 +23,15 @@ from calibre.gui2.store.search_result import SearchResult
from calibre.gui2.store.web_store_dialog import WebStoreDialog from calibre.gui2.store.web_store_dialog import WebStoreDialog
def as_base64(data):
if not isinstance(data, bytes):
data = data.encode('utf-8')
ans = b64encode(data)
if isinstance(ans, bytes):
ans = ans.decode('ascii')
return ans
def search(query, max_results=10, timeout=60): def search(query, max_results=10, timeout=60):
url = 'http://woblink.com/publication/ajax?mode=none&query=' + urllib.quote_plus(query.encode('utf-8')) url = 'http://woblink.com/publication/ajax?mode=none&query=' + urllib.quote_plus(query.encode('utf-8'))
if max_results > 10: if max_results > 10:
@ -79,11 +88,11 @@ class WoblinkStore(BasicStoreConfig, StorePlugin):
aff_root = 'https://www.a4b-tracking.com/pl/stat-click-text-link/16/58/' aff_root = 'https://www.a4b-tracking.com/pl/stat-click-text-link/16/58/'
url = 'http://woblink.com/publication' url = 'http://woblink.com/publication'
aff_url = aff_root + str(b64encode(url)) aff_url = aff_root + as_base64(url)
detail_url = None detail_url = None
if detail_item: if detail_item:
detail_url = aff_root + str(b64encode('http://woblink.com' + detail_item)) detail_url = aff_root + as_base64('http://woblink.com' + detail_item)
if external or self.config.get('open_external', False): if external or self.config.get('open_external', False):
open_url(QUrl(url_slash_cleaner(detail_url if detail_url else aff_url))) open_url(QUrl(url_slash_cleaner(detail_url if detail_url else aff_url)))

View File

@ -8,7 +8,6 @@ __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import json import json
from base64 import b64encode
from PyQt5.Qt import (QWidget, QGridLayout, QListWidget, QSize, Qt, QUrl, from PyQt5.Qt import (QWidget, QGridLayout, QListWidget, QSize, Qt, QUrl,
pyqtSlot, pyqtSignal, QVBoxLayout, QFrame, QLabel, pyqtSlot, pyqtSignal, QVBoxLayout, QFrame, QLabel,
@ -20,6 +19,7 @@ from calibre.ebooks.oeb.display.webview import load_html
from calibre.gui2 import error_dialog, question_dialog, gprefs, secure_web_page from calibre.gui2 import error_dialog, question_dialog, gprefs, secure_web_page
from calibre.utils.logging import default_log from calibre.utils.logging import default_log
from polyglot.builtins import unicode_type, range from polyglot.builtins import unicode_type, range
from polyglot.binary import as_base64_unicode
class Page(QWebPage): # {{{ class Page(QWebPage): # {{{
@ -77,7 +77,7 @@ class WebView(QWebView): # {{{
''' '''
raw = '::selection {background:#ffff00; color:#000;}\n'+raw raw = '::selection {background:#ffff00; color:#000;}\n'+raw
data = 'data:text/css;charset=utf-8;base64,' data = 'data:text/css;charset=utf-8;base64,'
data += b64encode(raw.encode('utf-8')) data += as_base64_unicode(raw)
self.settings().setUserStyleSheetUrl(QUrl(data)) self.settings().setUserStyleSheetUrl(QUrl(data))
def load_js(self): def load_js(self):

View File

@ -8,7 +8,6 @@ __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
import time, textwrap, json import time, textwrap, json
from bisect import bisect_right from bisect import bisect_right
from base64 import b64encode
from polyglot.builtins import map, unicode_type from polyglot.builtins import map, unicode_type
from threading import Thread from threading import Thread
from functools import partial from functools import partial
@ -31,6 +30,7 @@ from calibre.gui2.widgets2 import HistoryLineEdit2
from calibre.utils.ipc.simple_worker import offload_worker from calibre.utils.ipc.simple_worker import offload_worker
from polyglot.urllib import urlparse from polyglot.urllib import urlparse
from polyglot.queue import Queue, Empty from polyglot.queue import Queue, Empty
from polyglot.binary import as_base64_unicode
shutdown = object() shutdown = object()
@ -269,7 +269,7 @@ class WebPage(QWebPage):
settings.setDefaultTextEncoding('utf-8') settings.setDefaultTextEncoding('utf-8')
data = 'data:text/css;charset=utf-8;base64,' data = 'data:text/css;charset=utf-8;base64,'
css = '[data-in-split-mode="1"] [data-is-block="1"]:hover { cursor: pointer !important; border-top: solid 5px green !important }' css = '[data-in-split-mode="1"] [data-is-block="1"]:hover { cursor: pointer !important; border-top: solid 5px green !important }'
data += b64encode(css.encode('utf-8')) data += as_base64_unicode(css)
settings.setUserStyleSheetUrl(QUrl(data)) settings.setUserStyleSheetUrl(QUrl(data))
self.setNetworkAccessManager(NetworkAccessManager(self)) self.setNetworkAccessManager(NetworkAccessManager(self))

View File

@ -5,7 +5,6 @@ __docformat__ = 'restructuredtext en'
# Imports {{{ # Imports {{{
import math, json import math, json
from base64 import b64encode
from functools import partial from functools import partial
from polyglot.builtins import iteritems, map, unicode_type, string_or_bytes from polyglot.builtins import iteritems, map, unicode_type, string_or_bytes
@ -33,6 +32,7 @@ from calibre.gui2.viewer.footnote import Footnotes
from calibre.gui2.viewer.fake_net import NetworkAccessManager from calibre.gui2.viewer.fake_net import NetworkAccessManager
from calibre.ebooks.oeb.display.webview import load_html from calibre.ebooks.oeb.display.webview import load_html
from calibre.constants import isxp, iswindows, DEBUG, __version__ from calibre.constants import isxp, iswindows, DEBUG, __version__
from polyglot.binary import as_base64_unicode
# }}} # }}}
@ -144,7 +144,7 @@ class Document(QWebPage): # {{{
raw = prefix + opts.user_css raw = prefix + opts.user_css
raw = '::selection {background:#ffff00; color:#000;}\n'+raw raw = '::selection {background:#ffff00; color:#000;}\n'+raw
data = 'data:text/css;charset=utf-8;base64,' data = 'data:text/css;charset=utf-8;base64,'
data += b64encode(raw.encode('utf-8')) data += as_base64_unicode(raw)
self.settings().setUserStyleSheetUrl(QUrl(data)) self.settings().setUserStyleSheetUrl(QUrl(data))
def findText(self, q, flags): def findText(self, q, flags):

View File

@ -6,7 +6,7 @@ from __future__ import (unicode_literals, division, absolute_import,
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>' __copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>'
import binascii, os, random, struct, base64 import binascii, os, random, struct
from collections import OrderedDict from collections import OrderedDict
from hashlib import md5, sha256 from hashlib import md5, sha256
from itertools import permutations from itertools import permutations
@ -17,6 +17,7 @@ from calibre.srv.http_request import parse_uri
from calibre.srv.utils import parse_http_dict, encode_path from calibre.srv.utils import parse_http_dict, encode_path
from calibre.utils.monotonic import monotonic from calibre.utils.monotonic import monotonic
from polyglot import http_client from polyglot import http_client
from polyglot.binary import from_base64_unicode
MAX_AGE_SECONDS = 3600 MAX_AGE_SECONDS = 3600
nonce_counter, nonce_counter_lock = 0, Lock() nonce_counter, nonce_counter_lock = 0, Lock()
@ -76,7 +77,7 @@ def sha256_hex(s):
def base64_decode(s): def base64_decode(s):
return base64.standard_b64decode(as_bytestring(s)).decode('utf-8') return from_base64_unicode(s)
def synthesize_nonce(key_order, realm, secret, timestamp=None): def synthesize_nonce(key_order, realm, secret, timestamp=None):

View File

@ -5,7 +5,6 @@
from __future__ import absolute_import, division, print_function, unicode_literals from __future__ import absolute_import, division, print_function, unicode_literals
import os import os
from base64 import standard_b64decode
from functools import partial from functools import partial
from io import BytesIO from io import BytesIO
@ -20,6 +19,7 @@ from calibre.srv.utils import get_db, get_library_data
from calibre.utils.imghdr import what from calibre.utils.imghdr import what
from calibre.utils.serialize import MSGPACK_MIME, json_loads, msgpack_loads from calibre.utils.serialize import MSGPACK_MIME, json_loads, msgpack_loads
from polyglot.builtins import iteritems from polyglot.builtins import iteritems
from polyglot.binary import from_base64_bytes
receive_data_methods = {'GET', 'POST'} receive_data_methods = {'GET', 'POST'}
@ -160,7 +160,7 @@ def cdb_set_fields(ctx, rd, book_id, library_id):
if cdata is not False: if cdata is not False:
if cdata is not None: if cdata is not None:
try: try:
cdata = standard_b64decode(cdata.split(',', 1)[-1].encode('ascii')) cdata = from_base64_bytes(cdata.split(',', 1)[-1])
except Exception: except Exception:
raise HTTPBadRequest('Cover data is not valid base64 encoded data') raise HTTPBadRequest('Cover data is not valid base64 encoded data')
try: try:

View File

@ -2,31 +2,35 @@
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from __future__ import (unicode_literals, division, absolute_import, from __future__ import absolute_import, division, print_function, unicode_literals
print_function)
import sys, os, json, re import json
from base64 import standard_b64encode, standard_b64decode import os
from collections import defaultdict, OrderedDict import re
from itertools import count import sys
from collections import OrderedDict, defaultdict
from functools import partial from functools import partial
from itertools import count
from css_parser import replaceUrls from css_parser import replaceUrls
from css_parser.css import CSSRule from css_parser.css import CSSRule
from calibre import prepare_string_for_xml, force_unicode from calibre import force_unicode, prepare_string_for_xml
from calibre.ebooks import parse_css_length from calibre.ebooks import parse_css_length
from calibre.ebooks.css_transform_rules import StyleDeclaration
from calibre.ebooks.oeb.base import ( from calibre.ebooks.oeb.base import (
OEB_DOCS, OEB_STYLES, rewrite_links, XPath, urlunquote, XLINK, XHTML_NS, OPF, XHTML, EPUB_NS) EPUB_NS, OEB_DOCS, OEB_STYLES, OPF, XHTML, XHTML_NS, XLINK, XPath, rewrite_links,
urlunquote
)
from calibre.ebooks.oeb.iterator.book import extract_book from calibre.ebooks.oeb.iterator.book import extract_book
from calibre.ebooks.oeb.polish.container import Container as ContainerBase from calibre.ebooks.oeb.polish.container import Container as ContainerBase
from calibre.ebooks.oeb.polish.cover import set_epub_cover, find_cover_image from calibre.ebooks.oeb.polish.cover import find_cover_image, set_epub_cover
from calibre.ebooks.oeb.polish.css import transform_css from calibre.ebooks.oeb.polish.css import transform_css
from calibre.ebooks.oeb.polish.utils import extract from calibre.ebooks.oeb.polish.toc import get_landmarks, get_toc
from calibre.ebooks.css_transform_rules import StyleDeclaration from calibre.ebooks.oeb.polish.utils import extract, guess_type
from calibre.ebooks.oeb.polish.toc import get_toc, get_landmarks
from calibre.ebooks.oeb.polish.utils import guess_type
from calibre.utils.short_uuid import uuid4
from calibre.utils.logging import default_log from calibre.utils.logging import default_log
from calibre.utils.short_uuid import uuid4
from polyglot.binary import as_base64_unicode as encode_component, from_base64_unicode as decode_component
from polyglot.builtins import iteritems, map, unicode_type from polyglot.builtins import iteritems, map, unicode_type
from polyglot.urllib import quote, urlparse from polyglot.urllib import quote, urlparse
@ -35,14 +39,6 @@ RENDER_VERSION = 1
BLANK_JPEG = b'\xff\xd8\xff\xdb\x00C\x00\x03\x02\x02\x02\x02\x02\x03\x02\x02\x02\x03\x03\x03\x03\x04\x06\x04\x04\x04\x04\x04\x08\x06\x06\x05\x06\t\x08\n\n\t\x08\t\t\n\x0c\x0f\x0c\n\x0b\x0e\x0b\t\t\r\x11\r\x0e\x0f\x10\x10\x11\x10\n\x0c\x12\x13\x12\x10\x13\x0f\x10\x10\x10\xff\xc9\x00\x0b\x08\x00\x01\x00\x01\x01\x01\x11\x00\xff\xcc\x00\x06\x00\x10\x10\x05\xff\xda\x00\x08\x01\x01\x00\x00?\x00\xd2\xcf \xff\xd9' # noqa BLANK_JPEG = b'\xff\xd8\xff\xdb\x00C\x00\x03\x02\x02\x02\x02\x02\x03\x02\x02\x02\x03\x03\x03\x03\x04\x06\x04\x04\x04\x04\x04\x08\x06\x06\x05\x06\t\x08\n\n\t\x08\t\t\n\x0c\x0f\x0c\n\x0b\x0e\x0b\t\t\r\x11\r\x0e\x0f\x10\x10\x11\x10\n\x0c\x12\x13\x12\x10\x13\x0f\x10\x10\x10\xff\xc9\x00\x0b\x08\x00\x01\x00\x01\x01\x01\x11\x00\xff\xcc\x00\x06\x00\x10\x10\x05\xff\xda\x00\x08\x01\x01\x00\x00?\x00\xd2\xcf \xff\xd9' # noqa
def encode_component(x):
return standard_b64encode(x.encode('utf-8')).decode('ascii')
def decode_component(x):
return standard_b64decode(x).decode('utf-8')
def encode_url(name, frag=''): def encode_url(name, frag=''):
name = encode_component(name) name = encode_component(name)
if frag: if frag:

View File

@ -6,7 +6,7 @@ from __future__ import (unicode_literals, division, absolute_import,
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>' __copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>'
import zlib, json, base64, os import zlib, json, os
from io import BytesIO from io import BytesIO
from functools import partial from functools import partial
@ -14,11 +14,12 @@ from calibre.ebooks.metadata.meta import get_metadata
from calibre.srv.tests.base import LibraryBaseTest from calibre.srv.tests.base import LibraryBaseTest
from polyglot.http_client import OK, NOT_FOUND, FORBIDDEN from polyglot.http_client import OK, NOT_FOUND, FORBIDDEN
from polyglot.urllib import urlencode, quote from polyglot.urllib import urlencode, quote
from polyglot.binary import as_base64_bytes
def make_request(conn, url, headers={}, prefix='/ajax', username=None, password=None, method='GET', data=None): def make_request(conn, url, headers={}, prefix='/ajax', username=None, password=None, method='GET', data=None):
if username and password: if username and password:
headers[b'Authorization'] = b'Basic ' + base64.standard_b64encode((username + ':' + password).encode('utf-8')) headers[b'Authorization'] = b'Basic ' + as_base64_bytes((username + ':' + password))
conn.request(method, prefix + url, headers=headers, body=data) conn.request(method, prefix + url, headers=headers, body=data)
r = conn.getresponse() r = conn.getresponse()
data = r.read() data = r.read()

View File

@ -6,7 +6,7 @@ from __future__ import (unicode_literals, division, absolute_import,
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>' __copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>'
import base64, subprocess, os, time import subprocess, os, time
from collections import namedtuple from collections import namedtuple
try: try:
from distutils.spawn import find_executable from distutils.spawn import find_executable
@ -22,6 +22,7 @@ from polyglot import http_client
from polyglot.http_cookie import CookieJar from polyglot.http_cookie import CookieJar
from polyglot.urllib import (build_opener, HTTPBasicAuthHandler, from polyglot.urllib import (build_opener, HTTPBasicAuthHandler,
HTTPCookieProcessor, HTTPDigestAuthHandler, HTTPError) HTTPCookieProcessor, HTTPDigestAuthHandler, HTTPError)
from polyglot.binary import as_base64_bytes
REALM = 'calibre-test' REALM = 'calibre-test'
@ -101,7 +102,7 @@ class TestAuth(BaseTest):
self.ae(r.status, http_client.UNAUTHORIZED) self.ae(r.status, http_client.UNAUTHORIZED)
self.ae(r.getheader('WWW-Authenticate'), b'Basic realm="%s"' % bytes(REALM)) self.ae(r.getheader('WWW-Authenticate'), b'Basic realm="%s"' % bytes(REALM))
self.assertFalse(r.read()) self.assertFalse(r.read())
conn.request('GET', '/closed', headers={'Authorization': b'Basic ' + base64.standard_b64encode(b'testuser:testpw')}) conn.request('GET', '/closed', headers={'Authorization': b'Basic ' + as_base64_bytes(b'testuser:testpw')})
r = conn.getresponse() r = conn.getresponse()
self.ae(r.read(), b'closed') self.ae(r.read(), b'closed')
self.ae(r.status, http_client.OK) self.ae(r.status, http_client.OK)
@ -109,7 +110,7 @@ class TestAuth(BaseTest):
self.ae(b'closed', urlopen(server, un='!@#$%^&*()-=_+', pw='!@#$%^&*()-=_+', method='basic').read()) self.ae(b'closed', urlopen(server, un='!@#$%^&*()-=_+', pw='!@#$%^&*()-=_+', method='basic').read())
def request(un='testuser', pw='testpw'): def request(un='testuser', pw='testpw'):
conn.request('GET', '/closed', headers={'Authorization': b'Basic ' + base64.standard_b64encode(bytes('%s:%s' % (un, pw)))}) conn.request('GET', '/closed', headers={'Authorization': b'Basic ' + as_base64_bytes('%s:%s' % (un, pw))})
r = conn.getresponse() r = conn.getresponse()
return r.status, r.read() return r.status, r.read()
@ -254,7 +255,7 @@ class TestAuth(BaseTest):
conn = server.connect() conn = server.connect()
def request(un='testuser', pw='testpw'): def request(un='testuser', pw='testpw'):
conn.request('GET', '/closed', headers={'Authorization': b'Basic ' + base64.standard_b64encode(bytes('%s:%s' % (un, pw)))}) conn.request('GET', '/closed', headers={'Authorization': b'Basic ' + as_base64_bytes('%s:%s' % (un, pw))})
r = conn.getresponse() r = conn.getresponse()
return r.status, r.read() return r.status, r.read()

View File

@ -5,7 +5,6 @@
from __future__ import (unicode_literals, division, absolute_import, from __future__ import (unicode_literals, division, absolute_import,
print_function) print_function)
import socket, os, struct, errno, numbers import socket, os, struct, errno, numbers
from base64 import standard_b64encode
from collections import deque, namedtuple from collections import deque, namedtuple
from functools import partial from functools import partial
from hashlib import sha1 from hashlib import sha1
@ -17,6 +16,7 @@ from calibre.srv.web_socket import (
from calibre.utils.monotonic import monotonic from calibre.utils.monotonic import monotonic
from calibre.utils.socket_inheritance import set_socket_inherit from calibre.utils.socket_inheritance import set_socket_inherit
from polyglot.builtins import range, unicode_type from polyglot.builtins import range, unicode_type
from polyglot.binary import as_base64_bytes, as_base64_unicode
HANDSHAKE_STR = '''\ HANDSHAKE_STR = '''\
GET / HTTP/1.1\r GET / HTTP/1.1\r
@ -35,7 +35,7 @@ class WSClient(object):
self.timeout = timeout self.timeout = timeout
self.socket = socket.create_connection(('localhost', port), timeout) self.socket = socket.create_connection(('localhost', port), timeout)
set_socket_inherit(self.socket, False) set_socket_inherit(self.socket, False)
self.key = standard_b64encode(os.urandom(8)) self.key = as_base64_bytes(os.urandom(8))
self.socket.sendall(HANDSHAKE_STR.format(self.key).encode('ascii')) self.socket.sendall(HANDSHAKE_STR.format(self.key).encode('ascii'))
self.read_buf = deque() self.read_buf = deque()
self.read_upgrade_response() self.read_upgrade_response()
@ -64,7 +64,7 @@ class WSClient(object):
if rl != b'HTTP/1.1 101 Switching Protocols\r\n': if rl != b'HTTP/1.1 101 Switching Protocols\r\n':
raise ValueError('Server did not respond with correct switching protocols line') raise ValueError('Server did not respond with correct switching protocols line')
headers = read_headers(partial(next, lines)) headers = read_headers(partial(next, lines))
key = standard_b64encode(sha1(self.key + GUID_STR).digest()) key = as_base64_unicode(sha1(self.key + GUID_STR).digest())
if headers.get('Sec-WebSocket-Accept') != key: if headers.get('Sec-WebSocket-Accept') != key:
raise ValueError('Server did not respond with correct key in Sec-WebSocket-Accept') raise ValueError('Server did not respond with correct key in Sec-WebSocket-Accept')

View File

@ -2,24 +2,28 @@
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
from __future__ import (unicode_literals, division, absolute_import, from __future__ import absolute_import, division, print_function, unicode_literals
print_function)
import os, weakref, socket import os
from base64 import standard_b64encode import socket
import weakref
from collections import deque from collections import deque
from hashlib import sha1 from hashlib import sha1
from struct import unpack_from, pack, error as struct_error from struct import error as struct_error, pack, unpack_from
from threading import Lock from threading import Lock
from calibre import as_unicode from calibre import as_unicode
from calibre.constants import plugins from calibre.constants import plugins
from calibre.srv.loop import ServerLoop, HandleInterrupt, WRITE, READ, RDWR, Connection
from calibre.srv.http_response import HTTPConnection, create_http_handler from calibre.srv.http_response import HTTPConnection, create_http_handler
from calibre.srv.loop import (
RDWR, READ, WRITE, Connection, HandleInterrupt, ServerLoop
)
from calibre.srv.utils import DESIRED_SEND_BUFFER_SIZE from calibre.srv.utils import DESIRED_SEND_BUFFER_SIZE
from calibre.utils.speedups import ReadOnlyFileBuffer from calibre.utils.speedups import ReadOnlyFileBuffer
from polyglot.queue import Queue, Empty
from polyglot import http_client from polyglot import http_client
from polyglot.binary import as_base64_unicode
from polyglot.queue import Empty, Queue
speedup, err = plugins['speedup'] speedup, err = plugins['speedup']
if not speedup: if not speedup:
raise RuntimeError('Failed to load speedup module with error: ' + err) raise RuntimeError('Failed to load speedup module with error: ' + err)
@ -291,7 +295,7 @@ class WebSocketConnection(HTTPConnection):
if self.method != 'GET': if self.method != 'GET':
return self.simple_response(http_client.BAD_REQUEST, 'Invalid WebSocket method: %s' % self.method) return self.simple_response(http_client.BAD_REQUEST, 'Invalid WebSocket method: %s' % self.method)
response = HANDSHAKE_STR % standard_b64encode(sha1(key + GUID_STR).digest()) response = HANDSHAKE_STR % as_base64_unicode(sha1(key + GUID_STR).digest())
self.optimize_for_sending_packet() self.optimize_for_sending_packet()
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
self.set_state(WRITE, self.upgrade_connection_to_ws, ReadOnlyFileBuffer(response.encode('ascii')), inheaders) self.set_state(WRITE, self.upgrade_connection_to_ws, ReadOnlyFileBuffer(response.encode('ascii')), inheaders)

View File

@ -21,9 +21,9 @@ plugin_dir = os.path.join(config_dir, 'plugins')
def to_json(obj): def to_json(obj):
import datetime import datetime
if isinstance(obj, bytearray): if isinstance(obj, bytearray):
import base64 from base64 import standard_b64encode
return {'__class__': 'bytearray', return {'__class__': 'bytearray',
'__value__': base64.standard_b64encode(bytes(obj)).decode('ascii')} '__value__': standard_b64encode(bytes(obj)).decode('ascii')}
if isinstance(obj, datetime.datetime): if isinstance(obj, datetime.datetime):
from calibre.utils.date import isoformat from calibre.utils.date import isoformat
return {'__class__': 'datetime.datetime', return {'__class__': 'datetime.datetime',
@ -42,8 +42,8 @@ def from_json(obj):
custom = obj.get('__class__') custom = obj.get('__class__')
if custom is not None: if custom is not None:
if custom == 'bytearray': if custom == 'bytearray':
import base64 from base64 import standard_b64decode
return bytearray(base64.standard_b64decode(obj['__value__'])) return bytearray(standard_b64decode(obj['__value__'].encode('ascii')))
if custom == 'datetime.datetime': if custom == 'datetime.datetime':
from calibre.utils.iso8601 import parse_iso8601 from calibre.utils.iso8601 import parse_iso8601
return parse_iso8601(obj['__value__'], assume_utc=True) return parse_iso8601(obj['__value__'], assume_utc=True)

View File

@ -66,13 +66,11 @@ def json_dumps(data, **kw):
def decode_metadata(x, for_json): def decode_metadata(x, for_json):
import base64 from polyglot.binary import from_base64_bytes
from calibre.ebooks.metadata.book.serialize import metadata_from_dict from calibre.ebooks.metadata.book.serialize import metadata_from_dict
obj = metadata_from_dict(x) obj = metadata_from_dict(x)
if for_json and obj.cover_data and obj.cover_data[1]: if for_json and obj.cover_data and obj.cover_data[1]:
obj.cover_data = obj.cover_data[0], base64.standard_b64decode( obj.cover_data = obj.cover_data[0], from_base64_bytes(obj.cover_data[1])
obj.cover_data[1]
)
return obj return obj

View File

@ -17,7 +17,6 @@ import sys
import threading import threading
import time import time
import traceback import traceback
from base64 import b64decode
from calibre import browser, relpath, unicode_path from calibre import browser, relpath, unicode_path
from calibre.constants import filesystem_encoding, iswindows from calibre.constants import filesystem_encoding, iswindows
@ -35,6 +34,7 @@ from polyglot.urllib import (
URLError, quote, url2pathname, urljoin, urlparse, urlsplit, urlunparse, URLError, quote, url2pathname, urljoin, urlparse, urlsplit, urlunparse,
urlunsplit urlunsplit
) )
from polyglot.binary import from_base64_bytes
class AbortArticle(Exception): class AbortArticle(Exception):
@ -391,8 +391,8 @@ class RecursiveFetcher(object):
iurl = tag['src'] iurl = tag['src']
if iurl.startswith('data:image/'): if iurl.startswith('data:image/'):
try: try:
data = b64decode(iurl.partition(',')[-1]) data = from_base64_bytes(iurl.partition(',')[-1])
except: except Exception:
self.log.exception('Failed to decode embedded image') self.log.exception('Failed to decode embedded image')
continue continue
else: else:

32
src/polyglot/binary.py Normal file
View File

@ -0,0 +1,32 @@
#!/usr/bin/env python2
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
from __future__ import absolute_import, division, print_function, unicode_literals
from base64 import standard_b64encode, standard_b64decode
from polyglot.builtins import unicode_type
def as_base64_bytes(x, enc='utf-8'):
if isinstance(x, unicode_type):
x = x.encode(enc)
return standard_b64encode(x)
def as_base64_unicode(x, enc='utf-8'):
if isinstance(x, unicode_type):
x = x.encode(enc)
return standard_b64encode(x).decode('ascii')
def from_base64_unicode(x, enc='utf-8'):
if isinstance(x, unicode_type):
x = x.encode('ascii')
return standard_b64decode(x).decode(enc)
def from_base64_bytes(x):
if isinstance(x, unicode_type):
x = x.encode('ascii')
return standard_b64decode(x)