From bbe60ed21f4a1a52b1c8dbc0a9dd284dec450144 Mon Sep 17 00:00:00 2001 From: dieter Date: Mon, 27 Apr 2026 21:28:12 +0200 Subject: [PATCH 1/2] fix: preserve sign bit during signed integer encoding (fixes #6) --- templates/signed.txt | 16 ++++++++++++++-- tests/ebml.rs | 23 +++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/templates/signed.txt b/templates/signed.txt index 00db7a5..6748a9a 100644 --- a/templates/signed.txt +++ b/templates/signed.txt @@ -26,11 +26,23 @@ impl Element for {{ name }} { let bytes = self.0.to_be_bytes(); if self.0 >= 0 { let first_non_zero = bytes.iter().position(|&b| b != 0).unwrap_or(bytes.len() - 1); - buf.put_slice(&bytes[first_non_zero..]); + // Preserve sign: if the leading byte has bit 7 set, keep the 0x00 before it + let start = if first_non_zero > 0 && bytes[first_non_zero] & 0x80 != 0 { + first_non_zero - 1 + } else { + first_non_zero + }; + buf.put_slice(&bytes[start..]); Ok(()) } else { let first_non_ff = bytes.iter().position(|&b| b != 0xFF).unwrap_or(bytes.len() - 1); - buf.put_slice(&bytes[first_non_ff..]); + // Preserve sign: if the leading byte has bit 7 clear, keep the 0xFF before it + let start = if first_non_ff > 0 && bytes[first_non_ff] & 0x80 == 0 { + first_non_ff - 1 + } else { + first_non_ff + }; + buf.put_slice(&bytes[start..]); Ok(()) } } diff --git a/tests/ebml.rs b/tests/ebml.rs index eb6ed2d..5e1b158 100644 --- a/tests/ebml.rs +++ b/tests/ebml.rs @@ -43,6 +43,29 @@ fn write_ebml() { assert_eq!(ebml, ebml_read); } +#[test] +fn test_signed_integer_preserve_sign_bit() { + // Encode + let dp = DiscardPadding(14833333_i64); + let mut buf = Vec::new(); + dp.encode_body(&mut buf).unwrap(); + + // Decode + let mut b: &[u8] = &buf[..]; + let decoded = DiscardPadding::decode_body(&mut b).unwrap(); + + assert_eq!(dp, decoded); + + // Also test negative for regressions + let dp_neg = DiscardPadding(-14833333_i64); + let mut buf_neg = Vec::new(); + dp_neg.encode_body(&mut buf_neg).unwrap(); + + let mut b_neg: &[u8] = &buf_neg[..]; + let decoded_neg = DiscardPadding::decode_body(&mut b_neg).unwrap(); + assert_eq!(dp_neg, decoded_neg); +} + #[cfg(feature = "tokio")] mod tokio_tests { use mkv_element::io::tokio_impl::*; From 3340fd2d5f15c91c593608582b6247573cb8e588 Mon Sep 17 00:00:00 2001 From: dieter Date: Sat, 2 May 2026 16:04:45 +0200 Subject: [PATCH 2/2] fix formatting --- tests/ebml.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/ebml.rs b/tests/ebml.rs index 5e1b158..cfd2b7b 100644 --- a/tests/ebml.rs +++ b/tests/ebml.rs @@ -49,18 +49,14 @@ fn test_signed_integer_preserve_sign_bit() { let dp = DiscardPadding(14833333_i64); let mut buf = Vec::new(); dp.encode_body(&mut buf).unwrap(); - // Decode let mut b: &[u8] = &buf[..]; let decoded = DiscardPadding::decode_body(&mut b).unwrap(); - assert_eq!(dp, decoded); - // Also test negative for regressions let dp_neg = DiscardPadding(-14833333_i64); let mut buf_neg = Vec::new(); dp_neg.encode_body(&mut buf_neg).unwrap(); - let mut b_neg: &[u8] = &buf_neg[..]; let decoded_neg = DiscardPadding::decode_body(&mut b_neg).unwrap(); assert_eq!(dp_neg, decoded_neg);