forked from RustPython/RustPython
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbinascii.rs
More file actions
92 lines (77 loc) · 2.65 KB
/
binascii.rs
File metadata and controls
92 lines (77 loc) · 2.65 KB
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
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use crate::function::PyFuncArgs;
use crate::obj::objbytes;
use crate::obj::objint;
use crate::pyobject::{PyObjectRef, PyResult};
use crate::vm::VirtualMachine;
use crc::{crc32, Hasher32};
use num_traits::ToPrimitive;
fn hex_nibble(n: u8) -> u8 {
match n {
0..=9 => b'0' + n,
10..=15 => b'a' + n,
_ => unreachable!(),
}
}
fn binascii_hexlify(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(data, Some(vm.ctx.bytes_type()))]);
let bytes = objbytes::get_value(data);
let mut hex = Vec::<u8>::with_capacity(bytes.len() * 2);
for b in bytes.iter() {
hex.push(hex_nibble(b >> 4));
hex.push(hex_nibble(b & 0xf));
}
Ok(vm.ctx.new_bytes(hex))
}
fn unhex_nibble(c: u8) -> Option<u8> {
match c {
b'0'..=b'9' => Some(c - b'0'),
b'a'..=b'f' => Some(c - b'a' + 10),
b'A'..=b'F' => Some(c - b'A' + 10),
_ => None,
}
}
fn binascii_unhexlify(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
// TODO: allow 'str' hexstrings as well
arg_check!(vm, args, required = [(hexstr, Some(vm.ctx.bytes_type()))]);
let hex_bytes = &objbytes::get_value(hexstr);
if hex_bytes.len() % 2 != 0 {
return Err(vm.new_value_error("Odd-length string".to_string()));
}
let mut unhex = Vec::<u8>::with_capacity(hex_bytes.len() / 2);
for i in (0..hex_bytes.len()).step_by(2) {
let n1 = unhex_nibble(hex_bytes[i]);
let n2 = unhex_nibble(hex_bytes[i + 1]);
if n1.is_some() && n2.is_some() {
unhex.push(n1.unwrap() << 4 | n2.unwrap());
} else {
return Err(vm.new_value_error("Non-hexadecimal digit found".to_string()));
}
}
Ok(vm.ctx.new_bytes(unhex))
}
fn binascii_crc32(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
vm,
args,
required = [(data, Some(vm.ctx.bytes_type()))],
optional = [(value, None)]
);
let bytes = objbytes::get_value(data);
let crc = match value {
None => 0u32,
Some(value) => objint::get_value(&value).to_u32().unwrap(),
};
let mut digest = crc32::Digest::new_with_initial(crc32::IEEE, crc);
digest.write(&bytes);
Ok(vm.ctx.new_int(digest.sum32()))
}
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
let ctx = &vm.ctx;
py_module!(vm, "binascii", {
"hexlify" => ctx.new_rustfunc(binascii_hexlify),
"b2a_hex" => ctx.new_rustfunc(binascii_hexlify),
"unhexlify" => ctx.new_rustfunc(binascii_unhexlify),
"a2b_hex" => ctx.new_rustfunc(binascii_unhexlify),
"crc32" => ctx.new_rustfunc(binascii_crc32),
})
}