Skip to content

Commit a1621e9

Browse files
committed
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
1 parent 2f2aeae commit a1621e9

File tree

1 file changed

+112
-4
lines changed

1 file changed

+112
-4
lines changed

binascii/binascii.py

Lines changed: 112 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,113 @@
1-
def b2a_base64():
2-
raise NotImplementError
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
36

4-
def a2b_base64():
5-
raise NotImplementError
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.wrapbytes(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.wrapbytes(res.build())

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy