pub struct EmulationPreventionIo<I> {
inner: I,
zero_count: u8,
}
impl<I> EmulationPreventionIo<I> {
pub fn new(inner: I) -> Self {
Self { inner, zero_count: 0 }
}
}
impl<I: std::io::Write> std::io::Write for EmulationPreventionIo<I> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
for &byte in buf {
if self.zero_count >= 2 && (byte <= 0x03) {
self.inner.write_all(&[0x3])?;
self.zero_count = 0;
}
self.inner.write_all(&[byte])?;
if byte == 0x00 {
self.zero_count += 1;
} else {
self.zero_count = 0;
}
}
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
self.inner.flush()
}
}
impl<I: std::io::Read> std::io::Read for EmulationPreventionIo<I> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let mut read_size = 0;
let mut one_byte = [0; 1];
while buf.len() > read_size {
let size = self.inner.read(&mut one_byte)?;
if size == 0 {
break;
}
let byte = one_byte[0];
match byte {
0x03 if self.zero_count >= 2 => {
self.zero_count = 0;
continue;
}
0x00 => {
self.zero_count += 1;
}
_ => {
self.zero_count = 0;
}
}
buf[read_size] = byte;
read_size += 1;
}
Ok(read_size)
}
}
#[cfg(test)]
#[cfg_attr(all(test, coverage_nightly), coverage(off))]
mod tests {
use std::io::{Read, Write};
use crate::EmulationPreventionIo;
#[test]
fn test_write_emulation_prevention_single() {
let mut buf = Vec::new();
let mut writer = EmulationPreventionIo::new(&mut buf);
writer.write_all(&[0x00, 0x00, 0x01]).unwrap();
writer.flush().unwrap();
assert_eq!(buf, vec![0x00, 0x00, 0x03, 0x01]);
}
#[test]
fn test_write_emulation_prevention_multiple() {
let mut buf = Vec::new();
let mut writer = EmulationPreventionIo::new(&mut buf);
writer.write_all(&[0x00, 0x00, 0x01, 0x00, 0x00, 0x02]).unwrap();
writer.flush().unwrap();
assert_eq!(buf, vec![0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x03, 0x02]);
}
#[test]
fn test_read_emulation_prevention() {
let input = [0x00, 0x00, 0x03, 0x01];
let mut reader = EmulationPreventionIo::new(&input[..]);
let mut output = Vec::new();
reader.read_to_end(&mut output).unwrap();
assert_eq!(output, vec![0x00, 0x00, 0x01]);
}
#[test]
fn test_read_emulation_prevention_multiple() {
let input = [0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x03, 0x02];
let mut reader = EmulationPreventionIo::new(&input[..]);
let mut output = Vec::new();
reader.read_to_end(&mut output).unwrap();
assert_eq!(output, vec![0x00, 0x00, 0x01, 0x00, 0x00, 0x02]);
}
#[test]
fn test_roundtrip() {
let original = vec![0x00, 0x00, 0x01, 0x00, 0x00, 0x02];
let mut encoded = Vec::new();
let mut writer = EmulationPreventionIo::new(&mut encoded);
writer.write_all(&original).unwrap();
writer.flush().unwrap();
let mut reader = EmulationPreventionIo::new(&encoded[..]);
let mut decoded = Vec::new();
reader.read_to_end(&mut decoded).unwrap();
assert_eq!(original, decoded);
}
}