2015-02-22 16:00:14 +00:00
|
|
|
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
|
2014-05-19 20:24:22 +00:00
|
|
|
|
2015-02-22 16:00:14 +00:00
|
|
|
# ____________________________________________________________
|
|
|
|
|
|
|
|
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())
|