rwutil/
bytes0.rs

1//! Read and write 0-terminated byte strings.
2//!
3//! Example:
4//!
5//! ```
6//! use rwutil::bytes0::ReadBytes0Ext;
7//!
8//! // a &[u8] implements the io::Read interface
9//! let src: Vec<u8> = vec![0x61, 0x62, 0x63, 0];
10//!
11//! // reading data into a new vector
12//! let buf: Vec<u8> = src.as_slice().read_bytes0().unwrap();
13//!
14//! assert_eq!(buf, b"abc")
15//! ```
16//!
17//! # Security
18//! The current implementation is similar to the trouble `gets` from C in that
19//! it does not have a maximum size for reading. While you will not encounter
20//! a buffer overflow, the vector the string is read into can grow arbitrarily
21//! large, allow a supplier of untrusted data to cause an OOM panic if allowed
22//! to send an infinite amount of data.
23
24use std::io;
25use std::io::{Read, Write};
26
27pub trait ReadBytes0Ext : Read {
28    fn read_bytes0(&mut self) -> io::Result<Vec<u8>> {
29        let it = self.bytes();
30
31        let result: Result<Vec<u8>,_> =
32            it.take_while(|b| match *b {
33                Ok(b) => b != 0,
34                _ => true
35            }).collect();
36
37        Ok(try!(result))
38    }
39}
40
41pub trait WriteBytes0Ext : Write {
42    fn write_bytes0(&mut self, data: &[u8]) -> io::Result<()> {
43        try!(self.write_all(data));
44        try!(self.write_all(&[0; 1]));
45        Ok(())
46    }
47}
48
49impl<R: Read> ReadBytes0Ext for R {
50}
51
52impl<W: Write> WriteBytes0Ext for W {
53}
54
55#[cfg(test)]
56mod test {
57    use bytes0::{ReadBytes0Ext, WriteBytes0Ext};
58
59    #[test]
60    fn test_bytes0() {
61        let buf = vec![0x61, 0x62, 0x63, 0];
62        assert_eq!(buf.as_slice().read_bytes0().unwrap(), b"abc");
63
64        let mut out = Vec::new();
65        out.write_bytes0(b"abc").unwrap();
66        assert_eq!(buf, out);
67    }
68}