aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe-php-shim/src/string.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-08-02 05:56:56 +0900
committernsfisis <nsfisis@gmail.com>2026-08-02 05:56:56 +0900
commit4fa973840f0a0e2cbb16f5e3341c0625793af2ed (patch)
tree6fcf9342ad97302fcb065e642309b6ccf81fe87c /crates/shirabe-php-shim/src/string.rs
parent73911c5da18cd37761f90a15558d76d5742f38e5 (diff)
downloadphp-shirabe-4fa973840f0a0e2cbb16f5e3341c0625793af2ed.tar.gz
php-shirabe-4fa973840f0a0e2cbb16f5e3341c0625793af2ed.tar.zst
php-shirabe-4fa973840f0a0e2cbb16f5e3341c0625793af2ed.zip
refactor(php-shim): drop pack/unpack in favor of direct byte handling
The only callers were trivial fixed-format uses: reading the first four hash bytes as a native int, splitting in_addr byte strings, and building a constant ZIP EOCD record. Each site now does the byte manipulation directly, so the general-purpose shims are no longer needed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe-php-shim/src/string.rs')
-rw-r--r--crates/shirabe-php-shim/src/string.rs143
1 files changed, 0 insertions, 143 deletions
diff --git a/crates/shirabe-php-shim/src/string.rs b/crates/shirabe-php-shim/src/string.rs
index 9563d614..aad5c884 100644
--- a/crates/shirabe-php-shim/src/string.rs
+++ b/crates/shirabe-php-shim/src/string.rs
@@ -598,149 +598,6 @@ fn hex_digit_value(b: u8) -> Option<u8> {
}
}
-pub fn pack(_format: &str, _values: &[PhpMixed]) -> Vec<u8> {
- let fb = _format.as_bytes();
- let mut out: Vec<u8> = Vec::new();
- let mut vi = 0usize;
- let mut i = 0;
- while i < fb.len() {
- let code = fb[i];
- i += 1;
- // Repeat count: a number, '*' (consume the rest), or implicitly 1.
- let mut repeat: usize = 1;
- let mut star = false;
- if i < fb.len() && fb[i] == b'*' {
- star = true;
- i += 1;
- } else {
- let start = i;
- while i < fb.len() && fb[i].is_ascii_digit() {
- i += 1;
- }
- if i > start {
- repeat = _format[start..i].parse().unwrap_or(1);
- }
- }
- match code {
- b'C' | b'c' | b'n' | b'v' | b'N' | b'V' => {
- let count = if star {
- _values.len().saturating_sub(vi)
- } else {
- repeat
- };
- for _ in 0..count {
- let val = crate::intval(_values.get(vi).unwrap_or(&PhpMixed::Null));
- vi += 1;
- match code {
- b'C' | b'c' => out.push(val as u8),
- b'n' => out.extend_from_slice(&(val as u16).to_be_bytes()),
- b'v' => out.extend_from_slice(&(val as u16).to_le_bytes()),
- b'N' => out.extend_from_slice(&(val as u32).to_be_bytes()),
- b'V' => out.extend_from_slice(&(val as u32).to_le_bytes()),
- _ => unreachable!(),
- }
- }
- }
- b'a' | b'A' => {
- let s = crate::php_to_string(_values.get(vi).unwrap_or(&PhpMixed::Null));
- vi += 1;
- let bytes = s.as_bytes();
- let len = if star { bytes.len() } else { repeat };
- let pad = if code == b'A' { b' ' } else { 0 };
- for j in 0..len {
- out.push(bytes.get(j).copied().unwrap_or(pad));
- }
- }
- _ => {
- // TODO(phase-d): only the C/c/n/v/N/V/a/A pack format codes are ported; the
- // machine-size and floating-point codes are not.
- todo!("pack format code {}", code as char)
- }
- }
- }
- out
-}
-
-pub fn unpack(_format: &str, _data: &[u8]) -> Option<IndexMap<String, PhpMixed>> {
- let mut result = IndexMap::new();
- let mut offset = 0usize;
- for group in _format.split('/') {
- if group.is_empty() {
- continue;
- }
- let gb = group.as_bytes();
- let code = gb[0];
- let mut j = 1;
- let mut repeat: usize = 1;
- let mut star = false;
- if j < gb.len() && gb[j] == b'*' {
- star = true;
- j += 1;
- } else {
- let start = j;
- while j < gb.len() && gb[j].is_ascii_digit() {
- j += 1;
- }
- if j > start {
- repeat = group[start..j].parse().unwrap_or(1);
- }
- }
- let name = &group[j..];
- // `i`/`I` are the native int (4 bytes on the LP64 targets in use); `s`/`S` are the native
- // short (2 bytes).
- let size = match code {
- b'C' | b'c' => 1,
- b'n' | b'v' | b's' | b'S' => 2,
- b'N' | b'V' | b'i' | b'I' => 4,
- _ => {
- // TODO(phase-d): only C/c/n/v/N/V/s/S/i/I unpack format codes are ported; the
- // machine-size long/quad and floating-point codes are not.
- todo!("unpack format code {}", code as char)
- }
- };
- let count = if star {
- _data.len().saturating_sub(offset) / size
- } else {
- repeat
- };
- for idx in 0..count {
- if offset + size > _data.len() {
- break;
- }
- let chunk = &_data[offset..offset + size];
- offset += size;
- let value: i64 = match code {
- b'C' => chunk[0] as i64,
- b'c' => chunk[0] as i8 as i64,
- b'n' => u16::from_be_bytes([chunk[0], chunk[1]]) as i64,
- b'v' => u16::from_le_bytes([chunk[0], chunk[1]]) as i64,
- b's' => i16::from_ne_bytes([chunk[0], chunk[1]]) as i64,
- b'S' => u16::from_ne_bytes([chunk[0], chunk[1]]) as i64,
- b'N' => u32::from_be_bytes(chunk.try_into().unwrap()) as i64,
- b'V' => u32::from_le_bytes(chunk.try_into().unwrap()) as i64,
- b'i' => i32::from_ne_bytes(chunk.try_into().unwrap()) as i64,
- b'I' => u32::from_ne_bytes(chunk.try_into().unwrap()) as i64,
- _ => unreachable!(),
- };
- // PHP keys: "name" for a single element; "name1", "name2", ... for repeats; the 1-based
- // index alone when the name is empty.
- let key = if star || repeat > 1 {
- if name.is_empty() {
- (idx + 1).to_string()
- } else {
- format!("{}{}", name, idx + 1)
- }
- } else if name.is_empty() {
- "1".to_string()
- } else {
- name.to_string()
- };
- result.insert(key, PhpMixed::Int(value));
- }
- }
- Some(result)
-}
-
pub fn sscanf(_subject: &str, _format: &str, _a: &mut i64, _b: &mut i64) -> i64 {
// TODO(phase-d): a general sscanf format-string parser is not ported; this specialized two-int
// overload has no current callers.