diff options
| author | Max Audron <audron@cocaine.farm> | 2020-04-29 00:00:44 +0200 |
|---|---|---|
| committer | Max Audron <audron@cocaine.farm> | 2020-04-29 00:00:44 +0200 |
| commit | fc64e11cdd35051a2ea87237f548ae0497a2f7f9 (patch) | |
| tree | c57937731898b0ffd66d1d95bb0f181cae568c37 /src/primitive/string.rs | |
| parent | finish parsing of primitive types (diff) | |
refactor everything
Diffstat (limited to 'src/primitive/string.rs')
| -rw-r--r-- | src/primitive/string.rs | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/src/primitive/string.rs b/src/primitive/string.rs new file mode 100644 index 0000000..86bcdec --- /dev/null +++ b/src/primitive/string.rs @@ -0,0 +1,94 @@ +extern crate byteorder; + +use std::result::Result; +use std::vec::Vec; + +use failure::Error; + +use log::trace; + +use crate::{Deserialize, DeserializeUTF8, Serialize, SerializeUTF8}; +use crate::util; + +/// We Shadow the String type here as we can only use impl on types in our own scope. +/// +/// Strings are serialized as an i32 for the length in bytes, then the chars represented in UTF-16 in bytes. +/// +/// Strings can only be serialized as UTF-8 null-terminated ByteArrays with (de)serialize_utf8(). +impl Serialize for String { + fn serialize(&self) -> Result<Vec<u8>, Error> { + let mut res: Vec<u8> = Vec::new(); + + let utf16: Vec<u16> = self.encode_utf16().collect(); + for i in utf16 { + res.extend(i.to_be_bytes().iter()); + } + + util::prepend_byte_len(&mut res); + return Ok(res); + } +} + +impl SerializeUTF8 for String { + fn serialize_utf8(&self) -> Result<Vec<u8>, Error> { + let mut res: Vec<u8> = Vec::new(); + res.extend(self.clone().into_bytes()); + res.extend(vec![0x00]); + util::prepend_byte_len(&mut res); + return Ok(res); + } +} + +impl Deserialize for String { + fn parse(b: &[u8]) -> Result<(usize, Self), Error> { + // Parse Length + let (_, len) = i32::parse(&b[0..4])?; + trace!(target: "primitive::String", "Parsing with length: {:?}, from bytes: {:x?}", len, &b[0..4]); + + if len == -1 { + return Ok((4, "".to_string())); + } + + // length as usize + let ulen = len as usize; + let mut pos: usize = 4; + let mut chars: Vec<u16> = Vec::new(); + loop { + // if position is behind the length plus our 4 bytes of the length we already parsed + if pos >= (ulen + 4) { + break; + } + let (slen, uchar) = u16::parse(&b[pos..(pos + 2)])?; + chars.push(uchar); + pos += slen; + } + + let res: String = String::from_utf16(&chars).unwrap(); + return Ok((pos, res)); + } +} + +impl DeserializeUTF8 for String { + fn parse_utf8(b: &[u8]) -> Result<(usize, Self), Error> { + let (_, len) = i32::parse(&b[0..4])?; + + trace!(target: "primitive::String", "Parsing with length: {:?}, from bytes: {:x?}", len, &b[0..4]); + + if len <= 0 { + return Ok((4, "".to_string())); + } + + let ulen = len as usize; + + let mut res: String = String::from_utf8(b[4..(ulen + 4)].to_vec())?; + + // If the last byte is zero remove it + // Receiving a string as bytearray will sometimes have + // the string null terminated + if res.chars().last().unwrap() == '\u{0}' { + let _ = res.pop(); + } + + return Ok((ulen + 4, res)); + } +} |
