Skip to content

Commit 7e10deb

Browse files
committed
stdlib/binascii: implement {b2a,a2b}_qp
Signed-off-by: Sebastien Binet <[email protected]>
1 parent 6d34733 commit 7e10deb

File tree

2 files changed

+95
-0
lines changed

2 files changed

+95
-0
lines changed

stdlib/binascii/binascii.go

+77
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
package binascii
77

88
import (
9+
"bytes"
910
"encoding/base64"
1011
"encoding/hex"
1112
"errors"
1213
"hash/crc32"
14+
"io"
15+
"mime/quotedprintable"
1316

1417
"github.com/go-python/gpython/py"
1518
)
@@ -33,6 +36,8 @@ func init() {
3336
py.MustNewMethod("crc32", crc32_, 0, "Compute CRC-32 incrementally."),
3437
py.MustNewMethod("unhexlify", a2b_hex, 0, unhexlify_doc),
3538
py.MustNewMethod("hexlify", b2a_hex, 0, hexlify_doc),
39+
py.MustNewMethod("a2b_qp", a2b_qp, 0, a2b_qp_doc),
40+
py.MustNewMethod("b2a_qp", b2a_qp, 0, b2a_qp_doc),
3641
},
3742
Globals: py.StringDict{
3843
"Incomplete": Incomplete,
@@ -156,3 +161,75 @@ const hexlify_doc = `Hexadecimal representation of binary data.
156161
157162
The return value is a bytes object. This function is also
158163
available as "b2a_hex()".`
164+
165+
const a2b_qp_doc = `Decode a string of qp-encoded data.`
166+
167+
func a2b_qp(self py.Object, args py.Tuple, kwargs py.StringDict) (py.Object, error) {
168+
var (
169+
pydata py.Object
170+
pyhdr py.Object = py.Bool(false)
171+
)
172+
err := py.ParseTupleAndKeywords(args, kwargs, "y*|p:binascii.a2b_qp", []string{"data", "header"}, &pydata, &pyhdr)
173+
if err != nil {
174+
return nil, err
175+
}
176+
177+
// TODO(sbinet)
178+
if pyhdr.(py.Bool) {
179+
return nil, py.NotImplementedError
180+
}
181+
182+
o := new(bytes.Buffer)
183+
r := quotedprintable.NewReader(bytes.NewReader([]byte(pydata.(py.Bytes))))
184+
_, err = io.Copy(o, r)
185+
if err != nil {
186+
// FIXME(sbinet): decorate the error somehow?
187+
return nil, err
188+
}
189+
return py.Bytes(o.Bytes()), nil
190+
}
191+
192+
const b2a_qp_doc = `Encode a string using quoted-printable encoding.
193+
194+
On encoding, when istext is set, newlines are not encoded, and white
195+
space at end of lines is. When istext is not set, \r and \n (CR/LF)
196+
are both encoded. When quotetabs is set, space and tabs are encoded.`
197+
198+
func b2a_qp(self py.Object, args py.Tuple, kwargs py.StringDict) (py.Object, error) {
199+
var (
200+
pydata py.Object
201+
pyqtabs py.Object = py.Bool(false)
202+
pyistxt py.Object = py.Bool(true)
203+
pyhdr py.Object = py.Bool(false)
204+
)
205+
err := py.ParseTupleAndKeywords(args, kwargs, "y*|ppp:binascii.b2a_qp", []string{"data", "quotetabs", "istext", "header"}, &pydata, &pyqtabs, &pyistxt, &pyhdr)
206+
if err != nil {
207+
return nil, err
208+
}
209+
210+
if pyqtabs.(py.Bool) {
211+
return nil, py.NotImplementedError
212+
}
213+
214+
if !pyistxt.(py.Bool) {
215+
return nil, py.NotImplementedError
216+
}
217+
218+
if pyhdr.(py.Bool) {
219+
return nil, py.NotImplementedError
220+
}
221+
222+
o := new(bytes.Buffer)
223+
w := quotedprintable.NewWriter(o)
224+
_, err = w.Write([]byte(pydata.(py.Bytes)))
225+
if err != nil {
226+
// FIXME(sbinet): decorate the error somehow?
227+
return nil, err
228+
}
229+
err = w.Close()
230+
if err != nil {
231+
// FIXME(sbinet): decorate the error somehow?
232+
return nil, err
233+
}
234+
return py.Bytes(o.Bytes()), nil
235+
}

stdlib/binascii/testdata/test.py

+18
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,19 @@
1212
def assertEqual(x, y):
1313
assert x == y, "got: %s, want: %s" % (repr(x), repr(y))
1414

15+
rawdata = b"The quick brown fox jumps over the lazy dog.\r\n"
16+
rawdata += bytes(range(256))
17+
rawdata += b"\r\nHello world.\n"
18+
1519
## base64
1620
assertEqual(binascii.b2a_base64(b'hello world!'), b'aGVsbG8gd29ybGQh\n')
1721
assertEqual(binascii.b2a_base64(b'hello\nworld!'), b'aGVsbG8Kd29ybGQh\n')
1822
assertEqual(binascii.b2a_base64(b'hello world!', newline=False), b'aGVsbG8gd29ybGQh')
1923
assertEqual(binascii.b2a_base64(b'hello\nworld!', newline=False), b'aGVsbG8Kd29ybGQh')
2024
assertEqual(binascii.a2b_base64("aGVsbG8gd29ybGQh\n"), b'hello world!')
2125

26+
assertEqual(binascii.b2a_base64(rawdata), b"VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZy4NCgABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8NCkhlbGxvIHdvcmxkLgo=\n")
27+
2228
try:
2329
binascii.b2a_base64("string")
2430
print("expected an exception")
@@ -37,6 +43,8 @@ def assertEqual(x, y):
3743
assertEqual(binascii.hexlify(b'hello world!'), b'68656c6c6f20776f726c6421')
3844
assertEqual(binascii.unhexlify(b'68656c6c6f20776f726c6421'), b'hello world!')
3945

46+
assertEqual(binascii.b2a_hex(rawdata), b'54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f672e0d0a000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff0d0a48656c6c6f20776f726c642e0a')
47+
4048
try:
4149
binascii.a2b_hex(b'123')
4250
print("expected an exception")
@@ -51,4 +59,14 @@ def assertEqual(x, y):
5159
print("expected an exception:",e)
5260
pass
5361

62+
## quotedprintable
63+
assertEqual(binascii.b2a_qp(b'hello world! = \t'), b'hello world! =3D =09')
64+
assertEqual(binascii.a2b_qp(b'hello world! =3D =09'), b'hello world! = \t')
65+
## ## TODO
66+
## #assertEqual(binascii.a2b_qp(b'hello world!', header=True), b'hello world!')
67+
## assertEqual(binascii.a2b_qp(rawdata, header=False), b'The quick brown fox jumps over the lazy dog.\r\n\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff\r\nHello world.\n')
68+
## assertEqual(binascii.b2a_qp(binascii.a2b_qp(rawdata)), b'The quick brown fox jumps over the lazy dog.\r\n=00=01=02=03=04=05=06=07=08=09\r\n=0B=0C\r=0E=0F=10=11=12=13=14=15=16=17=18=19=1A=1B=1C=1D=1E=1F !"#$%&\'()*+,-=\r\n./0123456789:;<=3D>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuv=\r\nwxyz{|}~=7F=80=81=82=83=84=85=86=87=88=89=8A=8B=8C=8D=8E=8F=90=91=92=93=94=\r\n=95=96=97=98=99=9A=9B=9C=9D=9E=9F=A0=A1=A2=A3=A4=A5=A6=A7=A8=A9=AA=AB=AC=AD=\r\n=AE=AF=B0=B1=B2=B3=B4=B5=B6=B7=B8=B9=BA=BB=BC=BD=BE=BF=C0=C1=C2=C3=C4=C5=C6=\r\n=C7=C8=C9=CA=CB=CC=CD=CE=CF=D0=D1=D2=D3=D4=D5=D6=D7=D8=D9=DA=DB=DC=DD=DE=DF=\r\n=E0=E1=E2=E3=E4=E5=E6=E7=E8=E9=EA=EB=EC=ED=EE=EF=F0=F1=F2=F3=F4=F5=F6=F7=F8=\r\n=F9=FA=FB=FC=FD=FE=FF\r\nHello world.\r\n')
69+
## ## TODO
70+
## #assertEqual(binascii.a2b_qp(rawdata, header=True), b'The quick brown fox jumps over the lazy dog.\r\n\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ `abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff\r\nHello world.\n')
71+
5472
print("done.")

0 commit comments

Comments
 (0)