1use core::{
2 borrow::Borrow,
3 ffi::CStr,
4 fmt::{self, Display},
5 slice,
6};
7
8use crate::{
9 String_CalcLen,
10 bindings::{STRING_SIZE, cc_codepoint, cc_string, cc_uint16, cc_unichar},
11 std_types::{Box, CString, String, ToString, Vec, c_char, c_int},
12};
13
14impl cc_string {
15 pub fn as_slice(&self) -> &[u8] {
16 let len = self.length as usize;
17 let data = self.buffer as *const u8;
18 if len == 0 || data.is_null() {
19 return &[];
20 }
21 unsafe { slice::from_raw_parts(data, len) }
22 }
23}
24
25impl Display for cc_string {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 String::from_utf16_lossy(
28 &self
29 .as_slice()
30 .iter()
31 .map(|c| Convert_CP437ToUnicode(*c))
32 .collect::<Vec<_>>(),
33 )
34 .fmt(f)
35 }
36}
37
38impl From<cc_string> for String {
39 fn from(cc_string: cc_string) -> Self {
40 cc_string.to_string()
41 }
42}
43
44pub struct OwnedString {
45 cc_string: cc_string,
46
47 #[allow(dead_code)]
48 c_str: Box<CStr>,
49}
50
51impl OwnedString {
52 pub fn new<S: Into<String>>(s: S) -> Self {
53 let bytes = s
54 .into()
55 .chars()
57 .map(|c| c as cc_codepoint)
58 .map(Convert_CodepointToCP437)
59 .collect::<Vec<_>>();
60 let length = bytes.len();
61 let capacity = bytes.len();
62
63 let c_str = CString::new(bytes).unwrap().into_boxed_c_str();
64 let buffer: *const c_char = c_str.as_ptr();
65
66 Self {
67 c_str,
68 cc_string: cc_string {
69 buffer: buffer as *mut c_char,
70 length: length as cc_uint16,
71 capacity: capacity as cc_uint16,
72 },
73 }
74 }
75
76 pub fn as_cc_string(&self) -> &cc_string {
77 &self.cc_string
78 }
79
80 pub unsafe fn get_cc_string(&self) -> cc_string {
84 cc_string { ..self.cc_string }
85 }
86}
87
88impl Borrow<cc_string> for OwnedString {
89 fn borrow(&self) -> &cc_string {
90 self.as_cc_string()
91 }
92}
93
94#[test]
95fn test_owned_string() {
96 let owned_string = OwnedString::new("hello");
97
98 fn use_cc_string<T: Borrow<cc_string>>(s: T) {
99 #[cfg(not(feature = "no_std"))]
100 {
101 println!("{:?}", s.borrow());
102 }
103 }
104
105 use_cc_string(owned_string.as_cc_string());
106
107 use_cc_string(owned_string);
108
109 }
111
112pub unsafe fn String_Init(buffer: *mut c_char, length: c_int, capacity: c_int) -> cc_string {
118 cc_string {
119 buffer,
120 length: length as _,
121 capacity: capacity as _,
122 }
123}
124
125#[must_use]
131pub unsafe fn String_FromRaw(buffer: *mut c_char, capacity: c_int) -> cc_string {
132 unsafe { String_Init(buffer, String_CalcLen(buffer, capacity), capacity) }
133}
134
135#[must_use]
145pub unsafe fn String_FromRawArray(buffer: &mut [c_char]) -> cc_string {
146 unsafe { String_FromRaw(buffer.as_mut_ptr(), c_int::try_from(buffer.len()).unwrap()) }
147}
148
149#[must_use]
150pub unsafe fn UNSAFE_GetString(data: &[u8]) -> cc_string {
151 let mut length = 0;
152 for i in (0..STRING_SIZE).rev() {
153 let code = data[i as usize];
154 if code == b'\0' || code == b' ' {
155 continue;
156 }
157 length = i + 1;
158 break;
159 }
160
161 unsafe {
162 String_Init(
163 data.as_ptr() as *mut c_char,
164 length as c_int,
165 STRING_SIZE as c_int,
166 )
167 }
168}
169
170#[test]
171fn test_get_string() {
172 unsafe {
173 let mut s =
174 b"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl0000000000000000"
175 .to_vec();
176 s.resize(STRING_SIZE as usize, 0);
177 assert_eq!(
178 UNSAFE_GetString(&s).to_string(),
179 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl"
180 );
181 }
182}
183
184pub const controlChars: &[cc_unichar] = &[
185 0x0000, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25D8, 0x25CB, 0x25D9, 0x2642,
186 0x2640, 0x266A, 0x266B, 0x263C, 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8,
187 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC,
188];
189
190pub const extendedChars: &[cc_unichar] = &[
191 0x2302, 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8,
192 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB,
193 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3,
194 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB,
195 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551,
196 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E,
197 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565,
198 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590,
199 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9,
200 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7,
201 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0,
202];
203
204pub fn Convert_CP437ToUnicode(raw: u8) -> cc_unichar {
205 if raw < 0x20 {
206 controlChars[raw as usize]
207 } else if raw < 0x7F {
208 raw as cc_unichar
209 } else {
210 extendedChars[raw as usize - 0x7F]
211 }
212}
213
214pub fn Convert_CodepointToCP437(cp: cc_codepoint) -> u8 {
215 let mut c: u8 = 0;
216 Convert_TryCodepointToCP437(cp, &mut c);
217 c
218}
219
220fn ReduceEmoji(cp: cc_codepoint) -> cc_codepoint {
221 if cp == 0x1F31E {
222 return 0x263C;
223 }
224 if cp == 0x1F3B5 {
225 return 0x266B;
226 }
227 if cp == 0x1F642 {
228 return 0x263A;
229 }
230
231 if cp == 0x1F600 || cp == 0x1F601 || cp == 0x1F603 {
232 return 0x263A;
233 }
234 if cp == 0x1F604 || cp == 0x1F606 || cp == 0x1F60A {
235 return 0x263A;
236 }
237 cp
238}
239
240fn Convert_TryCodepointToCP437(mut cp: cc_codepoint, c: &mut u8) -> bool {
241 if (0x20..0x7F).contains(&cp) {
242 *c = cp as u8;
243 return true;
244 }
245 if cp >= 0x1F000 {
246 cp = ReduceEmoji(cp);
247 }
248
249 for (i, &chr) in controlChars.iter().enumerate() {
250 if chr as cc_codepoint == cp {
251 *c = i as u8;
252 return true;
253 }
254 }
255
256 for (i, &chr) in extendedChars.iter().enumerate() {
257 if chr as cc_codepoint == cp {
258 *c = (i + 0x7F) as u8;
259 return true;
260 }
261 }
262
263 *c = b'?';
264 false
265}
266
267#[test]
268fn test_cp_437_conversion() {
269 let bytes: &[u8] = &[97, 236, 236]; let c_str = CString::new(bytes).unwrap();
272 let a = cc_string {
273 buffer: c_str.as_ptr() as *mut c_char,
274 length: bytes.len() as cc_uint16,
275 capacity: bytes.len() as cc_uint16,
276 };
277 assert_eq!(a.to_string(), "a∞∞");
278
279 let str = "a∞∞";
280 let s = OwnedString::new(str);
281 unsafe {
282 assert_eq!(
283 slice::from_raw_parts(
284 s.as_cc_string().buffer as *const u8,
285 s.as_cc_string().length as usize
286 ),
287 bytes
288 );
289 }
290}