| 482 | } |
| 483 | |
| 484 | pub fn unpack(&self, mut data: &[u8], vm: &VirtualMachine) -> PyResult<PyTupleRef> { |
| 485 | if self.size != data.len() { |
| 486 | return Err(new_struct_error( |
| 487 | vm, |
| 488 | format!("unpack requires a buffer of {} bytes", self.size), |
| 489 | )); |
| 490 | } |
| 491 | |
| 492 | let mut items = Vec::with_capacity(self.arg_count); |
| 493 | for code in &self.codes { |
| 494 | data = &data[code.pre_padding..]; |
| 495 | debug!("unpack code: {code:?}"); |
| 496 | match code.code { |
| 497 | FormatType::Pad => { |
| 498 | data = &data[code.repeat..]; |
| 499 | } |
| 500 | FormatType::Str => { |
| 501 | let (str_data, rest) = data.split_at(code.repeat); |
| 502 | // string is just stored inline |
| 503 | items.push(vm.ctx.new_bytes(str_data.to_vec()).into()); |
| 504 | data = rest; |
| 505 | } |
| 506 | FormatType::Pascal => { |
| 507 | let (str_data, rest) = data.split_at(code.repeat); |
| 508 | items.push(unpack_pascal(vm, str_data)); |
| 509 | data = rest; |
| 510 | } |
| 511 | _ => { |
| 512 | let unpack = code.info.unpack.unwrap(); |
| 513 | for _ in 0..code.repeat { |
| 514 | let (item_data, rest) = data.split_at(code.info.size); |
| 515 | items.push(unpack(vm, item_data)); |
| 516 | data = rest; |
| 517 | } |
| 518 | } |
| 519 | }; |
| 520 | } |
| 521 | |
| 522 | Ok(PyTuple::new_ref(items, &vm.ctx)) |
| 523 | } |
| 524 | |
| 525 | #[inline] |
| 526 | pub const fn size(&self) -> usize { |