| 412 | } |
| 413 | #[pyfunction] |
| 414 | fn a2b_qp(args: A2bQpArgs) -> PyResult<Vec<u8>> { |
| 415 | let s = args.data; |
| 416 | let header = args.header; |
| 417 | s.with_ref(|buffer| { |
| 418 | let len = buffer.len(); |
| 419 | let mut out_data = Vec::with_capacity(len); |
| 420 | |
| 421 | let mut idx = 0; |
| 422 | |
| 423 | while idx < len { |
| 424 | if buffer[idx] == b'=' { |
| 425 | idx += 1; |
| 426 | if idx >= len { |
| 427 | break; |
| 428 | } |
| 429 | // Soft line breaks |
| 430 | if (buffer[idx] == b'\n') || (buffer[idx] == b'\r') { |
| 431 | if buffer[idx] != b'\n' { |
| 432 | while idx < len && buffer[idx] != b'\n' { |
| 433 | idx += 1; |
| 434 | } |
| 435 | } |
| 436 | if idx < len { |
| 437 | idx += 1; |
| 438 | } |
| 439 | } else if buffer[idx] == b'=' { |
| 440 | // broken case from broken python qp |
| 441 | out_data.push(b'='); |
| 442 | idx += 1; |
| 443 | } else if idx + 1 < len |
| 444 | && ((buffer[idx] >= b'A' && buffer[idx] <= b'F') |
| 445 | || (buffer[idx] >= b'a' && buffer[idx] <= b'f') |
| 446 | || (buffer[idx] >= b'0' && buffer[idx] <= b'9')) |
| 447 | && ((buffer[idx + 1] >= b'A' && buffer[idx + 1] <= b'F') |
| 448 | || (buffer[idx + 1] >= b'a' && buffer[idx + 1] <= b'f') |
| 449 | || (buffer[idx + 1] >= b'0' && buffer[idx + 1] <= b'9')) |
| 450 | { |
| 451 | // hex val |
| 452 | if let (Some(ch1), Some(ch2)) = |
| 453 | (unhex_nibble(buffer[idx]), unhex_nibble(buffer[idx + 1])) |
| 454 | { |
| 455 | out_data.push((ch1 << 4) | ch2); |
| 456 | } |
| 457 | idx += 2; |
| 458 | } else { |
| 459 | out_data.push(b'='); |
| 460 | } |
| 461 | } else if header && buffer[idx] == b'_' { |
| 462 | out_data.push(b' '); |
| 463 | idx += 1; |
| 464 | } else { |
| 465 | out_data.push(buffer[idx]); |
| 466 | idx += 1; |
| 467 | } |
| 468 | } |
| 469 | |
| 470 | Ok(out_data) |
| 471 | }) |