use crate::error::{encoding_error, CtpResult};
use encoding::all::GB18030;
use encoding::{DecoderTrap, EncoderTrap, Encoding};
use std::ffi::{CStr, CString};
pub struct GbkConverter;
impl GbkConverter {
pub fn gb18030_to_utf8(bytes: &[u8]) -> CtpResult<String> {
let trimmed_bytes = Self::trim_null_bytes(bytes);
if trimmed_bytes.is_empty() {
return Ok(String::new());
}
GB18030
.decode(trimmed_bytes, DecoderTrap::Replace)
.map_err(|e| encoding_error(&format!("GB18030解码失败: {}", e)))
}
pub fn utf8_to_gb18030(utf8_str: &str) -> CtpResult<Vec<u8>> {
GB18030
.encode(utf8_str, EncoderTrap::Replace)
.map_err(|e| encoding_error(&format!("UTF-8编码失败: {}", e)))
}
pub fn utf8_to_gb18030_cstring(utf8_str: &str) -> CtpResult<CString> {
let gb_bytes = Self::utf8_to_gb18030(utf8_str)?;
CString::new(gb_bytes).map_err(|e| encoding_error(&format!("创建CString失败: {}", e)))
}
pub unsafe fn cstring_to_utf8(ptr: *const i8) -> CtpResult<String> {
if ptr.is_null() {
return Ok(String::new());
}
let c_str = CStr::from_ptr(ptr);
let bytes = c_str.to_bytes();
Self::gb18030_to_utf8(bytes)
}
fn trim_null_bytes(bytes: &[u8]) -> &[u8] {
bytes
.iter()
.rposition(|&b| b != 0)
.map_or(&[], |pos| &bytes[..=pos])
}
pub fn fixed_bytes_to_utf8<const N: usize>(bytes: &[u8; N]) -> CtpResult<String> {
Self::gb18030_to_utf8(bytes)
}
pub fn utf8_to_fixed_bytes<const N: usize>(utf8_str: &str) -> CtpResult<[u8; N]> {
let gb_bytes = Self::utf8_to_gb18030(utf8_str)?;
let mut result = [0u8; N];
if gb_bytes.len() >= N {
result.copy_from_slice(&gb_bytes[..N]);
} else {
result[..gb_bytes.len()].copy_from_slice(&gb_bytes);
}
Ok(result)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_utf8_to_gb18030_and_back() {
let original = "测试字符串";
let gb_bytes = GbkConverter::utf8_to_gb18030(original).unwrap();
let converted = GbkConverter::gb18030_to_utf8(&gb_bytes).unwrap();
assert_eq!(original, converted);
}
#[test]
fn test_empty_string() {
let result = GbkConverter::gb18030_to_utf8(&[]).unwrap();
assert_eq!(result, "");
}
#[test]
fn test_null_terminated_bytes() {
let bytes = b"test\0\0\0";
let result = GbkConverter::gb18030_to_utf8(bytes).unwrap();
assert_eq!(result, "test");
}
#[test]
fn test_fixed_bytes_conversion() {
let original = "测试";
let fixed_bytes: [u8; 20] = GbkConverter::utf8_to_fixed_bytes(original).unwrap();
let converted = GbkConverter::fixed_bytes_to_utf8(&fixed_bytes).unwrap();
assert_eq!(converted.trim_end_matches('\0'), original);
}
}