mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Merge pull request #3816 from chang-57/binascii_qp
Add `binascii` `a2b_qp`
This commit is contained in:
2
Lib/test/test_binascii.py
vendored
2
Lib/test/test_binascii.py
vendored
@@ -266,8 +266,6 @@ class BinASCIITest(unittest.TestCase):
|
||||
expected1 = s.hex(':').encode('ascii')
|
||||
self.assertEqual(binascii.b2a_hex(self.type2test(s), ':'), expected1)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_qp(self):
|
||||
type2test = self.type2test
|
||||
a2b_qp = binascii.a2b_qp
|
||||
|
||||
@@ -11,6 +11,8 @@ mod decl {
|
||||
};
|
||||
use itertools::Itertools;
|
||||
|
||||
const MAXLINESIZE: usize = 76;
|
||||
|
||||
#[pyattr(name = "Error", once)]
|
||||
fn error_type(vm: &VirtualMachine) -> PyTypeRef {
|
||||
vm.ctx.new_exception_type(
|
||||
@@ -176,13 +178,285 @@ mod decl {
|
||||
// The 64 instead of the expected 63 is because
|
||||
// there are a few uuencodes out there that use
|
||||
// '`' as zero instead of space.
|
||||
if !(0x20..=0x60).contains(c) {
|
||||
if !(b' '..=(b' ' + 64)).contains(c) {
|
||||
if [b'\r', b'\n'].contains(c) {
|
||||
return Ok(0);
|
||||
}
|
||||
return Err(vm.new_value_error("Illegal char".to_string()));
|
||||
}
|
||||
Ok((*c - 0x20) & 0x3f)
|
||||
Ok((*c - b' ') & 0x3f)
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
struct A2bQpArgs {
|
||||
#[pyarg(any)]
|
||||
data: ArgAsciiBuffer,
|
||||
#[pyarg(named, default = "false")]
|
||||
header: bool,
|
||||
}
|
||||
#[pyfunction]
|
||||
fn a2b_qp(args: A2bQpArgs) -> PyResult<Vec<u8>> {
|
||||
let s = args.data;
|
||||
let header = args.header;
|
||||
s.with_ref(|buffer| {
|
||||
let len = buffer.len();
|
||||
let mut out_data = Vec::with_capacity(len);
|
||||
|
||||
let mut idx = 0;
|
||||
|
||||
while idx < len {
|
||||
if buffer[idx] == b'=' {
|
||||
idx += 1;
|
||||
if idx >= len {
|
||||
break;
|
||||
}
|
||||
// Soft line breaks
|
||||
if (buffer[idx] == b'\n') || (buffer[idx] == b'\r') {
|
||||
if buffer[idx] != b'\n' {
|
||||
while idx < len && buffer[idx] != b'\n' {
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
if idx < len {
|
||||
idx += 1;
|
||||
}
|
||||
} else if buffer[idx] == b'=' {
|
||||
// roken case from broken python qp
|
||||
out_data.push(b'=');
|
||||
idx += 1;
|
||||
} else if idx + 1 < len
|
||||
&& ((buffer[idx] >= b'A' && buffer[idx] <= b'F')
|
||||
|| (buffer[idx] >= b'a' && buffer[idx] <= b'f')
|
||||
|| (buffer[idx] >= b'0' && buffer[idx] <= b'9'))
|
||||
&& ((buffer[idx + 1] >= b'A' && buffer[idx + 1] <= b'F')
|
||||
|| (buffer[idx + 1] >= b'a' && buffer[idx + 1] <= b'f')
|
||||
|| (buffer[idx + 1] >= b'0' && buffer[idx + 1] <= b'9'))
|
||||
{
|
||||
// hexval
|
||||
if let (Some(ch1), Some(ch2)) =
|
||||
(unhex_nibble(buffer[idx]), unhex_nibble(buffer[idx + 1]))
|
||||
{
|
||||
out_data.push(ch1 << 4 | ch2);
|
||||
}
|
||||
idx += 2;
|
||||
} else {
|
||||
out_data.push(b'=');
|
||||
}
|
||||
} else if header && buffer[idx] == b'_' {
|
||||
out_data.push(b' ');
|
||||
idx += 1;
|
||||
} else {
|
||||
out_data.push(buffer[idx]);
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(out_data)
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
struct B2aQpArgs {
|
||||
#[pyarg(any)]
|
||||
data: ArgAsciiBuffer,
|
||||
#[pyarg(named, default = "false")]
|
||||
quotetabs: bool,
|
||||
#[pyarg(named, default = "true")]
|
||||
istext: bool,
|
||||
#[pyarg(named, default = "false")]
|
||||
header: bool,
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn b2a_qp(args: B2aQpArgs) -> PyResult<Vec<u8>> {
|
||||
let s = args.data;
|
||||
let quotetabs = args.quotetabs;
|
||||
let istext = args.istext;
|
||||
let header = args.header;
|
||||
s.with_ref(|buf| {
|
||||
let buflen = buf.len();
|
||||
let mut linelen = 0;
|
||||
let mut odatalen = 0;
|
||||
let mut crlf = false;
|
||||
let mut ch;
|
||||
|
||||
let mut inidx;
|
||||
let mut outidx;
|
||||
|
||||
inidx = 0;
|
||||
while inidx < buflen {
|
||||
if buf[inidx] == b'\n' {
|
||||
break;
|
||||
}
|
||||
inidx += 1;
|
||||
}
|
||||
if buflen > 0 && inidx < buflen && buf[inidx - 1] == b'\r' {
|
||||
crlf = true;
|
||||
}
|
||||
|
||||
inidx = 0;
|
||||
while inidx < buflen {
|
||||
let mut delta = 0;
|
||||
if (buf[inidx] > 126)
|
||||
|| (buf[inidx] == b'=')
|
||||
|| (header && buf[inidx] == b'_')
|
||||
|| (buf[inidx] == b'.'
|
||||
&& linelen == 0
|
||||
&& (inidx + 1 == buflen
|
||||
|| buf[inidx + 1] == b'\n'
|
||||
|| buf[inidx + 1] == b'\r'
|
||||
|| buf[inidx + 1] == 0))
|
||||
|| (!istext && ((buf[inidx] == b'\r') || (buf[inidx] == b'\n')))
|
||||
|| ((buf[inidx] == b'\t' || buf[inidx] == b' ') && (inidx + 1 == buflen))
|
||||
|| ((buf[inidx] < 33)
|
||||
&& (buf[inidx] != b'\r')
|
||||
&& (buf[inidx] != b'\n')
|
||||
&& (quotetabs || ((buf[inidx] != b'\t') && (buf[inidx] != b' '))))
|
||||
{
|
||||
if (linelen + 3) >= MAXLINESIZE {
|
||||
linelen = 0;
|
||||
delta += if crlf { 3 } else { 2 };
|
||||
}
|
||||
linelen += 3;
|
||||
delta += 3;
|
||||
inidx += 1;
|
||||
} else if istext
|
||||
&& ((buf[inidx] == b'\n')
|
||||
|| ((inidx + 1 < buflen)
|
||||
&& (buf[inidx] == b'\r')
|
||||
&& (buf[inidx + 1] == b'\n')))
|
||||
{
|
||||
linelen = 0;
|
||||
// Protect against whitespace on end of line
|
||||
if (inidx != 0) && ((buf[inidx - 1] == b' ') || (buf[inidx - 1] == b'\t')) {
|
||||
delta += 2;
|
||||
}
|
||||
delta += if crlf { 2 } else { 1 };
|
||||
inidx += if buf[inidx] == b'\r' { 2 } else { 1 };
|
||||
} else {
|
||||
if (inidx + 1 != buflen)
|
||||
&& (buf[inidx + 1] != b'\n')
|
||||
&& (linelen + 1) >= MAXLINESIZE
|
||||
{
|
||||
linelen = 0;
|
||||
delta += if crlf { 3 } else { 2 };
|
||||
}
|
||||
linelen += 1;
|
||||
delta += 1;
|
||||
inidx += 1;
|
||||
}
|
||||
odatalen += delta;
|
||||
}
|
||||
|
||||
let mut out_data = Vec::with_capacity(odatalen);
|
||||
inidx = 0;
|
||||
outidx = 0;
|
||||
linelen = 0;
|
||||
|
||||
while inidx < buflen {
|
||||
if (buf[inidx] > 126)
|
||||
|| (buf[inidx] == b'=')
|
||||
|| (header && buf[inidx] == b'_')
|
||||
|| ((buf[inidx] == b'.')
|
||||
&& (linelen == 0)
|
||||
&& (inidx + 1 == buflen
|
||||
|| buf[inidx + 1] == b'\n'
|
||||
|| buf[inidx + 1] == b'\r'
|
||||
|| buf[inidx + 1] == 0))
|
||||
|| (!istext && ((buf[inidx] == b'\r') || (buf[inidx] == b'\n')))
|
||||
|| ((buf[inidx] == b'\t' || buf[inidx] == b' ') && (inidx + 1 == buflen))
|
||||
|| ((buf[inidx] < 33)
|
||||
&& (buf[inidx] != b'\r')
|
||||
&& (buf[inidx] != b'\n')
|
||||
&& (quotetabs || ((buf[inidx] != b'\t') && (buf[inidx] != b' '))))
|
||||
{
|
||||
if (linelen + 3) >= MAXLINESIZE {
|
||||
// MAXLINESIZE = 76
|
||||
out_data.push(b'=');
|
||||
outidx += 1;
|
||||
if crlf {
|
||||
out_data.push(b'\r');
|
||||
outidx += 1;
|
||||
}
|
||||
out_data.push(b'\n');
|
||||
outidx += 1;
|
||||
linelen = 0;
|
||||
}
|
||||
out_data.push(b'=');
|
||||
outidx += 1;
|
||||
|
||||
ch = hex_nibble(buf[inidx] >> 4);
|
||||
if (b'a'..=b'f').contains(&ch) {
|
||||
ch -= b' ';
|
||||
}
|
||||
out_data.push(ch);
|
||||
ch = hex_nibble(buf[inidx] & 0xf);
|
||||
if (b'a'..=b'f').contains(&ch) {
|
||||
ch -= b' ';
|
||||
}
|
||||
out_data.push(ch);
|
||||
|
||||
outidx += 2;
|
||||
inidx += 1;
|
||||
linelen += 3;
|
||||
} else if istext
|
||||
&& ((buf[inidx] == b'\n')
|
||||
|| ((inidx + 1 < buflen)
|
||||
&& (buf[inidx] == b'\r')
|
||||
&& (buf[inidx + 1] == b'\n')))
|
||||
{
|
||||
linelen = 0;
|
||||
if (outidx != 0)
|
||||
&& ((out_data[outidx - 1] == b' ') || (out_data[outidx - 1] == b'\t'))
|
||||
{
|
||||
ch = hex_nibble(out_data[outidx - 1] >> 4);
|
||||
if (b'a'..=b'f').contains(&ch) {
|
||||
ch -= b' ';
|
||||
}
|
||||
out_data.push(ch);
|
||||
ch = hex_nibble(out_data[outidx - 1] & 0xf);
|
||||
if (b'a'..=b'f').contains(&ch) {
|
||||
ch -= b' ';
|
||||
}
|
||||
out_data.push(ch);
|
||||
out_data[outidx - 1] = b'=';
|
||||
outidx += 2;
|
||||
}
|
||||
|
||||
if crlf {
|
||||
out_data.push(b'\r');
|
||||
outidx += 1;
|
||||
}
|
||||
out_data.push(b'\n');
|
||||
outidx += 1;
|
||||
inidx += if buf[inidx] == b'\r' { 2 } else { 1 };
|
||||
} else {
|
||||
if (inidx + 1 != buflen) && (buf[inidx + 1] != b'\n') && (linelen + 1) >= 76 {
|
||||
// MAXLINESIZE = 76
|
||||
out_data.push(b'=');
|
||||
outidx += 1;
|
||||
if crlf {
|
||||
out_data.push(b'\r');
|
||||
outidx += 1;
|
||||
}
|
||||
out_data.push(b'\n');
|
||||
outidx += 1;
|
||||
linelen = 0;
|
||||
}
|
||||
linelen += 1;
|
||||
if header && buf[inidx] == b' ' {
|
||||
out_data.push(b'_');
|
||||
outidx += 1;
|
||||
inidx += 1;
|
||||
} else {
|
||||
out_data.push(buf[inidx]);
|
||||
outidx += 1;
|
||||
inidx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(out_data)
|
||||
})
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -259,7 +533,7 @@ mod decl {
|
||||
let length = if b.is_empty() {
|
||||
((-0x20i32) & 0x3fi32) as usize
|
||||
} else {
|
||||
((b[0] - 0x20) & 0x3f) as usize
|
||||
((b[0] - b' ') & 0x3f) as usize
|
||||
};
|
||||
|
||||
// Allocate the buffer
|
||||
@@ -316,7 +590,7 @@ mod decl {
|
||||
if backtick && num != 0 {
|
||||
0x60
|
||||
} else {
|
||||
0x20 + num
|
||||
b' ' + num
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user