1#![cfg_attr(doc_cfg, feature(doc_cfg))]
6
7use std::fs::File;
8use std::io::{Read, Seek, SeekFrom, Write};
9
10#[derive(Debug, Default)]
12pub struct Operations {
13 pub flip: bool,
15 pub reverse: bool,
17 pub swab: bool,
19}
20
21pub fn process_buffer(buffer: &mut [u8], ops: &Operations) {
23 for b in buffer.iter_mut() {
24 if ops.flip {
25 *b = !*b;
26 }
27
28 if ops.reverse & ops.swab {
29 let mut t = *b;
30 t = (t & 0xCC) >> 2 | (t & 0x33) << 2;
31 t = (t & 0xAA) >> 1 | (t & 0x55) << 1;
32 *b = t;
33 } else if ops.reverse {
34 let mut t = *b;
35 t = (t & 0xF0) >> 4 | (t & 0x0F) << 4;
36 t = (t & 0xCC) >> 2 | (t & 0x33) << 2;
37 t = (t & 0xAA) >> 1 | (t & 0x55) << 1;
38 *b = t;
39 } else if ops.swab {
40 let mut t = *b;
41 t = (t & 0xF0) >> 4 | (t & 0x0F) << 4;
42 *b = t;
43 }
44 }
45}
46
47pub fn process_file(file: &mut File, ops: &Operations) -> std::io::Result<u64> {
52 log::debug!("ops = {:?}", ops);
53
54 let mut nflipped = 0;
55 let mut buffer = [0; 1024 * 256];
56 loop {
57 let pos = file.stream_position()?;
58 let nread = file.read(&mut buffer)?;
59
60 log::debug!("pos = {}, nread = {}", pos, nread);
61 debug_assert_eq!(pos + nread as u64, file.stream_position()?);
62
63 if nread == 0 {
64 break;
65 }
66
67 process_buffer(&mut buffer[0..nread], ops);
68
69 file.seek(SeekFrom::Start(pos))?;
70
71 let nwritten = file.write(&buffer[0..nread])?;
72
73 log::trace!("nwritten = {}", nwritten);
74 debug_assert_eq!(nread, nwritten);
75
76 nflipped += nread as u64;
77 }
78 Ok(nflipped)
79}
80
81#[cfg(feature = "memmap")]
85#[cfg_attr(doc_cfg, doc(cfg(feature = "memmap")))]
86pub fn process_file_mmap(file: &mut File, ops: &Operations) -> std::io::Result<u64> {
87 let mut mmap = unsafe { memmap::MmapMut::map_mut(&file)? };
88
89 process_buffer(&mut mmap, ops);
90
91 Ok(mmap.len() as u64)
92}
93
94#[deprecated = "use [`process_file`](process_file) instead"]
95pub fn flip_file(file: &mut File) -> std::io::Result<u64> {
96 let mut nflipped = 0;
97 let mut buffer = [0; 1024 * 256];
98 loop {
99 let pos = file.stream_position()?;
100 let nread = file.read(&mut buffer)?;
101
102 log::debug!("pos = {}, nread = {}", pos, nread);
103 debug_assert_eq!(pos + nread as u64, file.stream_position()?);
104
105 if nread == 0 {
106 break;
107 }
108
109 for i in 0..nread {
110 buffer[i] = !buffer[i];
111 }
112
113 file.seek(SeekFrom::Start(pos))?;
114
115 let nwritten = file.write(&buffer[0..nread])?;
116
117 log::trace!("nwritten = {}", nwritten);
118 debug_assert_eq!(nread, nwritten);
119
120 nflipped += nread as u64;
121 }
122 Ok(nflipped)
123}
124
125#[deprecated = "use [`process_file_mmap`](process_file_mmap) instead"]
126#[cfg(feature = "memmap")]
127#[cfg_attr(doc_cfg, doc(cfg(feature = "memmap")))]
128pub fn flip_file_mmap(file: &mut File) -> std::io::Result<u64> {
129 let mut mmap = unsafe { memmap::MmapMut::map_mut(&file)? };
130
131 for b in mmap.iter_mut() {
132 *b = !*b;
133 }
134
135 Ok(mmap.len() as u64)
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 #[test]
143 #[allow(deprecated)]
144 fn test_flip_file() -> std::io::Result<()> {
145 let mut file = tempfile::tempfile()?;
146 for i in 0..255 {
147 file.write(&[i])?;
148 }
149 file.seek(SeekFrom::Start(0))?;
150 flip_file(&mut file)?;
151 file.seek(SeekFrom::Start(0))?;
152 for i in 0..255 {
153 let buf = &mut [0];
154 file.read(buf)?;
155 assert_eq!(buf[0], !i);
156 }
157 Ok(())
158 }
159
160 #[test]
161 #[cfg(feature = "memmap")]
162 #[allow(deprecated)]
163 fn test_flip_file_mmap() -> std::io::Result<()> {
164 let mut file = tempfile::tempfile()?;
165 for i in 0..255 {
166 file.write(&[i])?;
167 }
168 file.seek(SeekFrom::Start(0))?;
169 flip_file_mmap(&mut file)?;
170 file.seek(SeekFrom::Start(0))?;
171 for i in 0..255 {
172 let buf = &mut [0];
173 file.read(buf)?;
174 assert_eq!(buf[0], !i);
175 }
176 Ok(())
177 }
178}