Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(27095)

Side by Side Diff: Lib/base64.py

Issue 17839: base64 module should use memoryview
Patch Set: Created 6 years, 4 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Doc/library/codecs.rst ('k') | Lib/test/test_base64.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #! /usr/bin/env python3 1 #! /usr/bin/env python3
2 2
3 """RFC 3548: Base16, Base32, Base64 Data Encodings""" 3 """RFC 3548: Base16, Base32, Base64 Data Encodings"""
4 4
5 # Modified 04-Oct-1995 by Jack Jansen to use binascii module 5 # Modified 04-Oct-1995 by Jack Jansen to use binascii module
6 # Modified 30-Dec-2003 by Barry Warsaw to add full RFC 3548 support 6 # Modified 30-Dec-2003 by Barry Warsaw to add full RFC 3548 support
7 # Modified 22-May-2007 by Guido van Rossum to use bytes everywhere 7 # Modified 22-May-2007 by Guido van Rossum to use bytes everywhere
8 8
9 import re 9 import re
10 import struct 10 import struct
(...skipping 17 matching lines...) Expand all
28 28
29 29
30 bytes_types = (bytes, bytearray) # Types acceptable as binary data 30 bytes_types = (bytes, bytearray) # Types acceptable as binary data
31 31
32 def _bytes_from_decode_data(s): 32 def _bytes_from_decode_data(s):
33 if isinstance(s, str): 33 if isinstance(s, str):
34 try: 34 try:
35 return s.encode('ascii') 35 return s.encode('ascii')
36 except UnicodeEncodeError: 36 except UnicodeEncodeError:
37 raise ValueError('string argument should contain only ASCII characte rs') 37 raise ValueError('string argument should contain only ASCII characte rs')
38 elif isinstance(s, bytes_types): 38 if isinstance(s, bytes_types):
39 return s 39 return s
40 else: 40 try:
41 raise TypeError("argument should be bytes or ASCII string, not %s" % s._ _class__.__name__) 41 return memoryview(s).tobytes()
42 42 except TypeError:
43 raise TypeError("argument should be a bytes-like object or ASCII "
44 "string, not %r" % s.__class__.__name__) from None
43 45
44 46
45 # Base64 encoding/decoding uses binascii 47 # Base64 encoding/decoding uses binascii
46 48
47 def b64encode(s, altchars=None): 49 def b64encode(s, altchars=None):
48 """Encode a byte string using Base64. 50 """Encode a byte string using Base64.
49 51
50 s is the byte string to encode. Optional altchars must be a byte 52 s is the byte string to encode. Optional altchars must be a byte
51 string of length 2 which specifies an alternative alphabet for the 53 string of length 2 which specifies an alternative alphabet for the
52 '+' and '/' characters. This allows an application to 54 '+' and '/' characters. This allows an application to
53 e.g. generate url or filesystem safe Base64 strings. 55 e.g. generate url or filesystem safe Base64 strings.
54 56
55 The encoded byte string is returned. 57 The encoded byte string is returned.
56 """ 58 """
57 if not isinstance(s, bytes_types):
58 raise TypeError("expected bytes, not %s" % s.__class__.__name__)
59 # Strip off the trailing newline 59 # Strip off the trailing newline
60 encoded = binascii.b2a_base64(s)[:-1] 60 encoded = binascii.b2a_base64(s)[:-1]
61 if altchars is not None: 61 if altchars is not None:
62 if not isinstance(altchars, bytes_types):
63 raise TypeError("expected bytes, not %s"
64 % altchars.__class__.__name__)
65 assert len(altchars) == 2, repr(altchars) 62 assert len(altchars) == 2, repr(altchars)
66 return encoded.translate(bytes.maketrans(b'+/', altchars)) 63 return encoded.translate(bytes.maketrans(b'+/', altchars))
67 return encoded 64 return encoded
68 65
69 66
70 def b64decode(s, altchars=None, validate=False): 67 def b64decode(s, altchars=None, validate=False):
71 """Decode a Base64 encoded byte string. 68 """Decode a Base64 encoded byte string.
72 69
73 s is the byte string to decode. Optional altchars must be a 70 s is the byte string to decode. Optional altchars must be a
74 string of length 2 which specifies the alternative alphabet used 71 string of length 2 which specifies the alternative alphabet used
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 _b32tab = [bytes([i]) for i in _b32alphabet] 139 _b32tab = [bytes([i]) for i in _b32alphabet]
143 _b32tab2 = [a + b for a in _b32tab for b in _b32tab] 140 _b32tab2 = [a + b for a in _b32tab for b in _b32tab]
144 _b32rev = {v: k for k, v in enumerate(_b32alphabet)} 141 _b32rev = {v: k for k, v in enumerate(_b32alphabet)}
145 142
146 def b32encode(s): 143 def b32encode(s):
147 """Encode a byte string using Base32. 144 """Encode a byte string using Base32.
148 145
149 s is the byte string to encode. The encoded byte string is returned. 146 s is the byte string to encode. The encoded byte string is returned.
150 """ 147 """
151 if not isinstance(s, bytes_types): 148 if not isinstance(s, bytes_types):
152 raise TypeError("expected bytes, not %s" % s.__class__.__name__) 149 s = memoryview(s).tobytes()
153 leftover = len(s) % 5 150 leftover = len(s) % 5
154 # Pad the last quantum with zero bits if necessary 151 # Pad the last quantum with zero bits if necessary
155 if leftover: 152 if leftover:
156 s = s + bytes(5 - leftover) # Don't use += ! 153 s = s + bytes(5 - leftover) # Don't use += !
157 encoded = bytearray() 154 encoded = bytearray()
158 from_bytes = int.from_bytes 155 from_bytes = int.from_bytes
159 b32tab2 = _b32tab2 156 b32tab2 = _b32tab2
160 for i in range(0, len(s), 5): 157 for i in range(0, len(s), 5):
161 c = from_bytes(s[i: i + 5], 'big') 158 c = from_bytes(s[i: i + 5], 'big')
162 encoded += (b32tab2[c >> 30] + # bits 1 - 10 159 encoded += (b32tab2[c >> 30] + # bits 1 - 10
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 240
244 241
245 # RFC 3548, Base 16 Alphabet specifies uppercase, but hexlify() returns 242 # RFC 3548, Base 16 Alphabet specifies uppercase, but hexlify() returns
246 # lowercase. The RFC also recommends against accepting input case 243 # lowercase. The RFC also recommends against accepting input case
247 # insensitively. 244 # insensitively.
248 def b16encode(s): 245 def b16encode(s):
249 """Encode a byte string using Base16. 246 """Encode a byte string using Base16.
250 247
251 s is the byte string to encode. The encoded byte string is returned. 248 s is the byte string to encode. The encoded byte string is returned.
252 """ 249 """
253 if not isinstance(s, bytes_types):
254 raise TypeError("expected bytes, not %s" % s.__class__.__name__)
255 return binascii.hexlify(s).upper() 250 return binascii.hexlify(s).upper()
256 251
257 252
258 def b16decode(s, casefold=False): 253 def b16decode(s, casefold=False):
259 """Decode a Base16 encoded byte string. 254 """Decode a Base16 encoded byte string.
260 255
261 s is the byte string to decode. Optional casefold is a flag 256 s is the byte string to decode. Optional casefold is a flag
262 specifying whether a lowercase alphabet is acceptable as input. 257 specifying whether a lowercase alphabet is acceptable as input.
263 For security purposes, the default is False. 258 For security purposes, the default is False.
264 259
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
299 294
300 def decode(input, output): 295 def decode(input, output):
301 """Decode a file; input and output are binary files.""" 296 """Decode a file; input and output are binary files."""
302 while True: 297 while True:
303 line = input.readline() 298 line = input.readline()
304 if not line: 299 if not line:
305 break 300 break
306 s = binascii.a2b_base64(line) 301 s = binascii.a2b_base64(line)
307 output.write(s) 302 output.write(s)
308 303
304 def _input_type_check(s):
305 try:
306 memoryview(s)
307 except TypeError as err:
308 msg = "expected bytes-like object, not %s" % s.__class__.__name__
309 raise TypeError(msg) from err
309 310
310 def encodebytes(s): 311 def encodebytes(s):
311 """Encode a bytestring into a bytestring containing multiple lines 312 """Encode a bytestring into a bytestring containing multiple lines
312 of base-64 data.""" 313 of base-64 data."""
313 if not isinstance(s, bytes_types): 314 _input_type_check(s)
314 raise TypeError("expected bytes, not %s" % s.__class__.__name__)
315 pieces = [] 315 pieces = []
316 for i in range(0, len(s), MAXBINSIZE): 316 for i in range(0, len(s), MAXBINSIZE):
317 chunk = s[i : i + MAXBINSIZE] 317 chunk = s[i : i + MAXBINSIZE]
318 pieces.append(binascii.b2a_base64(chunk)) 318 pieces.append(binascii.b2a_base64(chunk))
319 return b"".join(pieces) 319 return b"".join(pieces)
320 320
321 def encodestring(s): 321 def encodestring(s):
322 """Legacy alias of encodebytes().""" 322 """Legacy alias of encodebytes()."""
323 import warnings 323 import warnings
324 warnings.warn("encodestring() is a deprecated alias, use encodebytes()", 324 warnings.warn("encodestring() is a deprecated alias, use encodebytes()",
325 DeprecationWarning, 2) 325 DeprecationWarning, 2)
326 return encodebytes(s) 326 return encodebytes(s)
327 327
328 328
329 def decodebytes(s): 329 def decodebytes(s):
330 """Decode a bytestring of base-64 data into a bytestring.""" 330 """Decode a bytestring of base-64 data into a bytestring."""
331 if not isinstance(s, bytes_types): 331 _input_type_check(s)
332 raise TypeError("expected bytes, not %s" % s.__class__.__name__)
333 return binascii.a2b_base64(s) 332 return binascii.a2b_base64(s)
334 333
335 def decodestring(s): 334 def decodestring(s):
336 """Legacy alias of decodebytes().""" 335 """Legacy alias of decodebytes()."""
337 import warnings 336 import warnings
338 warnings.warn("decodestring() is a deprecated alias, use decodebytes()", 337 warnings.warn("decodestring() is a deprecated alias, use decodebytes()",
339 DeprecationWarning, 2) 338 DeprecationWarning, 2)
340 return decodebytes(s) 339 return decodebytes(s)
341 340
342 341
(...skipping 29 matching lines...) Expand all
372 print(repr(s0)) 371 print(repr(s0))
373 s1 = encodebytes(s0) 372 s1 = encodebytes(s0)
374 print(repr(s1)) 373 print(repr(s1))
375 s2 = decodebytes(s1) 374 s2 = decodebytes(s1)
376 print(repr(s2)) 375 print(repr(s2))
377 assert s0 == s2 376 assert s0 == s2
378 377
379 378
380 if __name__ == '__main__': 379 if __name__ == '__main__':
381 main() 380 main()
OLDNEW
« no previous file with comments | « Doc/library/codecs.rst ('k') | Lib/test/test_base64.py » ('j') | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+