aboutsummaryrefslogtreecommitdiff
path: root/src/primitive/string.rs
diff options
context:
space:
mode:
authorMax Audron <audron@cocaine.farm>2020-04-29 00:00:44 +0200
committerMax Audron <audron@cocaine.farm>2020-04-29 00:00:44 +0200
commitfc64e11cdd35051a2ea87237f548ae0497a2f7f9 (patch)
treec57937731898b0ffd66d1d95bb0f181cae568c37 /src/primitive/string.rs
parentfinish parsing of primitive types (diff)
refactor everything
Diffstat (limited to 'src/primitive/string.rs')
-rw-r--r--src/primitive/string.rs94
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));
+ }
+}