|
| 1 | +from pypy.interpreter.error import OperationError |
| 2 | +from pypy.interpreter.gateway import unwrap_spec |
| 3 | +from rpython.rlib.rstring import StringBuilder |
| 4 | +from pypy.module.binascii.interp_binascii import raise_Error |
| 5 | +from rpython.rlib.rarithmetic import ovfcheck |
| 6 | + |
| 7 | +# ____________________________________________________________ |
| 8 | + |
| 9 | +PAD = '=' |
| 10 | + |
| 11 | +table_a2b_base64 = [ |
| 12 | + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, |
| 13 | + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, |
| 14 | + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, |
| 15 | + 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, # Note PAD->-1 here |
| 16 | + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, |
| 17 | + 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, |
| 18 | + -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, |
| 19 | + 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1, |
| 20 | + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, |
| 21 | + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, |
| 22 | + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, |
| 23 | + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, |
| 24 | + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, |
| 25 | + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, |
| 26 | + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, |
| 27 | + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, |
| 28 | +] |
| 29 | +def _transform(n): |
| 30 | + if n == -1: |
| 31 | + return '\xff' |
| 32 | + else: |
| 33 | + return chr(n) |
| 34 | +table_a2b_base64 = ''.join(map(_transform, table_a2b_base64)) |
| 35 | +assert len(table_a2b_base64) == 256 |
| 36 | + |
| 37 | + |
| 38 | +@unwrap_spec(ascii='bufferstr') |
| 39 | +def a2b_base64(space, ascii): |
| 40 | + "Decode a line of base64 data." |
| 41 | + |
| 42 | + res = StringBuilder((len(ascii) // 4) * 3) # maximum estimate |
| 43 | + quad_pos = 0 |
| 44 | + leftchar = 0 |
| 45 | + leftbits = 0 |
| 46 | + last_char_was_a_pad = False |
| 47 | + |
| 48 | + for c in ascii: |
| 49 | + if c == PAD: |
| 50 | + if quad_pos > 2 or (quad_pos == 2 and last_char_was_a_pad): |
| 51 | + break # stop on 'xxx=' or on 'xx==' |
| 52 | + last_char_was_a_pad = True |
| 53 | + else: |
| 54 | + n = ord(table_a2b_base64[ord(c)]) |
| 55 | + if n == 0xff: |
| 56 | + continue # ignore strange characters |
| 57 | + # |
| 58 | + # Shift it in on the low end, and see if there's |
| 59 | + # a byte ready for output. |
| 60 | + quad_pos = (quad_pos + 1) & 3 |
| 61 | + leftchar = (leftchar << 6) | n |
| 62 | + leftbits += 6 |
| 63 | + # |
| 64 | + if leftbits >= 8: |
| 65 | + leftbits -= 8 |
| 66 | + res.append(chr(leftchar >> leftbits)) |
| 67 | + leftchar &= ((1 << leftbits) - 1) |
| 68 | + # |
| 69 | + last_char_was_a_pad = False |
| 70 | + else: |
| 71 | + if leftbits != 0: |
| 72 | + raise_Error(space, "Incorrect padding") |
| 73 | + |
| 74 | + return space.newbytes(res.build()) |
| 75 | + |
| 76 | +# ____________________________________________________________ |
| 77 | + |
| 78 | +table_b2a_base64 = ( |
| 79 | + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") |
| 80 | + |
| 81 | +@unwrap_spec(bin='bufferstr') |
| 82 | +def b2a_base64(space, bin): |
| 83 | + "Base64-code line of data." |
| 84 | + |
| 85 | + newlength = (len(bin) + 2) // 3 |
| 86 | + try: |
| 87 | + newlength = ovfcheck(newlength * 4) |
| 88 | + except OverflowError: |
| 89 | + raise OperationError(space.w_MemoryError, space.w_None) |
| 90 | + newlength += 1 |
| 91 | + res = StringBuilder(newlength) |
| 92 | + |
| 93 | + leftchar = 0 |
| 94 | + leftbits = 0 |
| 95 | + for c in bin: |
| 96 | + # Shift into our buffer, and output any 6bits ready |
| 97 | + leftchar = (leftchar << 8) | ord(c) |
| 98 | + leftbits += 8 |
| 99 | + res.append(table_b2a_base64[(leftchar >> (leftbits-6)) & 0x3f]) |
| 100 | + leftbits -= 6 |
| 101 | + if leftbits >= 6: |
| 102 | + res.append(table_b2a_base64[(leftchar >> (leftbits-6)) & 0x3f]) |
| 103 | + leftbits -= 6 |
| 104 | + # |
| 105 | + if leftbits == 2: |
| 106 | + res.append(table_b2a_base64[(leftchar & 3) << 4]) |
| 107 | + res.append(PAD) |
| 108 | + res.append(PAD) |
| 109 | + elif leftbits == 4: |
| 110 | + res.append(table_b2a_base64[(leftchar & 0xf) << 2]) |
| 111 | + res.append(PAD) |
| 112 | + res.append('\n') |
| 113 | + return space.newbytes(res.build()) |
0 commit comments