libtw2_packer/
lib.rs

1use arrayvec::ArrayVec;
2use buffer::with_buffer;
3use buffer::Buffer;
4use buffer::BufferRef;
5use buffer::CapacityError;
6use libtw2_common::num::Cast;
7use libtw2_common::unwrap_or_return;
8use std::iter;
9use std::mem;
10use std::slice;
11#[cfg(feature = "uuid")]
12use uuid::Uuid;
13use warn::Warn;
14
15#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
16pub enum Warning {
17    OverlongIntEncoding,
18    NonZeroIntPadding,
19    ExcessData,
20}
21
22#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
23pub struct ExcessData;
24
25#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
26pub struct WeirdStringTermination;
27
28impl From<ExcessData> for Warning {
29    fn from(_: ExcessData) -> Warning {
30        Warning::ExcessData
31    }
32}
33
34#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
35pub struct ControlCharacters;
36
37#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
38pub struct IntOutOfRange;
39
40#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
41pub struct UnexpectedEnd;
42
43// Format: ESDD_DDDD EDDD_DDDD EDDD_DDDD EDDD_DDDD PPPP_DDDD
44// E - Extend
45// S - Sign
46// D - Digit (little-endian)
47// P - Padding
48//
49// Padding must be zeroed. The extend bit specifies whether another byte
50// follows.
51fn read_int<W>(warn: &mut W, iter: &mut slice::Iter<u8>) -> Result<i32, UnexpectedEnd>
52where
53    W: Warn<Warning>,
54{
55    let mut result = 0;
56    let mut len = 1;
57
58    let mut src = *unwrap_or_return!(iter.next(), Err(UnexpectedEnd));
59    let sign = ((src >> 6) & 1) as i32;
60
61    result |= (src & 0b0011_1111) as i32;
62
63    for i in 0..4 {
64        if src & 0b1000_0000 == 0 {
65            break;
66        }
67        src = *unwrap_or_return!(iter.next(), Err(UnexpectedEnd));
68        len += 1;
69        if i == 3 && src & 0b1111_0000 != 0 {
70            warn.warn(Warning::NonZeroIntPadding);
71        }
72        result |= ((src & 0b0111_1111) as i32) << (6 + 7 * i);
73    }
74
75    if len > 1 && src == 0b0000_0000 {
76        warn.warn(Warning::OverlongIntEncoding);
77    }
78
79    result ^= -sign;
80
81    Ok(result)
82}
83
84/// Sets the n-th bit of a byte conditionally.
85fn to_bit(b: bool, bit: u32) -> u8 {
86    assert!(bit < 8);
87    if b {
88        1 << bit
89    } else {
90        0
91    }
92}
93
94fn write_int<E, F: FnMut(&[u8]) -> Result<(), E>>(int: i32, f: F) -> Result<(), E> {
95    let mut f = f;
96    let mut buf: ArrayVec<[u8; 5]> = ArrayVec::new();
97    let sign = if int < 0 { 1 } else { 0 };
98    let mut int = (int ^ -sign) as u32;
99    let next = (int & 0b0011_1111) as u8;
100    int >>= 6;
101    buf.push(to_bit(int != 0, 7) | to_bit(sign != 0, 6) | next);
102    while int != 0 {
103        let next = (int & 0b0111_1111) as u8;
104        int >>= 7;
105        buf.push(to_bit(int != 0, 7) | next);
106    }
107    f(&buf)
108}
109
110fn read_string<'a>(iter: &mut slice::Iter<'a, u8>) -> Result<&'a [u8], UnexpectedEnd> {
111    let slice = iter.as_slice();
112    // `by_ref` is needed as the iterator is silently copied otherwise.
113    for (i, b) in iter.by_ref().cloned().enumerate() {
114        if b == 0 {
115            return Ok(&slice[..i]);
116        }
117    }
118    Err(UnexpectedEnd)
119}
120
121fn write_string<E, F: FnMut(&[u8]) -> Result<(), E>>(string: &[u8], f: F) -> Result<(), E> {
122    let mut f = f;
123    assert!(string.iter().all(|&b| b != 0));
124    f(string)?;
125    f(&[0])?;
126    Ok(())
127}
128
129pub struct Packer<'d, 's> {
130    buf: BufferRef<'d, 's>,
131}
132
133impl<'r, 'd, 's> Buffer<'d> for &'r mut Packer<'d, 's> {
134    type Intermediate = buffer::BufferRefBuffer<'r, 'd, 's>;
135    fn to_to_buffer_ref(self) -> Self::Intermediate {
136        (&mut self.buf).to_to_buffer_ref()
137    }
138}
139
140impl<'d, 's> Packer<'d, 's> {
141    fn new(buf: BufferRef<'d, 's>) -> Packer<'d, 's> {
142        Packer { buf: buf }
143    }
144    pub fn write_string(&mut self, string: &[u8]) -> Result<(), CapacityError> {
145        write_string(string, |b| self.buf.write(b))
146    }
147    pub fn write_int(&mut self, int: i32) -> Result<(), CapacityError> {
148        write_int(int, |b| self.buf.write(b))
149    }
150    pub fn write_data(&mut self, data: &[u8]) -> Result<(), CapacityError> {
151        self.write_int(data.len().try_i32().ok_or(CapacityError)?)?;
152        self.buf.write(data)?;
153        Ok(())
154    }
155    pub fn write_raw(&mut self, data: &[u8]) -> Result<(), CapacityError> {
156        self.buf.write(data)
157    }
158    #[cfg(feature = "uuid")]
159    pub fn write_uuid(&mut self, uuid: Uuid) -> Result<(), CapacityError> {
160        self.write_raw(uuid.as_bytes())
161    }
162    pub fn write_rest(&mut self, data: &[u8]) -> Result<(), CapacityError> {
163        // TODO: Fail if other stuff happens afterwards.
164        self.buf.write(data)
165    }
166    pub fn written(self) -> &'d [u8] {
167        self.buf.initialized()
168    }
169}
170
171pub fn with_packer<'a, B: Buffer<'a>, F, R>(buf: B, f: F) -> R
172where
173    F: for<'b> FnOnce(Packer<'a, 'b>) -> R,
174{
175    with_buffer(buf, |b| f(Packer::new(b)))
176}
177
178pub struct Unpacker<'a> {
179    original: &'a [u8],
180    iter: slice::Iter<'a, u8>,
181    demo: bool,
182}
183
184impl<'a> Unpacker<'a> {
185    fn new_impl(data: &[u8], demo: bool) -> Unpacker {
186        Unpacker {
187            original: data,
188            iter: data.iter(),
189            demo: demo,
190        }
191    }
192    pub fn new(data: &[u8]) -> Unpacker {
193        Unpacker::new_impl(data, false)
194    }
195    pub fn new_from_demo(data: &[u8]) -> Unpacker {
196        assert!(
197            data.len() % 4 == 0,
198            "demo data must be padded to a multiple of four bytes"
199        );
200        Unpacker::new_impl(data, true)
201    }
202    pub fn is_empty(&self) -> bool {
203        self.iter.len() == 0
204    }
205    fn use_up(&mut self) {
206        // Advance the iterator to the end.
207        self.iter.by_ref().count();
208    }
209    fn error<T>(&mut self) -> Result<T, UnexpectedEnd> {
210        self.use_up();
211        Err(UnexpectedEnd)
212    }
213    pub fn read_string(&mut self) -> Result<&'a [u8], UnexpectedEnd> {
214        read_string(&mut self.iter)
215    }
216    pub fn read_int<W: Warn<Warning>>(&mut self, warn: &mut W) -> Result<i32, UnexpectedEnd> {
217        read_int(warn, &mut self.iter)
218    }
219    pub fn read_data<W: Warn<Warning>>(&mut self, warn: &mut W) -> Result<&'a [u8], UnexpectedEnd> {
220        let len = match self.read_int(warn).map(|l| l.try_usize()) {
221            Ok(Some(l)) => l,
222            _ => return self.error(),
223        };
224        let slice = self.iter.as_slice();
225        if len > slice.len() {
226            return self.error();
227        }
228        let (data, remaining) = slice.split_at(len);
229        self.iter = remaining.iter();
230        Ok(data)
231    }
232    pub fn read_rest(&mut self) -> Result<&'a [u8], UnexpectedEnd> {
233        // TODO: Fail if earlier call errored out.
234        let result = Ok(self.iter.as_slice());
235        self.use_up();
236        result
237    }
238    pub fn read_raw(&mut self, len: usize) -> Result<&'a [u8], UnexpectedEnd> {
239        let slice = self.iter.as_slice();
240        if slice.len() < len {
241            self.use_up();
242            return Err(UnexpectedEnd);
243        }
244        let (raw, rest) = slice.split_at(len);
245        self.iter = rest.iter();
246        Ok(raw)
247    }
248    #[cfg(feature = "uuid")]
249    pub fn read_uuid(&mut self) -> Result<Uuid, UnexpectedEnd> {
250        Ok(Uuid::from_slice(self.read_raw(mem::size_of::<Uuid>())?).unwrap())
251    }
252    pub fn finish<W: Warn<Warning>>(&mut self, warn: &mut W) {
253        if !self.demo {
254            if !self.is_empty() {
255                warn.warn(Warning::ExcessData);
256            }
257        } else {
258            let rest = self.as_slice();
259            if rest.len() >= 4 || rest.iter().any(|&b| b != 0) {
260                warn.warn(Warning::ExcessData);
261            }
262        }
263        self.use_up();
264    }
265    pub fn as_slice(&self) -> &'a [u8] {
266        self.iter.as_slice()
267    }
268    pub fn num_bytes_read(&self) -> usize {
269        self.original.len() - self.iter.len()
270    }
271}
272
273pub struct IntUnpacker<'a> {
274    iter: iter::Cloned<slice::Iter<'a, i32>>,
275}
276
277impl<'a> IntUnpacker<'a> {
278    pub fn new(slice: &[i32]) -> IntUnpacker {
279        IntUnpacker {
280            iter: slice.iter().cloned(),
281        }
282    }
283    pub fn read_int(&mut self) -> Result<i32, UnexpectedEnd> {
284        self.iter.next().ok_or(UnexpectedEnd)
285    }
286    pub fn finish<W: Warn<ExcessData>>(&mut self, warn: &mut W) {
287        // TODO: replace with !self.is_empty()
288        if self.iter.len() != 0 {
289            warn.warn(ExcessData);
290        }
291    }
292}
293
294pub fn in_range(v: i32, min: i32, max: i32) -> Result<i32, IntOutOfRange> {
295    if min <= v && v <= max {
296        Ok(v)
297    } else {
298        Err(IntOutOfRange)
299    }
300}
301
302pub fn at_least(v: i32, min: i32) -> Result<i32, IntOutOfRange> {
303    if min <= v {
304        Ok(v)
305    } else {
306        Err(IntOutOfRange)
307    }
308}
309
310pub fn to_bool(v: i32) -> Result<bool, IntOutOfRange> {
311    Ok(in_range(v, 0, 1)? != 0)
312}
313
314pub fn sanitize<'a, W: Warn<Warning>>(
315    warn: &mut W,
316    v: &'a [u8],
317) -> Result<&'a [u8], ControlCharacters> {
318    if v.iter().any(|&b| b < b' ') {
319        return Err(ControlCharacters);
320    }
321    let _ = warn;
322    // TODO: Implement whitespace skipping.
323    Ok(v)
324}
325
326pub fn positive(v: i32) -> Result<i32, IntOutOfRange> {
327    if v >= 0 {
328        Ok(v)
329    } else {
330        Err(IntOutOfRange)
331    }
332}
333
334pub fn string_to_ints(result: &mut [i32], string: &[u8]) {
335    assert!(string.iter().all(|&b| b != 0));
336    // Strict less-than because of the NUL-termination.
337    assert!(string.len() < result.len() * mem::size_of::<i32>());
338    let mut output = result.iter_mut();
339    let mut input = string.iter().cloned();
340    while let Some(o) = output.next() {
341        let v0 = input.next().unwrap_or(0).wrapping_add(0x80);
342        let v1 = input.next().unwrap_or(0).wrapping_add(0x80);
343        let v2 = input.next().unwrap_or(0).wrapping_add(0x80);
344        // FIXME: Use .is_empty()
345        let v3 = input
346            .next()
347            .unwrap_or(if output.len() != 0 { 0 } else { 0x80 })
348            .wrapping_add(0x80);
349        *o = (v0 as i32) << 24 | (v1 as i32) << 16 | (v2 as i32) << 8 | (v3 as i32);
350    }
351}
352
353pub fn string_to_ints3(string: &[u8]) -> [i32; 3] {
354    let mut result: [i32; 3] = Default::default();
355    string_to_ints(&mut result, string);
356    result
357}
358pub fn string_to_ints4(string: &[u8]) -> [i32; 4] {
359    let mut result: [i32; 4] = Default::default();
360    string_to_ints(&mut result, string);
361    result
362}
363pub fn string_to_ints6(string: &[u8]) -> [i32; 6] {
364    let mut result: [i32; 6] = Default::default();
365    string_to_ints(&mut result, string);
366    result
367}
368
369pub fn ints_to_bytes(result: &mut [u8], input: &[i32]) {
370    assert!(result.len() == input.len() * mem::size_of::<i32>());
371    for (output, input) in result.chunks_mut(mem::size_of::<i32>()).zip(input) {
372        output[0] = (((input >> 24) & 0xff) - 0x80) as u8;
373        output[1] = (((input >> 16) & 0xff) - 0x80) as u8;
374        output[2] = (((input >> 8) & 0xff) - 0x80) as u8;
375        output[3] = (((input >> 0) & 0xff) - 0x80) as u8;
376    }
377}
378
379pub fn bytes_to_string<'a, W>(warn: &mut W, bytes: &'a [u8]) -> &'a [u8]
380where
381    W: Warn<WeirdStringTermination>,
382{
383    if bytes.is_empty() {
384        warn.warn(WeirdStringTermination);
385        return bytes;
386    }
387    let end = bytes
388        .iter()
389        .position(|&b| b == 0)
390        .unwrap_or(bytes.len() - 1);
391    let (string, nuls) = bytes.split_at(end);
392    if !nuls.iter().all(|&b| b == 0) {
393        warn.warn(WeirdStringTermination);
394    }
395    string
396}
397
398pub fn string_to_bytes<'a, B: Buffer<'a>>(
399    buf: B,
400    string: &[u8],
401) -> Result<&'a [u8], CapacityError> {
402    with_buffer(buf, |buf| string_to_bytes_buffer_ref(buf, string))
403}
404
405fn string_to_bytes_buffer_ref<'d, 's>(
406    mut buf: BufferRef<'d, 's>,
407    string: &[u8],
408) -> Result<&'d [u8], CapacityError> {
409    assert!(string.iter().all(|&b| b != 0));
410    buf.write(string)?;
411    buf.write(&[0])?;
412    Ok(buf.initialized())
413}
414
415#[cfg(test)]
416#[rustfmt::skip]
417mod test {
418    use arrayvec::ArrayVec;
419    use quickcheck::quickcheck;
420    use std::i32;
421    use super::Unpacker;
422    use super::Warning::*;
423    use super::Warning;
424    use super::with_packer;
425    use warn::Ignore;
426    use warn::Panic;
427
428    fn assert_int_err(bytes: &[u8]) {
429        let mut unpacker = Unpacker::new(bytes);
430        unpacker.read_int(&mut Panic).unwrap_err();
431    }
432
433    fn assert_int_warnings(bytes: &[u8], int: i32, warnings: &[Warning]) {
434        let mut vec = vec![];
435        let mut unpacker = Unpacker::new(bytes);
436        assert_eq!(unpacker.read_int(&mut vec).unwrap(), int);
437        assert!(unpacker.as_slice().is_empty());
438        assert_eq!(vec, warnings);
439
440        let mut buf: ArrayVec<[u8; 5]> = ArrayVec::new();
441        let written = with_packer(&mut buf, |mut p| {
442            p.write_int(int).unwrap();
443            p.written()
444        });
445        if warnings.is_empty() {
446            assert_eq!(written, bytes);
447        } else {
448            assert!(written != bytes);
449        }
450    }
451
452    fn assert_int_warn(bytes: &[u8], int: i32, warning: Warning) {
453        assert_int_warnings(bytes, int, &[warning]);
454    }
455
456    fn assert_int(bytes: &[u8], int: i32) {
457        assert_int_warnings(bytes, int, &[]);
458    }
459
460    fn assert_str(bytes: &[u8], string: &[u8], remaining: &[u8]) {
461        let mut unpacker = Unpacker::new(bytes);
462        assert_eq!(unpacker.read_string().unwrap(), string);
463        assert_eq!(unpacker.as_slice(), remaining);
464
465        let mut buf = Vec::with_capacity(4096);
466        let written = with_packer(&mut buf, |mut p| {
467            p.write_string(string).unwrap();
468            p.write_rest(remaining).unwrap();
469            p.written()
470        });
471        assert_eq!(written, bytes);
472    }
473
474    fn assert_str_err(bytes: &[u8]) {
475        let mut unpacker = Unpacker::new(bytes);
476        unpacker.read_string().unwrap_err();
477    }
478
479    #[test] fn int_0() { assert_int(b"\x00", 0) }
480    #[test] fn int_1() { assert_int(b"\x01", 1) }
481    #[test] fn int_63() { assert_int(b"\x3f", 63) }
482    #[test] fn int_m1() { assert_int(b"\x40", -1) }
483    #[test] fn int_64() { assert_int(b"\x80\x01", 64) }
484    #[test] fn int_m65() { assert_int(b"\xc0\x01", -65) }
485    #[test] fn int_m64() { assert_int(b"\x7f", -64) }
486    #[test] fn int_min() { assert_int(b"\xff\xff\xff\xff\x0f", i32::min_value()) }
487    #[test] fn int_max() { assert_int(b"\xbf\xff\xff\xff\x0f", i32::max_value()) }
488    #[test] fn int_quirk1() { assert_int_warn(b"\xff\xff\xff\xff\xff", 0, NonZeroIntPadding) }
489    #[test] fn int_quirk2() { assert_int_warn(b"\xbf\xff\xff\xff\xff", -1, NonZeroIntPadding) }
490    #[test] fn int_empty() { assert_int_err(b"") }
491    #[test] fn int_extend_empty() { assert_int_err(b"\x80") }
492    #[test] fn int_overlong1() { assert_int_warn(b"\x80\x00", 0, OverlongIntEncoding) }
493    #[test] fn int_overlong2() { assert_int_warn(b"\xc0\x00", -1, OverlongIntEncoding) }
494
495    #[test] fn str_empty() { assert_str(b"\0", b"", b"") }
496    #[test] fn str_none() { assert_str_err(b"") }
497    #[test] fn str_no_nul() { assert_str_err(b"abc") }
498    #[test] fn str_rest1() { assert_str(b"abc\0def", b"abc", b"def") }
499    #[test] fn str_rest2() { assert_str(b"abc\0", b"abc", b"") }
500    #[test] fn str_rest3() { assert_str(b"abc\0\0", b"abc", b"\0") }
501    #[test] fn str_rest4() { assert_str(b"\0\0", b"", b"\0") }
502
503    #[test]
504    fn excess_data() {
505        let mut warnings = vec![];
506        let mut unpacker = Unpacker::new(b"\x00");
507        unpacker.finish(&mut warnings);
508        assert_eq!(warnings, [ExcessData]);
509    }
510
511    quickcheck! {
512        fn int_roundtrip(int: i32) -> bool {
513            let mut buf: ArrayVec<[u8; 5]> = ArrayVec::new();
514            let mut unpacker = Unpacker::new(with_packer(&mut buf, |mut p| {
515                p.write_int(int).unwrap();
516                p.written()
517            }));
518            let read_int = unpacker.read_int(&mut Panic).unwrap();
519            int == read_int && unpacker.as_slice().is_empty()
520        }
521
522        fn int_no_panic(data: Vec<u8>) -> bool {
523            let mut unpacker = Unpacker::new(&data);
524            let _ = unpacker.read_int(&mut Ignore);
525            true
526        }
527
528        fn string_no_panic(data: Vec<u8>) -> bool {
529            let mut unpacker = Unpacker::new(&data);
530            let _ = unpacker.read_string();
531            true
532        }
533    }
534}