use std::io::{Cursor, Read}; use crate::framework::error::GameError::ParseError; use crate::framework::error::GameResult; use crate::game::scripting::tsc::text_script::TextScriptEncoding; pub fn put_varint(val: i32, out: &mut Vec) { let mut x = ((val as u32) >> 31) ^ ((val as u32) << 1); loop { let mut n = (x & 0x7f) as u8; x >>= 7; if x != 0 { n |= 0x80; } out.push(n); if x == 0 { break; } } } pub fn read_cur_varint(cursor: &mut Cursor<&[u8]>) -> GameResult { let mut result = 0u32; for o in 0..5 { let mut n = [0u8]; cursor.read_exact(&mut n)?; let [n] = n; result |= (n as u32 & 0x7f) << (o * 7); if n & 0x80 == 0 { break; } } Ok(((result << 31) ^ (result >> 1)) as i32) } #[allow(unused)] pub fn read_varint>(iter: &mut I) -> GameResult { let mut result = 0u32; for o in 0..5 { let n = iter.next().ok_or_else(|| ParseError("Script unexpectedly ended.".to_owned()))?; result |= (n as u32 & 0x7f) << (o * 7); if n & 0x80 == 0 { break; } } Ok(((result << 31) ^ (result >> 1)) as i32) } pub fn put_string(buffer: &mut Vec, out: &mut Vec, encoding: TextScriptEncoding) { if buffer.is_empty() { return; } let mut chars_count = 0; let mut tmp_buf = Vec::new(); let encoding = match encoding { TextScriptEncoding::UTF8 => encoding_rs::UTF_8, TextScriptEncoding::ShiftJIS => encoding_rs::SHIFT_JIS, TextScriptEncoding::GBK => encoding_rs::GBK, }; let decoded_text = encoding.decode_without_bom_handling(&buffer).0; for chr in decoded_text.chars() { chars_count += 1; put_varint(chr as _, &mut tmp_buf); } buffer.clear(); put_varint(chars_count, out); out.append(&mut tmp_buf); } #[test] fn test_varint() { for n in -4000..=4000 { let mut out = Vec::new(); put_varint(n, &mut out); let result = read_varint(&mut out.iter().copied()).unwrap(); assert_eq!(result, n); let mut cur: Cursor<&[u8]> = Cursor::new(&out); let result = read_cur_varint(&mut cur).unwrap(); assert_eq!(result, n); } }