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}