mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'src/data/base64.rs')
| -rw-r--r-- | src/data/base64.rs | 578 |
1 files changed, 312 insertions, 266 deletions
diff --git a/src/data/base64.rs b/src/data/base64.rs index ccd27ff..895a362 100644 --- a/src/data/base64.rs +++ b/src/data/base64.rs @@ -4,293 +4,339 @@ use std::fmt; const CHARS: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; const PADDING: u8 = b'='; -fn decode_char(val: u8) -> Option<usize> -{ - match val - { - b'A'..=b'Z' => Some((val - b'A') as usize), - b'a'..=b'z' => Some(26 + (val - b'a') as usize), - b'0'..=b'9' => Some(52 + (val - b'0') as usize), - b'+' => Some(0x3E), - b'/' => Some(0x3F), - _ => None - } +fn decode_char(val: u8) -> Option<usize> { + match val { + b'A'..=b'Z' => Some((val - b'A') as usize), + b'a'..=b'z' => Some(26 + (val - b'a') as usize), + b'0'..=b'9' => Some(52 + (val - b'0') as usize), + b'+' => Some(0x3E), + b'/' => Some(0x3F), + _ => None, + } } -pub fn encode(input: &[u8], output: &mut [u8]) -> Result<usize, EncodeError> -{ - let use_pad = input.len() % 3 != 0; - let expect_len = if use_pad {4 * (input.len() / 3 + 1)} else {4 * (input.len() / 3)}; - if output.len() < expect_len - { - return Err(EncodeError::Overflow{need: expect_len, have: output.len()}); - } - let mut in_pos = 0usize; - let mut out_pos = 0usize; - while input.len() - in_pos >= 3 - { - let buff = ((input[in_pos] as usize) << 16) | ((input[in_pos + 1] as usize) << 8) | (input[in_pos + 2] as usize); - output[out_pos] = CHARS[buff >> 18]; - output[out_pos + 1] = CHARS[(buff >> 12) & 0x3F]; - output[out_pos + 2] = CHARS[(buff >> 6) & 0x3F]; - output[out_pos + 3] = CHARS[buff & 0x3F]; - out_pos += 4; - in_pos += 3; - } - let remain = input.len() - in_pos; - if remain > 0 - { - let mut buff = (input[in_pos] as usize) << 16; - if remain > 1 - { - buff |= (input[in_pos + 1] as usize) << 8; - } - in_pos += if remain > 1 {2} else {1}; - output[out_pos] = CHARS[buff >> 18]; - output[out_pos + 1] = CHARS[(buff >> 12) & 0x3F]; - if remain > 1 - { - output[out_pos + 2] = CHARS[(buff >> 6) & 0x3F]; - } - else {output[out_pos + 2] = PADDING;} - output[out_pos + 3] = PADDING; - out_pos += 4; - } - assert_eq!(in_pos, input.len(), "missed input ({in_pos}, expected {})", input.len()); - assert_eq!(out_pos, expect_len, "missed output ({out_pos}, expected {expect_len})"); - Ok(out_pos) +pub fn encode(input: &[u8], output: &mut [u8]) -> Result<usize, EncodeError> { + let use_pad = input.len() % 3 != 0; + let expect_len = if use_pad { + 4 * (input.len() / 3 + 1) + } else { + 4 * (input.len() / 3) + }; + if output.len() < expect_len { + return Err(EncodeError::Overflow { + need: expect_len, + have: output.len(), + }); + } + let mut in_pos = 0usize; + let mut out_pos = 0usize; + while input.len() - in_pos >= 3 { + let buff = ((input[in_pos] as usize) << 16) + | ((input[in_pos + 1] as usize) << 8) + | (input[in_pos + 2] as usize); + output[out_pos] = CHARS[buff >> 18]; + output[out_pos + 1] = CHARS[(buff >> 12) & 0x3F]; + output[out_pos + 2] = CHARS[(buff >> 6) & 0x3F]; + output[out_pos + 3] = CHARS[buff & 0x3F]; + out_pos += 4; + in_pos += 3; + } + let remain = input.len() - in_pos; + if remain > 0 { + let mut buff = (input[in_pos] as usize) << 16; + if remain > 1 { + buff |= (input[in_pos + 1] as usize) << 8; + } + in_pos += if remain > 1 { 2 } else { 1 }; + output[out_pos] = CHARS[buff >> 18]; + output[out_pos + 1] = CHARS[(buff >> 12) & 0x3F]; + if remain > 1 { + output[out_pos + 2] = CHARS[(buff >> 6) & 0x3F]; + } else { + output[out_pos + 2] = PADDING; + } + output[out_pos + 3] = PADDING; + out_pos += 4; + } + assert_eq!( + in_pos, + input.len(), + "missed input ({in_pos}, expected {})", + input.len() + ); + assert_eq!( + out_pos, expect_len, + "missed output ({out_pos}, expected {expect_len})" + ); + Ok(out_pos) } -macro_rules!do_decode -{ - ($input:ident, $in_pos:expr) => - { - match decode_char($input[$in_pos]) - { - None => return Err(DecodeError::Malformed{at: $in_pos, value: $input[$in_pos]}), - Some(v) => v, - } - }; +macro_rules! do_decode { + ($input:ident, $in_pos:expr) => { + match decode_char($input[$in_pos]) { + None => { + return Err(DecodeError::Malformed { + at: $in_pos, + value: $input[$in_pos], + }) + } + Some(v) => v, + } + }; } -pub fn decode(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> -{ - if input.len() % 4 != 0 - { - // can't decode, but check for malformed data first - let mut in_pad = false; - for (i, &c) in input.iter().enumerate() - { - if c == PADDING - { - if i % 4 < 2 - { - return Err(DecodeError::Malformed{at: i, value: c}); - } - in_pad = true; - } - else if in_pad && i % 4 == 0 - { - return Err(DecodeError::TrailingData{at: i}); - } - else if (in_pad && i % 4 == 3) || decode_char(c).is_none() - { - return Err(DecodeError::Malformed{at: i, value: c}); - } - } - return Err(DecodeError::Truncated); - } - let pad_len = if input.len() > 0 - { - if input[input.len() - 1] != PADDING {0} - else if input[input.len() - 2] != PADDING {1} - else {2} - } - else {0}; - let expect_len = input.len() / 4 * 3 - pad_len; - if output.len() < expect_len - { - return Err(DecodeError::Overflow{need: expect_len, have: output.len()}); - } - if !input.is_empty() - { - let mut in_pos = 0usize; - let mut out_pos = 0usize; - while in_pos < input.len() - 4 - { - let c0 = do_decode!(input, in_pos); - let c1 = do_decode!(input, in_pos + 1); - let c2 = do_decode!(input, in_pos + 2); - let c3 = do_decode!(input, in_pos + 3); - let buff = (c0 << 18) | (c1 << 12) | (c2 << 6) | c3; - output[out_pos] = (buff >> 16) as u8; - output[out_pos + 1] = (buff >> 8) as u8; - output[out_pos + 2] = buff as u8; - in_pos += 4; - out_pos += 3; - } - - let c0 = do_decode!(input, in_pos); - let c1 = do_decode!(input, in_pos + 1); - let mut buff = (c0 << 18) | (c1 << 12); - output[out_pos] = (buff >> 16) as u8; - out_pos += 1; - if input[in_pos + 2] == PADDING - { - if input[in_pos + 3] != PADDING - { - return Err(DecodeError::Malformed{at: in_pos + 3, value: input[in_pos + 3]}); - } - } - else - { - buff |= do_decode!(input, in_pos + 2) << 6; - output[out_pos] = (buff >> 8) as u8; - out_pos += 1; - if input[in_pos + 3] != PADDING - { - buff |= do_decode!(input, in_pos + 3); - output[out_pos] = buff as u8; - out_pos += 1; - } - } - in_pos += 4; - - assert_eq!(in_pos, input.len(), "missed input ({in_pos}, expected {})", input.len()); - assert_eq!(out_pos, expect_len, "missed output ({out_pos}, expected {expect_len})"); - Ok(out_pos) - } - else {Ok(0)} +pub fn decode(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> { + if input.len() % 4 != 0 { + // can't decode, but check for malformed data first + let mut in_pad = false; + for (i, &c) in input.iter().enumerate() { + if c == PADDING { + if i % 4 < 2 { + return Err(DecodeError::Malformed { at: i, value: c }); + } + in_pad = true; + } else if in_pad && i % 4 == 0 { + return Err(DecodeError::TrailingData { at: i }); + } else if (in_pad && i % 4 == 3) || decode_char(c).is_none() { + return Err(DecodeError::Malformed { at: i, value: c }); + } + } + return Err(DecodeError::Truncated); + } + let pad_len = if input.len() > 0 { + if input[input.len() - 1] != PADDING { + 0 + } else if input[input.len() - 2] != PADDING { + 1 + } else { + 2 + } + } else { + 0 + }; + let expect_len = input.len() / 4 * 3 - pad_len; + if output.len() < expect_len { + return Err(DecodeError::Overflow { + need: expect_len, + have: output.len(), + }); + } + if !input.is_empty() { + let mut in_pos = 0usize; + let mut out_pos = 0usize; + while in_pos < input.len() - 4 { + let c0 = do_decode!(input, in_pos); + let c1 = do_decode!(input, in_pos + 1); + let c2 = do_decode!(input, in_pos + 2); + let c3 = do_decode!(input, in_pos + 3); + let buff = (c0 << 18) | (c1 << 12) | (c2 << 6) | c3; + output[out_pos] = (buff >> 16) as u8; + output[out_pos + 1] = (buff >> 8) as u8; + output[out_pos + 2] = buff as u8; + in_pos += 4; + out_pos += 3; + } + + let c0 = do_decode!(input, in_pos); + let c1 = do_decode!(input, in_pos + 1); + let mut buff = (c0 << 18) | (c1 << 12); + output[out_pos] = (buff >> 16) as u8; + out_pos += 1; + if input[in_pos + 2] == PADDING { + if input[in_pos + 3] != PADDING { + return Err(DecodeError::Malformed { + at: in_pos + 3, + value: input[in_pos + 3], + }); + } + } else { + buff |= do_decode!(input, in_pos + 2) << 6; + output[out_pos] = (buff >> 8) as u8; + out_pos += 1; + if input[in_pos + 3] != PADDING { + buff |= do_decode!(input, in_pos + 3); + output[out_pos] = buff as u8; + out_pos += 1; + } + } + in_pos += 4; + + assert_eq!( + in_pos, + input.len(), + "missed input ({in_pos}, expected {})", + input.len() + ); + assert_eq!( + out_pos, expect_len, + "missed output ({out_pos}, expected {expect_len})" + ); + Ok(out_pos) + } else { + Ok(0) + } } #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum DecodeError -{ - Malformed{at: usize, value: u8}, - Overflow{need: usize, have: usize}, - Truncated, - TrailingData{at: usize}, +pub enum DecodeError { + Malformed { at: usize, value: u8 }, + Overflow { need: usize, have: usize }, + Truncated, + TrailingData { at: usize }, } -impl fmt::Display for DecodeError -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result - { - match self - { - Self::Malformed{at, value} => write!(f, "malformed base64 character {value:?} (at {at})"), - Self::Overflow{need, have} => write!(f, "decoder overflow (need {need}, but only have {have})"), - Self::Truncated => f.write_str("truncated base64 input stream"), - Self::TrailingData{at} => write!(f, "trailing data in base64 stream (at {at})"), - } - } +impl fmt::Display for DecodeError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Malformed { at, value } => { + write!(f, "malformed base64 character {value:?} (at {at})") + } + Self::Overflow { need, have } => { + write!(f, "decoder overflow (need {need}, but only have {have})") + } + Self::Truncated => f.write_str("truncated base64 input stream"), + Self::TrailingData { at } => write!(f, "trailing data in base64 stream (at {at})"), + } + } } impl Error for DecodeError {} #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum EncodeError -{ - Overflow{need: usize, have: usize} +pub enum EncodeError { + Overflow { need: usize, have: usize }, } -impl fmt::Display for EncodeError -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result - { - match self - { - Self::Overflow{need, have} => write!(f, "encoder overflow (need {need}, but only have {have})"), - } - } +impl fmt::Display for EncodeError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Overflow { need, have } => { + write!(f, "encoder overflow (need {need}, but only have {have})") + } + } + } } impl Error for EncodeError {} #[cfg(test)] -mod test -{ - use super::*; - - #[test] - fn validate_chars() - { - for (i, &c0) in CHARS.iter().enumerate() - { - assert_ne!(c0, PADDING, "padding character in data charset at {i}"); - if i > 0 - { - for (j, &c1) in CHARS[..i].iter().enumerate() - { - assert_ne!(c1, c0, "duplicate data character at {j} and {i}") - } - } - } - } - - #[test] - fn decode_matches_chars() - { - for (i, &c0) in CHARS.iter().enumerate() - { - assert_eq!(decode_char(c0), Some(i), "data character {c0} (at {i}) isn't decoded properly"); - } - } - - macro_rules!test_codec - { - ($func:ident, $input:expr => $expect:expr) => - { - { - const EMPTY: u8 = 0xC9u8; // arbitrary - let mut output = [EMPTY; 64]; - let input = $input; - let expect = $expect; - assert_eq!($func(input, &mut output), Ok(expect.len())); - assert_eq!(&output[..expect.len()], expect); - assert!(output[expect.len()..].iter().all(|&x| x == EMPTY), "output buffer overflow"); - } - }; - } - - #[test] - fn encoder_success() - { - test_codec!(encode, b"Hello Wor" => b"SGVsbG8gV29y"); - test_codec!(encode, b"Hello Worl" => b"SGVsbG8gV29ybA=="); - test_codec!(encode, b"Hello World" => b"SGVsbG8gV29ybGQ="); - test_codec!(encode, b"Hello World!" => b"SGVsbG8gV29ybGQh"); - } - - #[test] - fn decoder_success() - { - test_codec!(decode, b"SGVsbG8gV29y" => b"Hello Wor"); - test_codec!(decode, b"SGVsbG8gV29ybA==" => b"Hello Worl"); - test_codec!(decode, b"SGVsbG8gV29ybGQ=" => b"Hello World"); - test_codec!(decode, b"SGVsbG8gV29ybGQh" => b"Hello World!"); - } - - #[test] - fn encoder_fail() - { - let mut output = [0u8; 64]; - assert_eq!(encode(b"Hello Worl", &mut output[..15]), Err(EncodeError::Overflow{need: 16, have: 15})); - assert_eq!(encode(b"Hello World!", &mut output[..0]), Err(EncodeError::Overflow{need: 16, have: 0})); - } - - #[test] - fn decoder_fail() - { - let mut output = [0u8; 64]; - assert_eq!(decode(b"SGVsbG8gV29ybA==", &mut output[..9]), Err(DecodeError::Overflow{need: 10, have: 9})); - assert_eq!(decode(b"SGVsbG8gV29ybGQh", &mut output[..11]), Err(DecodeError::Overflow{need: 12, have: 11})); - assert_eq!(decode(b"SGVsbG8gV29ybA", &mut output), Err(DecodeError::Truncated)); - assert_eq!(decode(b"SGVsbG8gV29yb", &mut output), Err(DecodeError::Truncated)); - assert_eq!(decode(b"SGVsbG8gV29y\n", &mut output), Err(DecodeError::Malformed{at: 12, value: b'\n'})); - assert_eq!(decode(b"SGVs_bG8gV29y\n", &mut output), Err(DecodeError::Malformed{at: 4, value: b'_'})); - assert_eq!(decode(b"SGVsbG8gV29ybA==*", &mut output), Err(DecodeError::TrailingData{at: 16})); - assert_eq!(decode(b"SGVsbG8gV29ybA=*", &mut output), Err(DecodeError::Malformed{at: 15, value: b'*'})); - assert_eq!(decode(b"SGVsbG8gV29ybA=A", &mut output), Err(DecodeError::Malformed{at: 15, value: b'A'})); - } +mod test { + use super::*; + + #[test] + fn validate_chars() { + for (i, &c0) in CHARS.iter().enumerate() { + assert_ne!(c0, PADDING, "padding character in data charset at {i}"); + if i > 0 { + for (j, &c1) in CHARS[..i].iter().enumerate() { + assert_ne!(c1, c0, "duplicate data character at {j} and {i}") + } + } + } + } + + #[test] + fn decode_matches_chars() { + for (i, &c0) in CHARS.iter().enumerate() { + assert_eq!( + decode_char(c0), + Some(i), + "data character {c0} (at {i}) isn't decoded properly" + ); + } + } + + macro_rules! test_codec { + ($func:ident, $input:expr => $expect:expr) => {{ + const EMPTY: u8 = 0xC9u8; // arbitrary + let mut output = [EMPTY; 64]; + let input = $input; + let expect = $expect; + assert_eq!($func(input, &mut output), Ok(expect.len())); + assert_eq!(&output[..expect.len()], expect); + assert!( + output[expect.len()..].iter().all(|&x| x == EMPTY), + "output buffer overflow" + ); + }}; + } + + #[test] + fn encoder_success() { + test_codec!(encode, b"Hello Wor" => b"SGVsbG8gV29y"); + test_codec!(encode, b"Hello Worl" => b"SGVsbG8gV29ybA=="); + test_codec!(encode, b"Hello World" => b"SGVsbG8gV29ybGQ="); + test_codec!(encode, b"Hello World!" => b"SGVsbG8gV29ybGQh"); + } + + #[test] + fn decoder_success() { + test_codec!(decode, b"SGVsbG8gV29y" => b"Hello Wor"); + test_codec!(decode, b"SGVsbG8gV29ybA==" => b"Hello Worl"); + test_codec!(decode, b"SGVsbG8gV29ybGQ=" => b"Hello World"); + test_codec!(decode, b"SGVsbG8gV29ybGQh" => b"Hello World!"); + } + + #[test] + fn encoder_fail() { + let mut output = [0u8; 64]; + assert_eq!( + encode(b"Hello Worl", &mut output[..15]), + Err(EncodeError::Overflow { need: 16, have: 15 }) + ); + assert_eq!( + encode(b"Hello World!", &mut output[..0]), + Err(EncodeError::Overflow { need: 16, have: 0 }) + ); + } + + #[test] + fn decoder_fail() { + let mut output = [0u8; 64]; + assert_eq!( + decode(b"SGVsbG8gV29ybA==", &mut output[..9]), + Err(DecodeError::Overflow { need: 10, have: 9 }) + ); + assert_eq!( + decode(b"SGVsbG8gV29ybGQh", &mut output[..11]), + Err(DecodeError::Overflow { need: 12, have: 11 }) + ); + assert_eq!( + decode(b"SGVsbG8gV29ybA", &mut output), + Err(DecodeError::Truncated) + ); + assert_eq!( + decode(b"SGVsbG8gV29yb", &mut output), + Err(DecodeError::Truncated) + ); + assert_eq!( + decode(b"SGVsbG8gV29y\n", &mut output), + Err(DecodeError::Malformed { + at: 12, + value: b'\n' + }) + ); + assert_eq!( + decode(b"SGVs_bG8gV29y\n", &mut output), + Err(DecodeError::Malformed { at: 4, value: b'_' }) + ); + assert_eq!( + decode(b"SGVsbG8gV29ybA==*", &mut output), + Err(DecodeError::TrailingData { at: 16 }) + ); + assert_eq!( + decode(b"SGVsbG8gV29ybA=*", &mut output), + Err(DecodeError::Malformed { + at: 15, + value: b'*' + }) + ); + assert_eq!( + decode(b"SGVsbG8gV29ybA=A", &mut output), + Err(DecodeError::Malformed { + at: 15, + value: b'A' + }) + ); + } } |