From a1621e9059adb7ac3cd05d8e9178d8d0665b7739 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 22 Feb 2015 18:00:14 +0200 Subject: [PATCH] binascii: Add Python base64 implementation from PyPy3-2.4.0's interp_base64.py Full source path in tarball: pypy3-2.4.0-src/pypy/module/binascii/interp_base64.py --- binascii/binascii.py | 116 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 4 deletions(-) diff --git a/binascii/binascii.py b/binascii/binascii.py index a827d138..61bf9b0e 100644 --- a/binascii/binascii.py +++ b/binascii/binascii.py @@ -1,5 +1,113 @@ -def b2a_base64(): - raise NotImplementError +from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import unwrap_spec +from rpython.rlib.rstring import StringBuilder +from pypy.module.binascii.interp_binascii import raise_Error +from rpython.rlib.rarithmetic import ovfcheck -def a2b_base64(): - raise NotImplementError +# ____________________________________________________________ + +PAD = '=' + +table_a2b_base64 = [ + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, + 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, # Note PAD->-1 here + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, + 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, + -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, + 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, +] +def _transform(n): + if n == -1: + return '\xff' + else: + return chr(n) +table_a2b_base64 = ''.join(map(_transform, table_a2b_base64)) +assert len(table_a2b_base64) == 256 + + +@unwrap_spec(ascii='bufferstr') +def a2b_base64(space, ascii): + "Decode a line of base64 data." + + res = StringBuilder((len(ascii) // 4) * 3) # maximum estimate + quad_pos = 0 + leftchar = 0 + leftbits = 0 + last_char_was_a_pad = False + + for c in ascii: + if c == PAD: + if quad_pos > 2 or (quad_pos == 2 and last_char_was_a_pad): + break # stop on 'xxx=' or on 'xx==' + last_char_was_a_pad = True + else: + n = ord(table_a2b_base64[ord(c)]) + if n == 0xff: + continue # ignore strange characters + # + # Shift it in on the low end, and see if there's + # a byte ready for output. + quad_pos = (quad_pos + 1) & 3 + leftchar = (leftchar << 6) | n + leftbits += 6 + # + if leftbits >= 8: + leftbits -= 8 + res.append(chr(leftchar >> leftbits)) + leftchar &= ((1 << leftbits) - 1) + # + last_char_was_a_pad = False + else: + if leftbits != 0: + raise_Error(space, "Incorrect padding") + + return space.wrapbytes(res.build()) + +# ____________________________________________________________ + +table_b2a_base64 = ( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") + +@unwrap_spec(bin='bufferstr') +def b2a_base64(space, bin): + "Base64-code line of data." + + newlength = (len(bin) + 2) // 3 + try: + newlength = ovfcheck(newlength * 4) + except OverflowError: + raise OperationError(space.w_MemoryError, space.w_None) + newlength += 1 + res = StringBuilder(newlength) + + leftchar = 0 + leftbits = 0 + for c in bin: + # Shift into our buffer, and output any 6bits ready + leftchar = (leftchar << 8) | ord(c) + leftbits += 8 + res.append(table_b2a_base64[(leftchar >> (leftbits-6)) & 0x3f]) + leftbits -= 6 + if leftbits >= 6: + res.append(table_b2a_base64[(leftchar >> (leftbits-6)) & 0x3f]) + leftbits -= 6 + # + if leftbits == 2: + res.append(table_b2a_base64[(leftchar & 3) << 4]) + res.append(PAD) + res.append(PAD) + elif leftbits == 4: + res.append(table_b2a_base64[(leftchar & 0xf) << 2]) + res.append(PAD) + res.append('\n') + return space.wrapbytes(res.build())