1
use std::io::Read;
2
use std::io::Write;
3
use std::io::{self};
4

            
5
use bitstream_io::BigEndian;
6
use bitstream_io::BitRead;
7
use bitstream_io::BitReader;
8
use bitstream_io::BitWrite;
9
use bitstream_io::BitWriter;
10
use log::error;
11

            
12
use merc_number::read_u64_variablelength;
13
use merc_number::write_u64_variablelength;
14
use merc_utilities::MercError;
15

            
16
/// Trait for writing bit-level data.
17
pub trait BitStreamWrite {
18
    /// Writes the least significant bits from a u64 value. The `number_of_bits` must be <= 64.
19
    fn write_bits(&mut self, value: u64, number_of_bits: u8) -> Result<(), MercError>;
20

            
21
    /// Writes a string prefixed with its length as a variable-width integer.
22
    fn write_string(&mut self, s: &str) -> Result<(), MercError>;
23

            
24
    /// Writes a u64 value using variable-width encoding.
25
    fn write_integer(&mut self, value: u64) -> Result<(), MercError>;
26

            
27
    /// Flushes any remaining bits to the underlying writer.
28
    fn flush(&mut self) -> Result<(), MercError>;
29
}
30

            
31
/// Trait for reading bit-level data.
32
pub trait BitStreamRead {
33
    /// Reads bits into the least significant bits of a u64. The `number_of_bits` must be <= 64.
34
    fn read_bits(&mut self, number_of_bits: u8) -> Result<u64, MercError>;
35

            
36
    /// Reads a length-prefixed string.
37
    fn read_string(&mut self) -> Result<String, MercError>;
38

            
39
    /// Reads a variable-width encoded integer.
40
    fn read_integer(&mut self) -> Result<u64, MercError>;
41
}
42

            
43
/// Writer for bit-level output operations using an underlying writer.
44
pub struct BitStreamWriter<W: Write> {
45
    writer: BitWriter<W, BigEndian>,
46
}
47

            
48
impl<W: Write> BitStreamWriter<W> {
49
    /// Creates a new BitStreamWriter wrapping the provided writer.
50
606
    pub fn new(writer: W) -> Self {
51
606
        Self {
52
606
            writer: BitWriter::new(writer),
53
606
        }
54
606
    }
55
}
56

            
57
impl<W: Write> Drop for BitStreamWriter<W> {
58
606
    fn drop(&mut self) {
59
606
        if self.flush().is_err() {
60
            error!("Error flushing the stream when dropped!")
61
606
        }
62
606
    }
63
}
64

            
65
/// Reader for bit-level input operations from an underlying reader.
66
pub struct BitStreamReader<R: Read> {
67
    reader: BitReader<R, BigEndian>,
68
    text_buffer: Vec<u8>,
69
}
70

            
71
impl<R: Read> BitStreamReader<R> {
72
    /// Creates a new BitStreamReader wrapping the provided reader.
73
612
    pub fn new(reader: R) -> Self {
74
612
        Self {
75
612
            reader: BitReader::new(reader),
76
612
            text_buffer: Vec::with_capacity(128),
77
612
        }
78
612
    }
79
}
80

            
81
impl<W: Write> BitStreamWrite for BitStreamWriter<W> {
82
2180551
    fn write_bits(&mut self, value: u64, number_of_bits: u8) -> Result<(), MercError> {
83
2180551
        if number_of_bits > 64 {
84
1
            return Err(io::Error::new(io::ErrorKind::InvalidInput, "number_of_bits must be <= 64").into());
85
2180550
        }
86
2180550
        Ok(self.writer.write_var(number_of_bits as u32, value)?)
87
2180551
    }
88

            
89
10491
    fn write_string(&mut self, s: &str) -> Result<(), MercError> {
90
10491
        self.write_integer(s.len() as u64)?;
91
10491
        self.writer.write_bytes(s.as_bytes())?;
92
10491
        Ok(())
93
10491
    }
94

            
95
666300
    fn write_integer(&mut self, value: u64) -> Result<(), MercError> {
96
666300
        write_u64_variablelength(&mut self.writer, value)?;
97
666300
        Ok(())
98
666300
    }
99

            
100
1109
    fn flush(&mut self) -> Result<(), MercError> {
101
1109
        self.writer.byte_align()?;
102
1109
        Ok(self.writer.flush()?)
103
1109
    }
104
}
105

            
106
impl<R: Read> BitStreamRead for BitStreamReader<R> {
107
2239358
    fn read_bits(&mut self, number_of_bits: u8) -> Result<u64, MercError> {
108
2239358
        if number_of_bits > 64 {
109
            return Err(io::Error::new(io::ErrorKind::InvalidInput, "number_of_bits must be <= 64").into());
110
2239358
        }
111
2239358
        Ok(self.reader.read_var(number_of_bits as u32)?)
112
2239358
    }
113

            
114
10943
    fn read_string(&mut self) -> Result<String, MercError> {
115
10943
        let length = self.read_integer()?;
116
10943
        let length_usize: usize = length
117
10943
            .try_into()
118
10943
            .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "string length exceeds usize"))?;
119

            
120
10943
        self.text_buffer.clear();
121
10943
        self.text_buffer
122
10943
            .try_reserve(length_usize)
123
10943
            .map_err(|_| io::Error::new(io::ErrorKind::OutOfMemory, "string too large to allocate"))?;
124
10943
        self.text_buffer.resize(length_usize, 0);
125
10943
        self.reader.read_bytes(&mut self.text_buffer)?;
126

            
127
        // Validate in place and copy the result out, so `text_buffer` keeps its
128
        // allocation for reuse on the next call (taking it would reset it to empty).
129
10943
        std::str::from_utf8(&self.text_buffer)
130
10943
            .map(str::to_owned)
131
10943
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e).into())
132
10943
    }
133

            
134
681051
    fn read_integer(&mut self) -> Result<u64, MercError> {
135
681051
        read_u64_variablelength(&mut self.reader)
136
681051
    }
137
}
138

            
139
#[cfg(test)]
140
mod tests {
141
    use super::BitStreamRead;
142
    use super::BitStreamReader;
143
    use super::BitStreamWrite;
144
    use super::BitStreamWriter;
145

            
146
    use log::debug;
147
    use rand::RngExt;
148
    use rand::distr::Alphanumeric;
149

            
150
    use merc_utilities::random_test;
151

            
152
    /// Decide (arbitrarily) what to write into the bitstream.
153
    #[derive(Debug)]
154
    enum Instruction {
155
        String(String),
156
        Integer(u64),
157
        /// (value, num_of_bits), where num_of_bits must be at most 64.
158
        Bits(u64, u8),
159
    }
160

            
161
    /// Calculate minimum bits needed to represent the value
162
    /// Use 1 bit if value is 0 to ensure at least 1 bit is written
163
3399
    pub(super) fn required_bits(value: u64) -> u8 {
164
3399
        if value == 0 {
165
            1
166
        } else {
167
3399
            64 - value.leading_zeros() as u8
168
        }
169
3399
    }
170

            
171
    #[test]
172
1
    fn test_arbitrary_bitstream() {
173
100
        random_test(100, |rng| {
174
100
            let instructions: Vec<Instruction> = (0..100)
175
10000
                .map(|_| match rng.random_range(0..3) {
176
                    0 => {
177
3275
                        let string = rng.sample_iter(&Alphanumeric).take(7).map(char::from).collect();
178
3275
                        Instruction::String(string)
179
                    }
180
3326
                    1 => Instruction::Integer(rng.random()),
181
                    2 => {
182
3399
                        let value: u64 = rng.random();
183
3399
                        Instruction::Bits(value, required_bits(value))
184
                    }
185
                    _ => unreachable!("The range is from 0 to 3"),
186
10000
                })
187
100
                .collect();
188

            
189
100
            let mut buffer = Vec::new();
190
            {
191
100
                let mut writer = BitStreamWriter::new(&mut buffer);
192

            
193
10000
                for inst in &instructions {
194
10000
                    debug!("Writing {inst:?}");
195
10000
                    match inst {
196
3275
                        Instruction::String(string) => {
197
3275
                            writer.write_string(string).expect("Failed to write into stream")
198
                        }
199
3326
                        Instruction::Integer(value) => {
200
3326
                            writer.write_integer(*value).expect("Failed to write into stream")
201
                        }
202
3399
                        Instruction::Bits(value, number_of_bits) => writer
203
3399
                            .write_bits(*value, *number_of_bits)
204
3399
                            .expect("Failed to write into stream"),
205
                    }
206
                }
207

            
208
100
                writer.flush().expect("Failed to write into stream");
209
            }
210

            
211
100
            let mut reader = BitStreamReader::new(&buffer[..]);
212

            
213
10000
            for inst in &instructions {
214
10000
                debug!("Checking {inst:?}");
215
10000
                match inst {
216
3275
                    Instruction::String(string) => {
217
3275
                        debug_assert_eq!(
218
3275
                            reader.read_string().expect("Failed to read from stream"),
219
                            *string,
220
                            "Failed to read back the string"
221
                        )
222
                    }
223
3326
                    Instruction::Integer(value) => {
224
3326
                        debug_assert_eq!(
225
3326
                            reader.read_integer().expect("Failed to read from stream"),
226
                            *value,
227
                            "Failed to read back the integer"
228
                        )
229
                    }
230
3399
                    Instruction::Bits(value, number_of_bits) => {
231
3399
                        debug_assert_eq!(
232
3399
                            reader.read_bits(*number_of_bits).expect("Failed to read from stream"),
233
                            *value,
234
                            "Failed to read back the bits"
235
                        )
236
                    }
237
                }
238
            }
239
100
        });
240
1
    }
241

            
242
    /// Writes the given strings and reads them back, asserting they round-trip.
243
101
    fn roundtrip_strings(strings: &[&str]) {
244
101
        let mut buffer = Vec::new();
245
        {
246
101
            let mut writer = BitStreamWriter::new(&mut buffer);
247
5007
            for s in strings {
248
5007
                writer.write_string(s).expect("Failed to write string");
249
5007
            }
250
101
            writer.flush().expect("Failed to flush");
251
        }
252

            
253
101
        let mut reader = BitStreamReader::new(&buffer[..]);
254
5007
        for s in strings {
255
5007
            assert_eq!(&reader.read_string().expect("Failed to read string"), s);
256
        }
257
101
    }
258

            
259
    #[test]
260
1
    fn test_string_edge_cases() {
261
        // Empty strings, multi-byte UTF-8, and a long string all in one stream so
262
        // that the shared `text_buffer` is reused across reads of differing length.
263
1
        roundtrip_strings(&["", "a", "", "héllo wörld", "🦀∑≈ç", &"x".repeat(10_000), ""]);
264
1
    }
265

            
266
    #[test]
267
1
    fn test_string_roundtrip_random_unicode() {
268
100
        random_test(100, |rng| {
269
100
            let strings: Vec<String> = (0..50)
270
5000
                .map(|_| {
271
5000
                    let len = rng.random_range(0..32);
272
77382
                    (0..len).map(|_| rng.random::<char>()).collect()
273
5000
                })
274
100
                .collect();
275
100
            let refs: Vec<&str> = strings.iter().map(String::as_str).collect();
276
100
            roundtrip_strings(&refs);
277
100
        });
278
1
    }
279

            
280
    #[test]
281
1
    fn test_read_string_rejects_invalid_utf8() {
282
        // Manually craft a stream: length 2 followed by an invalid UTF-8 sequence.
283
1
        let mut buffer = Vec::new();
284
1
        {
285
1
            let mut writer = BitStreamWriter::new(&mut buffer);
286
1
            writer.write_integer(2).expect("Failed to write length");
287
1
            writer.write_bits(0xFF, 8).expect("Failed to write byte");
288
1
            writer.write_bits(0xFE, 8).expect("Failed to write byte");
289
1
            writer.flush().expect("Failed to flush");
290
1
        }
291

            
292
1
        let mut reader = BitStreamReader::new(&buffer[..]);
293
1
        assert!(reader.read_string().is_err(), "Invalid UTF-8 should produce an error");
294
1
    }
295

            
296
    #[test]
297
1
    fn test_write_bits_rejects_too_many_bits() {
298
1
        let mut buffer = Vec::new();
299
1
        let mut writer = BitStreamWriter::new(&mut buffer);
300
1
        assert!(writer.write_bits(0, 65).is_err(), "More than 64 bits must be rejected");
301
1
    }
302
}