Skip to content

Commit 7be4092

Browse files
committed
stdlib/binascii: first import
Signed-off-by: Sebastien Binet <[email protected]>
1 parent 6b3e35b commit 7be4092

File tree

5 files changed

+248
-0
lines changed

5 files changed

+248
-0
lines changed

stdlib/binascii/binascii.go

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
// Copyright 2022 The go-python Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Package binascii provides the implementation of the python's 'binascii' module.
6+
package binascii
7+
8+
import (
9+
"encoding/base64"
10+
"encoding/hex"
11+
"errors"
12+
"hash/crc32"
13+
14+
"github.com/go-python/gpython/py"
15+
)
16+
17+
var (
18+
Incomplete = py.ExceptionType.NewType("binascii.Incomplete", "", nil, nil)
19+
Error = py.ValueError.NewType("binascii.Error", "", nil, nil)
20+
)
21+
22+
func init() {
23+
py.RegisterModule(&py.ModuleImpl{
24+
Info: py.ModuleInfo{
25+
Name: "binascii",
26+
Doc: "Conversion between binary data and ASCII",
27+
},
28+
Methods: []*py.Method{
29+
py.MustNewMethod("a2b_base64", a2b_base64, 0, "Decode a line of base64 data."),
30+
py.MustNewMethod("b2a_base64", b2a_base64, 0, "Base64-code line of data."),
31+
py.MustNewMethod("a2b_hex", a2b_hex, 0, a2b_hex_doc),
32+
py.MustNewMethod("b2a_hex", b2a_hex, 0, b2a_hex_doc),
33+
py.MustNewMethod("crc32", crc32_, 0, "Compute CRC-32 incrementally."),
34+
py.MustNewMethod("unhexlify", a2b_hex, 0, unhexlify_doc),
35+
py.MustNewMethod("hexlify", b2a_hex, 0, hexlify_doc),
36+
},
37+
Globals: py.StringDict{
38+
"Incomplete": Incomplete,
39+
"Error": Error,
40+
},
41+
})
42+
}
43+
44+
func b2a_base64(self py.Object, args py.Tuple, kwargs py.StringDict) (py.Object, error) {
45+
var (
46+
pydata py.Object
47+
pynewl py.Object = py.True
48+
)
49+
err := py.ParseTupleAndKeywords(args, kwargs, "y*|p:binascii.b2a_base64", []string{"data", "newline"}, &pydata, &pynewl)
50+
if err != nil {
51+
return nil, err
52+
}
53+
54+
var (
55+
buf = []byte(pydata.(py.Bytes))
56+
newline = bool(pynewl.(py.Bool))
57+
)
58+
59+
out := base64.StdEncoding.EncodeToString(buf)
60+
if newline {
61+
out += "\n"
62+
}
63+
return py.Bytes(out), nil
64+
}
65+
66+
func a2b_base64(self py.Object, args py.Tuple) (py.Object, error) {
67+
var pydata py.Object
68+
err := py.ParseTuple(args, "s:binascii.a2b_base64", &pydata)
69+
if err != nil {
70+
return nil, err
71+
}
72+
73+
out, err := base64.StdEncoding.DecodeString(string(pydata.(py.String)))
74+
if err != nil {
75+
return nil, py.ExceptionNewf(Error, "could not decode base64 data: %+v", err)
76+
}
77+
78+
return py.Bytes(out), nil
79+
}
80+
81+
func crc32_(self py.Object, args py.Tuple) (py.Object, error) {
82+
var (
83+
pydata py.Object
84+
pycrc py.Object = py.Int(0)
85+
)
86+
87+
err := py.ParseTuple(args, "y*|i:binascii.crc32", &pydata, &pycrc)
88+
if err != nil {
89+
return nil, err
90+
}
91+
92+
crc := crc32.Update(uint32(pycrc.(py.Int)), crc32.IEEETable, []byte(pydata.(py.Bytes)))
93+
return py.Int(crc), nil
94+
95+
}
96+
97+
const a2b_hex_doc = `Binary data of hexadecimal representation.
98+
99+
hexstr must contain an even number of hex digits (upper or lower case).
100+
This function is also available as "unhexlify()".`
101+
102+
func a2b_hex(self py.Object, args py.Tuple) (py.Object, error) {
103+
var (
104+
hexErr hex.InvalidByteError
105+
pydata py.Object
106+
src string
107+
)
108+
err := py.ParseTuple(args, "s*:binascii.a2b_hex", &pydata)
109+
if err != nil {
110+
return nil, err
111+
}
112+
113+
switch v := pydata.(type) {
114+
case py.String:
115+
src = string(v)
116+
case py.Bytes:
117+
src = string(v)
118+
}
119+
120+
o, err := hex.DecodeString(src)
121+
if err != nil {
122+
switch {
123+
case errors.Is(err, hex.ErrLength):
124+
return nil, py.ExceptionNewf(Error, "Odd-length string")
125+
case errors.As(err, &hexErr):
126+
return nil, py.ExceptionNewf(Error, "Non-hexadecimal digit found")
127+
default:
128+
return nil, py.ExceptionNewf(Error, "could not decode hex data: %+v", err)
129+
}
130+
}
131+
132+
return py.Bytes(o), nil
133+
}
134+
135+
const b2a_hex_doc = `Hexadecimal representation of binary data.
136+
137+
The return value is a bytes object. This function is also
138+
available as "hexlify()".`
139+
140+
func b2a_hex(self py.Object, args py.Tuple) (py.Object, error) {
141+
var pydata py.Object
142+
err := py.ParseTuple(args, "y*:binascii.b2a_hex", &pydata)
143+
if err != nil {
144+
return nil, err
145+
}
146+
147+
o := hex.EncodeToString([]byte(pydata.(py.Bytes)))
148+
return py.Bytes(o), nil
149+
}
150+
151+
const unhexlify_doc = `Binary data of hexadecimal representation.
152+
153+
hexstr must contain an even number of hex digits (upper or lower case).`
154+
155+
const hexlify_doc = `Hexadecimal representation of binary data.
156+
157+
The return value is a bytes object. This function is also
158+
available as "b2a_hex()".`

stdlib/binascii/binascii_test.go

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2022 The go-python Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package binascii_test
6+
7+
import (
8+
"testing"
9+
10+
"github.com/go-python/gpython/pytest"
11+
)
12+
13+
func TestBinascii(t *testing.T) {
14+
pytest.RunScript(t, "./testdata/test.py")
15+
}

stdlib/binascii/testdata/test.py

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Copyright 2022 The go-python Authors. All rights reserved.
2+
# Use of this source code is governed by a BSD-style
3+
# license that can be found in the LICENSE file.
4+
5+
import binascii
6+
7+
print("globals:")
8+
for name in ("Error", "Incomplete"):
9+
v = getattr(binascii, name)
10+
print("\nbinascii.%s:\n%s" % (name,repr(v)))
11+
12+
def assertEqual(x, y):
13+
assert x == y, "got: %s, want: %s" % (repr(x), repr(y))
14+
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+
19+
## base64
20+
assertEqual(binascii.b2a_base64(b'hello world!'), b'aGVsbG8gd29ybGQh\n')
21+
assertEqual(binascii.b2a_base64(b'hello\nworld!'), b'aGVsbG8Kd29ybGQh\n')
22+
assertEqual(binascii.b2a_base64(b'hello world!', newline=False), b'aGVsbG8gd29ybGQh')
23+
assertEqual(binascii.b2a_base64(b'hello\nworld!', newline=False), b'aGVsbG8Kd29ybGQh')
24+
assertEqual(binascii.a2b_base64("aGVsbG8gd29ybGQh\n"), b'hello world!')
25+
26+
assertEqual(binascii.a2b_base64(rawdata), b"N\x17\xaa\xba'$n\xba0\x9d\xfa1\x8e\xe9\xa9\xb2\x8b\xde\xae\xd8^\x95\xac\xf2v\x88>\xffMv\xdf\x8ez\xef\xcf")
27+
assertEqual(binascii.b2a_base64(rawdata), b"VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZy4NCgABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8NCkhlbGxvIHdvcmxkLgo=\n")
28+
29+
try:
30+
binascii.b2a_base64("string")
31+
print("expected an exception")
32+
except TypeError as e:
33+
print("expected an exception:", e)
34+
pass
35+
36+
## crc32
37+
assertEqual(binascii.crc32(b'hello world!'), 62177901)
38+
assertEqual(binascii.crc32(b'hello world!', 0), 62177901)
39+
assertEqual(binascii.crc32(b'hello world!', 42), 4055036404)
40+
41+
## hex
42+
assertEqual(binascii.b2a_hex(b'hello world!'), b'68656c6c6f20776f726c6421')
43+
assertEqual(binascii.a2b_hex(b'68656c6c6f20776f726c6421'), b'hello world!')
44+
assertEqual(binascii.hexlify(b'hello world!'), b'68656c6c6f20776f726c6421')
45+
assertEqual(binascii.unhexlify(b'68656c6c6f20776f726c6421'), b'hello world!')
46+
47+
assertEqual(binascii.b2a_hex(rawdata), b'54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f672e0d0a000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff0d0a48656c6c6f20776f726c642e0a')
48+
49+
try:
50+
binascii.a2b_hex(b'123')
51+
print("expected an exception")
52+
except binascii.Error as e:
53+
print("expected an exception:",e)
54+
pass
55+
56+
try:
57+
binascii.a2b_hex(b'hell')
58+
print("expected an exception")
59+
except binascii.Error as e:
60+
print("expected an exception:",e)
61+
pass
62+
63+
print("done.")
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
globals:
2+
3+
binascii.Error:
4+
<class 'binascii.Error'>
5+
6+
binascii.Incomplete:
7+
<class 'binascii.Incomplete'>
8+
expected an exception: binascii.b2a_base64() argument 1 must be bytes-like, not str
9+
expected an exception: Odd-length string
10+
expected an exception: Non-hexadecimal digit found
11+
done.

stdlib/stdlib.go

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/go-python/gpython/stdlib/marshal"
1919
"github.com/go-python/gpython/vm"
2020

21+
_ "github.com/go-python/gpython/stdlib/binascii"
2122
_ "github.com/go-python/gpython/stdlib/builtin"
2223
_ "github.com/go-python/gpython/stdlib/math"
2324
_ "github.com/go-python/gpython/stdlib/string"

0 commit comments

Comments
 (0)