1use crate::error::{encoding_error, CtpResult};
6use encoding::all::GB18030;
7use encoding::{DecoderTrap, EncoderTrap, Encoding};
8use std::ffi::{CStr, CString};
9
10pub struct GbkConverter;
12
13impl GbkConverter {
14 pub fn gb18030_to_utf8(bytes: &[u8]) -> CtpResult<String> {
22 let trimmed_bytes = Self::trim_null_bytes(bytes);
24
25 if trimmed_bytes.is_empty() {
26 return Ok(String::new());
27 }
28
29 GB18030
30 .decode(trimmed_bytes, DecoderTrap::Replace)
31 .map_err(|e| encoding_error(&format!("GB18030解码失败: {}", e)))
32 }
33
34 pub fn utf8_to_gb18030(utf8_str: &str) -> CtpResult<Vec<u8>> {
42 GB18030
43 .encode(utf8_str, EncoderTrap::Replace)
44 .map_err(|e| encoding_error(&format!("UTF-8编码失败: {}", e)))
45 }
46
47 pub fn utf8_to_gb18030_cstring(utf8_str: &str) -> CtpResult<CString> {
55 let gb_bytes = Self::utf8_to_gb18030(utf8_str)?;
56 CString::new(gb_bytes).map_err(|e| encoding_error(&format!("创建CString失败: {}", e)))
57 }
58
59 pub unsafe fn cstring_to_utf8(ptr: *const i8) -> CtpResult<String> {
70 if ptr.is_null() {
71 return Ok(String::new());
72 }
73
74 let c_str = CStr::from_ptr(ptr);
75 let bytes = c_str.to_bytes();
76 Self::gb18030_to_utf8(bytes)
77 }
78
79 fn trim_null_bytes(bytes: &[u8]) -> &[u8] {
81 bytes
82 .iter()
83 .rposition(|&b| b != 0)
84 .map_or(&[], |pos| &bytes[..=pos])
85 }
86
87 pub fn fixed_bytes_to_utf8<const N: usize>(bytes: &[u8; N]) -> CtpResult<String> {
95 Self::gb18030_to_utf8(bytes)
96 }
97
98 pub fn utf8_to_fixed_bytes<const N: usize>(utf8_str: &str) -> CtpResult<[u8; N]> {
106 let gb_bytes = Self::utf8_to_gb18030(utf8_str)?;
107 let mut result = [0u8; N];
108
109 if gb_bytes.len() >= N {
110 result.copy_from_slice(&gb_bytes[..N]);
111 } else {
112 result[..gb_bytes.len()].copy_from_slice(&gb_bytes);
113 }
114
115 Ok(result)
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn test_utf8_to_gb18030_and_back() {
125 let original = "测试字符串";
126 let gb_bytes = GbkConverter::utf8_to_gb18030(original).unwrap();
127 let converted = GbkConverter::gb18030_to_utf8(&gb_bytes).unwrap();
128 assert_eq!(original, converted);
129 }
130
131 #[test]
132 fn test_empty_string() {
133 let result = GbkConverter::gb18030_to_utf8(&[]).unwrap();
134 assert_eq!(result, "");
135 }
136
137 #[test]
138 fn test_null_terminated_bytes() {
139 let bytes = b"test\0\0\0";
140 let result = GbkConverter::gb18030_to_utf8(bytes).unwrap();
141 assert_eq!(result, "test");
142 }
143
144 #[test]
145 fn test_fixed_bytes_conversion() {
146 let original = "测试";
147 let fixed_bytes: [u8; 20] = GbkConverter::utf8_to_fixed_bytes(original).unwrap();
148 let converted = GbkConverter::fixed_bytes_to_utf8(&fixed_bytes).unwrap();
149 assert_eq!(converted.trim_end_matches('\0'), original);
150 }
151}