diff --git a/Cargo.toml b/Cargo.toml index 556ede8..0d0123d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ byteorder = "1.4" bzip2-rs = "0.1" crc32fast = "1.3" serde_json = "1.0" +encoding = "0.2" serde = { version = "1.0", optional = true } diff --git a/src/buffer.rs b/src/buffer.rs index 420be8b..38c2502 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -4,6 +4,8 @@ use crate::GDResult; use byteorder::{BigEndian, ByteOrder, LittleEndian}; use std::{convert::TryInto, marker::PhantomData}; +use encoding::{DecoderTrap, Encoding}; + /// A struct representing a buffer with a specific byte order. /// /// It's comprised of a byte slice that it reads from, a cursor to keep track of @@ -320,6 +322,36 @@ pub trait StringDecoder { fn decode_string(data: &[u8], cursor: &mut usize, delimiter: Self::Delimiter) -> GDResult; } +pub struct Latin1Decoder; + +impl StringDecoder for Latin1Decoder { + type Delimiter = [u8; 1]; + + const DELIMITER: Self::Delimiter = [0x00]; + + fn decode_string(data: &[u8], cursor: &mut usize, delimiter: Self::Delimiter) -> GDResult { + // Find the position of the delimiter in the data. If the delimiter is not + // found, the length of the data is returned. + let position = data + // Create an iterator over the data. + .iter() + // Find the position of the delimiter + .position(|&b| b == delimiter.as_ref()[0]) + // If the delimiter is not found, use the whole data slice. + .unwrap_or(data.len()); + + let result = encoding::all::ISO_8859_1 + .decode(&data[.. position], DecoderTrap::Strict) + .map_err(|e| PacketBad.context(e))?; + + // Update the cursor position + // The +1 is to skip the delimiter + *cursor += position + 1; + + Ok(result) + } +} + /// A decoder for UTF-8 encoded strings. /// /// This decoder uses a single null byte (`0x00`) as the default delimiter. diff --git a/src/protocols/gamespy/protocols/one/protocol.rs b/src/protocols/gamespy/protocols/one/protocol.rs index cc0c67f..bddf85c 100644 --- a/src/protocols/gamespy/protocols/one/protocol.rs +++ b/src/protocols/gamespy/protocols/one/protocol.rs @@ -1,6 +1,6 @@ use byteorder::LittleEndian; -use crate::buffer::Utf8Decoder; +use crate::buffer::Latin1Decoder; use crate::protocols::gamespy::common::has_password; use crate::GDErrorKind::TypeParse; @@ -46,7 +46,7 @@ fn get_server_values_impl(socket: &mut UdpSocket) -> GDResult::new(&data); - let mut as_string = bufferer.read_string::(None)?; + let mut as_string = bufferer.read_string::(None)?; as_string.remove(0); let splited: Vec = as_string.split('\\').map(str::to_string).collect();