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..cfd2b7b 100644 --- a/tests/ebml.rs +++ b/tests/ebml.rs @@ -43,6 +43,25 @@ 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::*;