rw_utils/
string_write.rs

1use std::io;
2use std::io::{Error, ErrorKind, Write};
3use std::mem::size_of;
4use encoding::{Encoding, EncoderTrap};
5use encoding::all::{UTF_16BE, UTF_16LE};
6
7///
8/// Trait that provides various methods to write strings.
9/// Automatically implemented for all implementations of io::Write.
10/// This trait is sealed and cannot be implemented manually.
11///
12pub trait StringWrite : private::Sealed {
13
14    ///
15    /// Writes an u16 little endian length prefix followed by an utf-8 representation of the string
16    /// Returns the total amount of bytes written
17    ///
18    fn write_string_u16_le_len_utf8(&mut self, string: &str) -> io::Result<usize>;
19
20    ///
21    /// Writes an u16 big endian length prefix followed by an utf-8 representation of the string
22    /// Returns the total amount of bytes written
23    ///
24    fn write_string_u16_be_len_utf8(&mut self, string: &str) -> io::Result<usize>;
25
26    ///
27    /// Writes an u32 little endian length prefix followed by an utf-8 representation of the string
28    /// Returns the total amount of bytes written
29    ///
30    fn write_string_u32_le_len_utf8(&mut self, string: &str) -> io::Result<usize>;
31
32    ///
33    /// Writes an u32 big endian length prefix followed by an utf-8 representation of the string
34    /// Returns the total amount of bytes written
35    ///
36    fn write_string_u32_be_len_utf8(&mut self, string: &str) -> io::Result<usize>;
37
38    ///
39    /// Writes an utf-8 representation of the string and a zero byte.
40    /// If the string ends with a null char then no zero byte is appended.
41    /// If the string contains a null char in the middle then the method fails.
42    /// Returns the total amount of bytes written
43    ///
44    fn write_string_zero_terminated_utf8(&mut self, string: &str) -> io::Result<usize>;
45
46    ///
47    /// Writes an utf-8 representation of the string
48    /// Returns the total amount of bytes written
49    ///
50    fn write_string_utf8(&mut self, string: &str) -> io::Result<usize>;
51
52    ///
53    /// Writes an utf-16-be representation of the string
54    /// Returns the total amount of bytes written
55    ///
56    fn write_string_utf16_be(&mut self, string: &str) -> io::Result<usize>;
57
58    ///
59    /// Writes an utf-16-le representation of the string
60    /// Returns the total amount of bytes written
61    ///
62    fn write_string_utf16_le(&mut self, string: &str) -> io::Result<usize>;
63
64    ///
65    /// Writes an utf-32-be representation of the string
66    /// Returns the total amount of bytes written
67    ///
68    fn write_string_utf32_be(&mut self, string: &str) -> io::Result<usize>;
69
70    ///
71    /// Writes an utf-32-le representation of the string
72    /// Returns the total amount of bytes written
73    ///
74    fn write_string_utf32_le(&mut self, string: &str) -> io::Result<usize>;
75
76    ///
77    /// Writes a string that can be read by a java program using the java.io.DataInput#readUTF facility.
78    /// In general, it writes a big endian u16 to indicate how many bytes it will write.
79    /// Each character is a re-encoded utf-16 representation of the string.
80    /// 1. The string is utf-16 encoded
81    /// 2. Each u16 of the utf-16 is encoded as 1,2 or 3 bytes using a custom java specific encoding.
82    /// Returns the total amount of bytes written
83    ///
84    fn write_java_data_output_utf(&mut self, string: &str) -> io::Result<usize>;
85}
86
87
88const ZERO: [u8; 1] = [0u8];
89impl <T> StringWrite for T where T: Write {
90    fn write_string_u16_le_len_utf8(&mut self, string: &str) -> io::Result<usize> {
91        let x = string.as_bytes();
92        let len_u16 = x.len() as u16;
93        if x.len() != len_u16 as usize {
94            return Err(Error::new(ErrorKind::Other, "string too long"));
95        }
96
97        self.write_all(len_u16.to_le_bytes().as_slice())?;
98        self.write_all(x)?;
99        return Ok(x.len()+2);
100    }
101
102    fn write_string_u16_be_len_utf8(&mut self, string: &str) -> io::Result<usize> {
103        let x = string.as_bytes();
104        let len_u16 = x.len() as u16;
105        if x.len() != len_u16 as usize {
106            return Err(Error::new(ErrorKind::Other, "string too long"));
107        }
108
109        self.write_all(len_u16.to_be_bytes().as_slice())?;
110        self.write_all(x)?;
111        return Ok(x.len()+2);
112    }
113
114    fn write_string_u32_le_len_utf8(&mut self, string: &str) -> io::Result<usize> {
115        let x = string.as_bytes();
116        self.write_all((x.len() as u32).to_le_bytes().as_slice())?;
117        self.write_all(x)?;
118        return Ok(x.len()+4);
119    }
120
121    fn write_string_u32_be_len_utf8(&mut self, string: &str) -> io::Result<usize> {
122        let x = string.as_bytes();
123        self.write_all((x.len() as u32).to_be_bytes().as_slice())?;
124        self.write_all(x)?;
125        return Ok(x.len()+4);
126    }
127
128    fn write_string_zero_terminated_utf8(&mut self, string: &str) -> io::Result<usize> {
129        let x = string.as_bytes();
130        if x.len() == 0 {
131            return Ok(0);
132        }
133
134        for i in 0 .. x.len()-1 {
135            if x[i] == 0 {
136                return Err(Error::new(ErrorKind::InvalidInput, "Null byte found in string"));
137            }
138        }
139
140        if x[x.len()-1] == 0 {
141            self.write_all(x)?;
142            return Ok(x.len());
143        }
144
145        self.write_all(x)?;
146        self.write_all(&ZERO)?;
147        return Ok(x.len()+1);
148    }
149
150    fn write_string_utf8(&mut self, string: &str) -> io::Result<usize> {
151        let x = string.as_bytes();
152        self.write_all(x)?;
153        return Ok(x.len());
154    }
155
156    fn write_string_utf16_be(&mut self, string: &str) -> io::Result<usize> {
157        let encoded = UTF_16BE.encode(string, EncoderTrap::Strict)
158            .map_err(|e| Error::new(ErrorKind::Other, e.as_ref()))?;
159        self.write_all(encoded.as_slice())?;
160        return Ok(encoded.len());
161    }
162
163    fn write_string_utf16_le(&mut self, string: &str) -> io::Result<usize> {
164        let encoded = UTF_16LE.encode(string, EncoderTrap::Strict)
165            .map_err(|e| Error::new(ErrorKind::Other, e.as_ref()))?;
166        self.write_all(encoded.as_slice())?;
167        return Ok(encoded.len());
168    }
169
170    #[cfg(target_endian = "big")]
171    fn write_string_utf32_be(&mut self, string: &str) -> io::Result<usize> {
172        let mut data: Vec<char> = string.chars().collect();
173        let sl : &mut [u8] = unsafe { std::slice::from_raw_parts_mut(data.as_mut_ptr().cast(), data.len() * size_of::<char>()) };
174        self.write_all(sl)?;
175        return Ok(sl.len());
176    }
177
178    #[cfg(target_endian = "big")]
179    fn write_string_utf32_le(&mut self, string: &str) -> io::Result<usize> {
180        let mut data: Vec<u32> = string.chars().map(|c| c as u32).collect();
181        for i in 0 .. data.len() {
182            data[i] = data[i].to_le();
183        }
184
185        let sl : &mut [u8] = unsafe { std::slice::from_raw_parts_mut(data.as_mut_ptr().cast(), data.len() * size_of::<u32>()) };
186        self.write_all(sl)?;
187        return Ok(sl.len());
188    }
189
190    #[cfg(target_endian = "little")]
191    fn write_string_utf32_be(&mut self, string: &str) -> io::Result<usize> {
192        let mut data: Vec<u32> = string.chars().map(|c| c as u32).collect();
193        for i in 0 .. data.len() {
194            data[i] = data[i].to_be();
195        }
196
197        let sl : &mut [u8] = unsafe { std::slice::from_raw_parts_mut(data.as_mut_ptr().cast(), data.len() * size_of::<u32>()) };
198        self.write_all(sl)?;
199        return Ok(sl.len());
200    }
201
202    #[cfg(target_endian = "little")]
203    fn write_string_utf32_le(&mut self, string: &str) -> io::Result<usize> {
204        let mut data: Vec<char> = string.chars().collect();
205        let sl : &mut [u8] = unsafe { std::slice::from_raw_parts_mut(data.as_mut_ptr().cast(), data.len() * size_of::<char>()) };
206        self.write_all(sl)?;
207        return Ok(sl.len());
208    }
209
210    fn write_java_data_output_utf(&mut self, string: &str) -> io::Result<usize> {
211        let encoded = UTF_16LE.encode(string, EncoderTrap::Strict)
212            .map_err(|e| Error::new(ErrorKind::Other, e.as_ref()))?;
213
214        if encoded.len() & 1 != 0 {
215            panic!("UTF-16 encoder failed and gave a odd number of bytes as output without reporting an error!");
216        }
217
218        let sl : &[u16] = unsafe { std::slice::from_raw_parts(encoded.as_ptr().cast(), encoded.len() >> 1) };
219        let mut count : usize = 0;
220        for c_le in sl {
221            let c = c_le.to_le();
222            if c < 0x80 && c != 0 {
223                count+=1;
224                continue;
225            }
226            if c >= 0x800 {
227                count+=3;
228                continue;
229            }
230            count+=2;
231        }
232
233        if count > 65535 {
234            return Err(Error::new(ErrorKind::Other, "String length exceeds maximum allowed value"));
235        }
236
237        let mut data : Vec<u8> = vec![0u8; count+2];
238        let mut index = 2usize;
239        //This is always big endian in java.
240        data[0] = ((count >> 8)& 0xFFusize) as u8;
241        data[1] = ((count >> 0)& 0xFFusize) as u8;
242
243        for c_le in sl {
244            let c = c_le.to_le();
245            if c < 0x80 && c != 0 {
246                data[index] = c as u8;
247                index+=1;
248                continue;
249            }
250
251            if c >= 0x800 {
252                data[index] = (0xE0 | ((c >> 12) & 0x0F)) as u8;
253                data[index+1] = (0x80 | ((c >>  6) & 0x3F)) as u8;
254                data[index+2] = (0x80 | ((c >>  0) & 0x3F)) as u8;
255                index+=3;
256                continue;
257            }
258
259            data[index] = (0xC0 | ((c >>  6) & 0x1F)) as u8;
260            data[index+1] = (0x80 | ((c >>  0) & 0x3F)) as u8;
261            index+=2;
262        }
263
264        self.write_all(data.as_slice())?;
265        return Ok(data.len());
266    }
267}
268
269mod private {
270    use std::io::Write;
271
272    impl <T> Sealed for T where T: Write {}
273    pub trait Sealed {
274
275    }
276}