| 434 | } |
| 435 | |
| 436 | pub fn fromhex(bytes: &[u8], vm: &VirtualMachine) -> PyResult<Vec<u8>> { |
| 437 | let mut iter = bytes.iter().enumerate(); |
| 438 | let mut result: Vec<u8> = Vec::with_capacity(bytes.len() / 2); |
| 439 | // None means odd number of hex digits, Some(i) means invalid char at position i |
| 440 | let invalid_char: Option<usize> = loop { |
| 441 | let (i, &b) = match iter.next() { |
| 442 | Some(val) => val, |
| 443 | None => { |
| 444 | return Ok(result); |
| 445 | } |
| 446 | }; |
| 447 | |
| 448 | if is_py_ascii_whitespace(b) { |
| 449 | continue; |
| 450 | } |
| 451 | |
| 452 | let top = match b { |
| 453 | b'0'..=b'9' => b - b'0', |
| 454 | b'a'..=b'f' => 10 + b - b'a', |
| 455 | b'A'..=b'F' => 10 + b - b'A', |
| 456 | _ => break Some(i), |
| 457 | }; |
| 458 | |
| 459 | let (i, b) = match iter.next() { |
| 460 | Some(val) => val, |
| 461 | None => break None, // odd number of hex digits |
| 462 | }; |
| 463 | |
| 464 | let bot = match b { |
| 465 | b'0'..=b'9' => b - b'0', |
| 466 | b'a'..=b'f' => 10 + b - b'a', |
| 467 | b'A'..=b'F' => 10 + b - b'A', |
| 468 | _ => break Some(i), |
| 469 | }; |
| 470 | |
| 471 | result.push((top << 4) + bot); |
| 472 | }; |
| 473 | |
| 474 | match invalid_char { |
| 475 | None => Err(vm.new_value_error( |
| 476 | "fromhex() arg must contain an even number of hexadecimal digits", |
| 477 | )), |
| 478 | Some(i) => Err(vm.new_value_error(format!( |
| 479 | "non-hexadecimal number found in fromhex() arg at position {i}" |
| 480 | ))), |
| 481 | } |
| 482 | } |
| 483 | |
| 484 | /// Parse hex string from str or bytes-like object |
| 485 | pub fn fromhex_object(string: PyObjectRef, vm: &VirtualMachine) -> PyResult<Vec<u8>> { |