GCC Code Coverage Report


Directory: src/gate/
File: src/gate/encode/texts.c
Date: 2025-09-22 22:57:09
Exec Total Coverage
Lines: 0 730 0.0%
Functions: 0 34 0.0%
Branches: 0 370 0.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/encode/texts.h"
30 #include "gate/results.h"
31 #include "gate/debugging.h"
32 #include "gate/utilities.h"
33
34 static char const gate_bom_utf8[] = { (char)0xEF, (char)0xBB, (char)0xBF };
35 static char const gate_bom_utf16le[] = { (char)0xFF, (char)0xFE };
36 static char const gate_bom_utf16be[] = { (char)0xFE, (char)0xFF };
37 static char const gate_bom_utf32le[] = { (char)0x00, (char)0x00, (char)0xFF, (char)0xFE };
38 static char const gate_bom_utf32be[] = { (char)0x00, (char)0x00, (char)0xFE, (char)0xFF };
39
40 gate_string_t const gate_text_bom_utf8 = { gate_bom_utf8, 3, NULL };
41 gate_string_t const gate_text_bom_utf16le = { gate_bom_utf16le, 2, NULL };
42 gate_string_t const gate_text_bom_utf16be = { gate_bom_utf16be, 2, NULL };
43 gate_string_t const gate_text_bom_utf32le = { gate_bom_utf32le, 4, NULL };
44 gate_string_t const gate_text_bom_utf32be = { gate_bom_utf32be, 4, NULL };
45
46 ✗ gate_size_t gate_text_detect_bom(char const* data, gate_size_t datalen, unsigned int* bomtype)
47 {
48 ✗ if (gate_str_starts_with(data, datalen, gate_text_bom_utf8.str, gate_text_bom_utf8.length))
49 {
50 ✗ *bomtype = GATE_TEXT_BOMTYPE_UTF8;
51 ✗ return gate_text_bom_utf8.length;
52 }
53 ✗ if (gate_str_starts_with(data, datalen, gate_text_bom_utf16le.str, gate_text_bom_utf16le.length))
54 {
55 ✗ *bomtype = GATE_TEXT_BOMTYPE_UTF16LE;
56 ✗ return gate_text_bom_utf16le.length;
57 }
58 ✗ if (gate_str_starts_with(data, datalen, gate_text_bom_utf16be.str, gate_text_bom_utf16be.length))
59 {
60 ✗ *bomtype = GATE_TEXT_BOMTYPE_UTF16BE;
61 ✗ return gate_text_bom_utf16be.length;
62 }
63 ✗ if (gate_str_starts_with(data, datalen, gate_text_bom_utf32le.str, gate_text_bom_utf32le.length))
64 {
65 ✗ *bomtype = GATE_TEXT_BOMTYPE_UTF32LE;
66 ✗ return gate_text_bom_utf32le.length;
67 }
68 ✗ if (gate_str_starts_with(data, datalen, gate_text_bom_utf32be.str, gate_text_bom_utf32be.length))
69 {
70 ✗ *bomtype = GATE_TEXT_BOMTYPE_UTF32BE;
71 ✗ return gate_text_bom_utf32be.length;
72 }
73
74 ✗ *bomtype = GATE_TEXT_BOMTYPE_UNKNOWN;
75 ✗ return 0;
76 }
77
78
79 ✗ gate_result_t gate_text_load_utf8(gate_stream_t* src, gate_strbuilder8_t* dst)
80 {
81 gate_result_t ret;
82 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
83 gate_size_t bytesreturned;
84 gate_size_t byteswritten;
85
86 do
87 {
88 ✗ ret = gate_stream_read_block(src, buffer, 3, &bytesreturned);
89 ✗ if (GATE_FAILED(ret))
90 {
91 ✗ break;
92 }
93 ✗ if (bytesreturned < 3)
94 {
95 ✗ gate_strbuilder_append_text(dst, buffer, bytesreturned);
96 ✗ ret = GATE_RESULT_OK;
97 ✗ break;
98 }
99 ✗ if (gate_str_compare(buffer, bytesreturned, gate_bom_utf8, 3) != 0)
100 {
101 ✗ gate_strbuilder_append_text(dst, buffer, bytesreturned);
102 }
103
104 for (;;)
105 {
106 ✗ ret = gate_stream_read_block(src, buffer, sizeof(buffer), &bytesreturned);
107 ✗ if (GATE_FAILED(ret))
108 {
109 ✗ break;
110 }
111 ✗ if (bytesreturned == 0)
112 {
113 ✗ ret = GATE_RESULT_OK;
114 ✗ break;
115 }
116 ✗ byteswritten = gate_strbuilder_append_text(dst, buffer, bytesreturned);
117 ✗ if (byteswritten != bytesreturned)
118 {
119 ✗ ret = GATE_RESULT_OUTOFMEMORY;
120 ✗ break;
121 }
122 }
123
124 } while (0);
125
126 ✗ return ret;
127 }
128
129 /* ANSI byte character mapping of 128 - 159 to unicode characters */
130 static const gate_uint32_t gate_text_ansi_char_map[] = {
131 8364, 129, 8218, 402, 8222, 8230, 8224, 8225,
132 710, 8240, 352, 8249, 338, 141, 381, 143,
133 144, 8216, 8217, 8220, 8221, 8226, 8211, 8212,
134 732, 8482, 353, 8250, 339, 157, 382, 376
135 };
136
137 ✗ gate_result_t gate_text_load_ansi(gate_stream_t* src, gate_strbuilder8_t* dst)
138 {
139 ✗ gate_result_t ret = GATE_RESULT_OK;
140 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
141 gate_size_t bytesreturned;
142 gate_size_t ndx;
143 gate_uint8_t chr;
144 char utf8buffer[16];
145 gate_size_t utf8size;
146
147 do
148 {
149 ✗ ret = gate_stream_read_block(src, buffer, sizeof(buffer), &bytesreturned);
150 ✗ if (GATE_FAILED(ret))
151 {
152 /* failed to read from stream */
153 ✗ break;
154 }
155 ✗ if (bytesreturned == 0)
156 {
157 /* end of stream reached -> returning success */
158 ✗ break;
159 }
160 ✗ for (ndx = 0; ndx != bytesreturned; ++ndx)
161 {
162 ✗ chr = (gate_uint8_t)buffer[ndx];
163 ✗ if (chr <= 127)
164 {
165 ✗ if (0 == gate_strbuilder_append_text(dst, &buffer[ndx], 1))
166 {
167 ✗ ret = GATE_RESULT_OUTOFMEMORY;
168 ✗ break;
169 }
170 }
171 ✗ else if (chr >= 160)
172 {
173 ✗ utf8size = gate_char_write_utf8((gate_char32_t)chr, utf8buffer, sizeof(utf8buffer));
174 ✗ if (utf8size != gate_strbuilder_append_text(dst, utf8buffer, utf8size))
175 {
176 ✗ ret = GATE_RESULT_OUTOFMEMORY;
177 ✗ break;
178 }
179 }
180 else
181 {
182 ✗ utf8size = gate_char_write_utf8(gate_text_ansi_char_map[chr - 128], utf8buffer, sizeof(utf8buffer));
183 ✗ if (utf8size != gate_strbuilder_append_text(dst, utf8buffer, utf8size))
184 {
185 ✗ ret = GATE_RESULT_OUTOFMEMORY;
186 ✗ break;
187 }
188 }
189 }
190 ✗ } while (GATE_SUCCEEDED(ret));
191
192 ✗ return ret;
193
194 }
195 ✗ gate_result_t gate_text_load_utf16le(gate_stream_t* src, gate_strbuilder8_t* dst)
196 {
197 ✗ gate_result_t ret = GATE_RESULT_OK;
198 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
199 gate_size_t bytesread;
200 ✗ gate_size_t bufferpos = 0;
201 gate_size_t length;
202 gate_char16_t chr16[2];
203 gate_size_t chr16used;
204 gate_char32_t chr32;
205 gate_char8_t chr8[8];
206 gate_size_t byteswritten;
207
208 char* ptr;
209
210 ✗ while (GATE_SUCCEEDED(ret))
211 {
212 ✗ ret = gate_stream_read_block(src, &buffer[bufferpos], sizeof(buffer) - bufferpos, &bytesread);
213 ✗ if (GATE_FAILED(ret) || (bytesread == 0))
214 {
215 break;
216 }
217
218 ✗ bufferpos += bytesread;
219 ✗ ptr = buffer;
220 ✗ length = sizeof(buffer) - bufferpos;
221 ✗ while (length > 1)
222 {
223 ✗ chr16[0] = (gate_char16_t)(((gate_uint16_t)(gate_uint8_t)ptr[0]))
224 ✗ | (gate_char16_t)(((gate_uint16_t)(gate_uint8_t)ptr[1]) >> 8)
225 ;
226 ✗ if (length > 3)
227 {
228 ✗ chr16[1] = (gate_char16_t)(((gate_uint16_t)(gate_uint8_t)ptr[2]))
229 ✗ | (gate_char16_t)(((gate_uint16_t)(gate_uint8_t)ptr[3]) >> 8)
230 ;
231 ✗ ptr += 4;
232 ✗ length -= 4;
233 }
234 else
235 {
236 ✗ chr16[1] = 0;
237 ✗ ptr += 2;
238 ✗ length -= 2;
239 }
240 ✗ chr16used = gate_char_read_utf16(chr16, 2, &chr32);
241
242 ✗ byteswritten = gate_char_write_utf8(chr32, &chr8[0], sizeof(chr8));
243 ✗ if (0 == gate_strbuilder_append_text(dst, chr8, byteswritten))
244 {
245 ✗ ret = GATE_RESULT_OUTOFMEMORY;
246 ✗ break;
247 }
248 }
249 ✗ if (length != 0)
250 {
251 ✗ gate_mem_move(&buffer[0], ptr, length);
252 }
253 ✗ bufferpos = length;
254 }
255
256 ✗ return ret;
257 }
258 ✗ gate_result_t gate_text_load_utf16be(gate_stream_t* src, gate_strbuilder8_t* dst)
259 {
260 ✗ gate_result_t ret = GATE_RESULT_OK;
261 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
262 gate_size_t bytesread;
263 ✗ gate_size_t bufferpos = 0;
264 gate_size_t length;
265 gate_char16_t chr16[2];
266 gate_size_t chr16used;
267 gate_char32_t chr32;
268 gate_char8_t chr8[32];
269 gate_size_t byteswritten;
270
271 char* ptr;
272
273 ✗ while (GATE_SUCCEEDED(ret))
274 {
275 ✗ ret = gate_stream_read_block(src, &buffer[bufferpos], sizeof(buffer) - bufferpos, &bytesread);
276 ✗ if (GATE_FAILED(ret) || (bytesread == 0))
277 {
278 break;
279 }
280
281 ✗ bufferpos += bytesread;
282 ✗ ptr = buffer;
283 ✗ length = sizeof(buffer) - bufferpos;
284 ✗ while (length > 1)
285 {
286 ✗ chr16[0] = (gate_char16_t)(((gate_uint16_t)(gate_uint8_t)ptr[1]))
287 ✗ | (gate_char16_t)(((gate_uint16_t)(gate_uint8_t)ptr[0]) >> 8)
288 ;
289 ✗ if (length > 3)
290 {
291 ✗ chr16[1] = (gate_char16_t)(((gate_uint16_t)(gate_uint8_t)ptr[3]))
292 ✗ | (gate_char16_t)(((gate_uint16_t)(gate_uint8_t)ptr[2]) >> 8)
293 ;
294 ✗ ptr += 4;
295 ✗ length -= 4;
296 }
297 else
298 {
299 ✗ chr16[1] = 0;
300 ✗ ptr += 2;
301 ✗ length -= 2;
302 }
303 ✗ chr16used = gate_char_read_utf16(chr16, 2, &chr32);
304
305 ✗ byteswritten = gate_char_write_utf8(chr32, &chr8[0], sizeof(chr8));
306 ✗ if (0 == gate_strbuilder_append_text(dst, chr8, byteswritten))
307 {
308 ✗ ret = GATE_RESULT_OUTOFMEMORY;
309 ✗ break;
310 }
311 }
312 ✗ if (length != 0)
313 {
314 ✗ gate_mem_move(&buffer[0], ptr, length);
315 }
316 ✗ bufferpos = length;
317 }
318 ✗ return ret;
319 }
320 ✗ gate_result_t gate_text_load_utf32le(gate_stream_t* src, gate_strbuilder8_t* dst)
321 {
322 ✗ gate_result_t ret = GATE_RESULT_OK;
323 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
324 gate_size_t bytesread;
325 ✗ gate_size_t bufferpos = 0;
326 gate_size_t length;
327 gate_char32_t chr32;
328 gate_char8_t chr8[32];
329 gate_size_t byteswritten;
330
331 char* ptr;
332
333 ✗ while (GATE_SUCCEEDED(ret))
334 {
335 ✗ ret = gate_stream_read_block(src, &buffer[bufferpos], sizeof(buffer) - bufferpos, &bytesread);
336 ✗ if (GATE_FAILED(ret) || (bytesread == 0))
337 {
338 break;
339 }
340
341 ✗ bufferpos += bytesread;
342 ✗ ptr = buffer;
343 ✗ length = sizeof(buffer) - bufferpos;
344 ✗ while (length > 4)
345 {
346 ✗ chr32 = (gate_char32_t)(((gate_uint32_t)(gate_uint8_t)ptr[0]))
347 ✗ | (gate_char32_t)(((gate_uint32_t)(gate_uint8_t)ptr[1]) >> 8)
348 ✗ | (gate_char32_t)(((gate_uint32_t)(gate_uint8_t)ptr[2]) >> 16)
349 ✗ | (gate_char32_t)(((gate_uint32_t)(gate_uint8_t)ptr[3]) >> 24)
350 ;
351 ✗ ptr += 4;
352 ✗ length -= 4;
353
354 ✗ byteswritten = gate_char_write_utf8(chr32, &chr8[0], sizeof(chr8));
355 ✗ if (0 == gate_strbuilder_append_text(dst, chr8, byteswritten))
356 {
357 ✗ ret = GATE_RESULT_OUTOFMEMORY;
358 ✗ break;
359 }
360 }
361 ✗ if (length != 0)
362 {
363 ✗ gate_mem_move(&buffer[0], ptr, length);
364 }
365 ✗ bufferpos = length;
366 }
367 ✗ return ret;
368 }
369 ✗ gate_result_t gate_text_load_utf32be(gate_stream_t* src, gate_strbuilder8_t* dst)
370 {
371 ✗ gate_result_t ret = GATE_RESULT_OK;
372 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
373 gate_size_t bytesread;
374 ✗ gate_size_t bufferpos = 0;
375 gate_size_t length;
376 gate_char32_t chr32;
377 gate_char8_t chr8[32];
378 gate_size_t byteswritten;
379
380 char* ptr;
381
382 ✗ while (GATE_SUCCEEDED(ret))
383 {
384 ✗ ret = gate_stream_read_block(src, &buffer[bufferpos], sizeof(buffer) - bufferpos, &bytesread);
385 ✗ if (GATE_FAILED(ret) || (bytesread == 0))
386 {
387 break;
388 }
389
390 ✗ bufferpos += bytesread;
391 ✗ ptr = buffer;
392 ✗ length = sizeof(buffer) - bufferpos;
393 ✗ while (length > 4)
394 {
395 ✗ chr32 = (gate_char32_t)(((gate_uint32_t)(gate_uint8_t)ptr[3]))
396 ✗ | (gate_char32_t)(((gate_uint32_t)(gate_uint8_t)ptr[2]) >> 8)
397 ✗ | (gate_char32_t)(((gate_uint32_t)(gate_uint8_t)ptr[1]) >> 16)
398 ✗ | (gate_char32_t)(((gate_uint32_t)(gate_uint8_t)ptr[0]) >> 24)
399 ;
400 ✗ ptr += 4;
401 ✗ length -= 4;
402
403 ✗ byteswritten = gate_char_write_utf8(chr32, &chr8[0], sizeof(chr8));
404 ✗ if (0 == gate_strbuilder_append_text(dst, chr8, byteswritten))
405 {
406 ✗ ret = GATE_RESULT_OUTOFMEMORY;
407 ✗ break;
408 }
409 }
410 ✗ if (length != 0)
411 {
412 ✗ gate_mem_move(&buffer[0], ptr, length);
413 }
414 ✗ bufferpos = length;
415 }
416 ✗ return ret;
417 }
418
419 ✗ gate_result_t gate_text_save_utf8(gate_string_t const* src, gate_stream_t* dst, gate_bool_t addbom)
420 {
421 ✗ gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
422 ✗ gate_size_t byteswritten = 0;
423
424 ✗ if (addbom)
425 {
426 ✗ ret = gate_stream_write_block(dst, gate_text_bom_utf8.str, gate_text_bom_utf8.length, &byteswritten);
427 ✗ if (GATE_FAILED(ret)) return ret;
428 }
429 ✗ ret = gate_stream_write_block(dst, src->str, src->length, &byteswritten);
430 ✗ GATE_DEBUG_ASSERT(byteswritten == src->length);
431 ✗ return ret;
432 }
433 ✗ gate_result_t gate_text_save_ansi(gate_string_t const* src, gate_stream_t* dst)
434 {
435 ✗ gate_result_t ret = GATE_RESULT_OK;
436 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
437 ✗ gate_size_t bufferpos = 0;
438 gate_char8_t chr8;
439 gate_char32_t chr32;
440 gate_size_t utf8block;
441 gate_size_t ndx;
442 gate_size_t byteswritten;
443 ✗ char const* ptr = src->str;
444 ✗ gate_size_t length = src->length;
445
446 ✗ while ((length != 0) && GATE_SUCCEEDED(ret))
447 {
448 ✗ utf8block = gate_char_read_utf8(ptr, length, &chr32);
449 ✗ if (utf8block == 0)
450 {
451 ✗ ret = GATE_RESULT_INVALIDINPUT;
452 ✗ break;
453 }
454 ✗ ptr += utf8block;
455 ✗ length -= utf8block;
456
457 ✗ if ((chr32 <= 127) || ((chr32 >= 160) && (chr32 <= 255)))
458 {
459 ✗ buffer[bufferpos++] = (gate_char8_t)chr32;
460 }
461 else
462 {
463 ✗ chr8 = '?'; /* if character not in ansi map -> use '?' as replacement */
464 ✗ for (ndx = 0; ndx != sizeof(gate_text_ansi_char_map) / sizeof(gate_text_ansi_char_map[0]); ++ndx)
465 {
466 ✗ if (gate_text_ansi_char_map[ndx] == chr32)
467 {
468 ✗ chr8 = (gate_char8_t)(ndx + 128);
469 ✗ break;
470 }
471 }
472 ✗ buffer[bufferpos++] = chr8;
473 }
474
475 ✗ if (bufferpos >= sizeof(buffer) / 2)
476 {
477 ✗ ret = gate_stream_write_block(dst, buffer, bufferpos, &byteswritten);
478 /* if write attempt fails, while-loop while be canceled */
479 ✗ bufferpos = 0;
480 }
481
482 }
483
484 ✗ if (bufferpos != 0)
485 {
486 ✗ ret = gate_stream_write_block(dst, buffer, bufferpos, &byteswritten);
487 ✗ bufferpos = 0;
488 }
489
490 ✗ return ret;
491 }
492 ✗ gate_result_t gate_text_save_utf16le(gate_string_t const* src, gate_stream_t* dst, gate_bool_t addbom)
493 {
494 ✗ gate_result_t ret = GATE_RESULT_OK;
495 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
496 gate_char16_t utf16[8];
497 gate_size_t utf16used;
498 ✗ gate_size_t bufferpos = 0;
499 gate_char32_t chr32;
500 gate_size_t utf8block;
501 gate_size_t ndx;
502 gate_size_t byteswritten;
503 ✗ char const* ptr = src->str;
504 ✗ gate_size_t length = src->length;
505
506 ✗ if (addbom)
507 {
508 ✗ ret = gate_stream_write_block(dst, gate_text_bom_utf16le.str, gate_text_bom_utf16le.length, &byteswritten);
509 ✗ if (GATE_FAILED(ret)) return ret;
510 }
511
512 ✗ while ((length != 0) && GATE_SUCCEEDED(ret))
513 {
514 ✗ utf8block = gate_char_read_utf8(ptr, length, &chr32);
515 ✗ if (utf8block == 0)
516 {
517 ✗ ret = GATE_RESULT_INVALIDINPUT;
518 ✗ break;
519 }
520 ✗ ptr += utf8block;
521 ✗ length -= utf8block;
522
523 ✗ utf16used = gate_char_write_utf16(chr32, utf16, sizeof(utf16) / sizeof(utf16[0]));
524 ✗ for (ndx = 0; ndx != utf16used; ++ndx)
525 {
526 ✗ buffer[bufferpos++] = (char)(gate_uint8_t)(((gate_uint16_t)utf16[ndx]) & 0x00ff);
527 ✗ buffer[bufferpos++] = (char)(gate_uint8_t)(((gate_uint16_t)utf16[ndx] >> 8) & 0x00ff);
528 }
529
530 ✗ if (bufferpos >= sizeof(buffer) / 2)
531 {
532 ✗ ret = gate_stream_write_block(dst, buffer, bufferpos, &byteswritten);
533 /* if write attempt fails, while-loop while be canceled */
534 ✗ bufferpos = 0;
535 }
536 }
537
538 ✗ if (bufferpos != 0)
539 {
540 ✗ ret = gate_stream_write_block(dst, buffer, bufferpos, &byteswritten);
541 ✗ bufferpos = 0;
542 }
543
544 ✗ return ret;
545 }
546 ✗ gate_result_t gate_text_save_utf16be(gate_string_t const* src, gate_stream_t* dst, gate_bool_t addbom)
547 {
548 ✗ gate_result_t ret = GATE_RESULT_OK;
549 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
550 gate_char16_t utf16[8];
551 gate_size_t utf16used;
552 ✗ gate_size_t bufferpos = 0;
553 gate_char32_t chr32;
554 gate_size_t utf8block;
555 gate_size_t ndx;
556 gate_size_t byteswritten;
557 ✗ char const* ptr = src->str;
558 ✗ gate_size_t length = src->length;
559
560 ✗ if (addbom)
561 {
562 ✗ ret = gate_stream_write_block(dst, gate_text_bom_utf16be.str, gate_text_bom_utf16be.length, &byteswritten);
563 ✗ if (GATE_FAILED(ret)) return ret;
564 }
565
566 ✗ while ((length != 0) && GATE_SUCCEEDED(ret))
567 {
568 ✗ utf8block = gate_char_read_utf8(ptr, length, &chr32);
569 ✗ if (utf8block == 0)
570 {
571 ✗ ret = GATE_RESULT_INVALIDINPUT;
572 ✗ break;
573 }
574 ✗ ptr += utf8block;
575 ✗ length -= utf8block;
576
577 ✗ utf16used = gate_char_write_utf16(chr32, utf16, sizeof(utf16) / sizeof(utf16[0]));
578 ✗ for (ndx = 0; ndx != utf16used; ++ndx)
579 {
580 ✗ buffer[bufferpos++] = (char)(gate_uint8_t)(((gate_uint16_t)utf16[ndx] >> 8) & 0x00ff);
581 ✗ buffer[bufferpos++] = (char)(gate_uint8_t)(((gate_uint16_t)utf16[ndx]) & 0x00ff);
582 }
583
584 ✗ if (bufferpos >= sizeof(buffer) / 2)
585 {
586 ✗ ret = gate_stream_write_block(dst, buffer, bufferpos, &byteswritten);
587 /* if write attempt fails, while-loop while be canceled */
588 ✗ bufferpos = 0;
589 }
590 }
591
592 ✗ if (bufferpos != 0)
593 {
594 ✗ ret = gate_stream_write_block(dst, buffer, bufferpos, &byteswritten);
595 ✗ bufferpos = 0;
596 }
597
598 ✗ return ret;
599 }
600 ✗ gate_result_t gate_text_save_utf32le(gate_string_t const* src, gate_stream_t* dst, gate_bool_t addbom)
601 {
602 ✗ gate_result_t ret = GATE_RESULT_OK;
603 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
604 ✗ gate_size_t bufferpos = 0;
605 gate_char32_t chr32;
606 gate_size_t utf8block;
607 gate_size_t byteswritten;
608 ✗ char const* ptr = src->str;
609 ✗ gate_size_t length = src->length;
610
611 ✗ if (addbom)
612 {
613 ✗ ret = gate_stream_write_block(dst, gate_text_bom_utf32le.str, gate_text_bom_utf32le.length, &byteswritten);
614 ✗ if (GATE_FAILED(ret)) return ret;
615 }
616
617 ✗ while ((length != 0) && GATE_SUCCEEDED(ret))
618 {
619 ✗ utf8block = gate_char_read_utf8(ptr, length, &chr32);
620 ✗ if (utf8block == 0)
621 {
622 ✗ ret = GATE_RESULT_INVALIDINPUT;
623 ✗ break;
624 }
625 ✗ ptr += utf8block;
626 ✗ length -= utf8block;
627
628 ✗ buffer[bufferpos++] = (char)(gate_uint8_t)(((gate_uint32_t)chr32) & 0x00ff);
629 ✗ buffer[bufferpos++] = (char)(gate_uint8_t)(((gate_uint32_t)chr32 >> 8) & 0x00ff);
630 ✗ buffer[bufferpos++] = (char)(gate_uint8_t)(((gate_uint32_t)chr32 >> 16) & 0x00ff);
631 ✗ buffer[bufferpos++] = (char)(gate_uint8_t)(((gate_uint32_t)chr32 >> 24) & 0x00ff);
632
633 ✗ if (bufferpos >= sizeof(buffer) / 2)
634 {
635 ✗ ret = gate_stream_write_block(dst, buffer, bufferpos, &byteswritten);
636 /* if write attempt fails, while-loop while be canceled */
637 ✗ bufferpos = 0;
638 }
639 }
640
641 ✗ if (bufferpos != 0)
642 {
643 ✗ ret = gate_stream_write_block(dst, buffer, bufferpos, &byteswritten);
644 ✗ bufferpos = 0;
645 }
646
647 ✗ return ret;
648 }
649 ✗ gate_result_t gate_text_save_utf32be(gate_string_t const* src, gate_stream_t* dst, gate_bool_t addbom)
650 {
651 ✗ gate_result_t ret = GATE_RESULT_OK;
652 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
653 ✗ gate_size_t bufferpos = 0;
654 gate_char32_t chr32;
655 gate_size_t utf8block;
656 gate_size_t byteswritten;
657 ✗ char const* ptr = src->str;
658 ✗ gate_size_t length = src->length;
659
660 ✗ if (addbom)
661 {
662 ✗ ret = gate_stream_write_block(dst, gate_text_bom_utf32be.str, gate_text_bom_utf32be.length, &byteswritten);
663 ✗ if (GATE_FAILED(ret)) return ret;
664 }
665
666 ✗ while ((length != 0) && GATE_SUCCEEDED(ret))
667 {
668 ✗ utf8block = gate_char_read_utf8(ptr, length, &chr32);
669 ✗ if (utf8block == 0)
670 {
671 ✗ ret = GATE_RESULT_INVALIDINPUT;
672 ✗ break;
673 }
674 ✗ ptr += utf8block;
675 ✗ length -= utf8block;
676
677 ✗ buffer[bufferpos++] = (char)(gate_uint8_t)(((gate_uint32_t)chr32 >> 24) & 0x00ff);
678 ✗ buffer[bufferpos++] = (char)(gate_uint8_t)(((gate_uint32_t)chr32 >> 16) & 0x00ff);
679 ✗ buffer[bufferpos++] = (char)(gate_uint8_t)(((gate_uint32_t)chr32 >> 8) & 0x00ff);
680 ✗ buffer[bufferpos++] = (char)(gate_uint8_t)(((gate_uint32_t)chr32) & 0x00ff);
681
682 ✗ if (bufferpos >= sizeof(buffer) / 2)
683 {
684 ✗ ret = gate_stream_write_block(dst, buffer, bufferpos, &byteswritten);
685 /* if write attempt fails, while-loop while be canceled */
686 ✗ bufferpos = 0;
687 }
688 }
689
690 ✗ if (bufferpos != 0)
691 {
692 ✗ ret = gate_stream_write_block(dst, buffer, bufferpos, &byteswritten);
693 ✗ bufferpos = 0;
694 }
695
696 ✗ return ret;
697 }
698
699 ✗ gate_result_t gate_text_c_escape(gate_string_t const* str, gate_strbuilder8_t* dst)
700 {
701 ✗ gate_result_t ret = GATE_RESULT_OK;
702 ✗ char const* ptr = str->str;
703 ✗ gate_size_t len = str->length;
704 ✗ char buffer[8] = GATE_INIT_EMPTY;
705 ✗ gate_size_t buffer_used = 0;
706
707 ✗ while (len != 0)
708 {
709 ✗ switch (*ptr)
710 {
711 ✗ case '\\': buffer[0] = '\\'; buffer[1] = '\\'; buffer_used = 2; break;
712 ✗ case '\"': buffer[0] = '\\'; buffer[1] = '\"'; buffer_used = 2; break;
713 ✗ case '\a': buffer[0] = '\\'; buffer[1] = 'a'; buffer_used = 2; break;
714 ✗ case '\b': buffer[0] = '\\'; buffer[1] = 'b'; buffer_used = 2; break;
715 ✗ case 0x1b: buffer[0] = '\\'; buffer[1] = 'e'; buffer_used = 2; break;
716 ✗ case '\f': buffer[0] = '\\'; buffer[1] = 'f'; buffer_used = 2; break;
717 ✗ case '\n': buffer[0] = '\\'; buffer[1] = 'n'; buffer_used = 2; break;
718 ✗ case '\r': buffer[0] = '\\'; buffer[1] = 'r'; buffer_used = 2; break;
719 ✗ case '\t': buffer[0] = '\\'; buffer[1] = 't'; buffer_used = 2; break;
720 ✗ case '\v': buffer[0] = '\\'; buffer[1] = 'v'; buffer_used = 2; break;
721 ✗ default: buffer[0] = *ptr; buffer_used = 1; break;
722 }
723
724 ✗ if (0 == gate_strbuilder_append_text(dst, buffer, buffer_used))
725 {
726 ✗ ret = GATE_RESULT_OUTOFMEMORY;
727 ✗ break;
728 }
729 ✗ ++ptr;
730 ✗ --len;
731 }
732 ✗ return ret;
733 }
734
735 ✗ gate_result_t gate_text_c_unescape(gate_string_t const* str, gate_strbuilder8_t* dst)
736 {
737 ✗ gate_result_t ret = GATE_RESULT_OK;
738 ✗ char const* ptr = (str ? str->str : NULL);
739 ✗ gate_size_t len = (str ? str->length : 0);
740 ✗ char buffer[8] = GATE_INIT_EMPTY;
741 gate_uint8_t u8;
742 ✗ gate_size_t buffer_used = 8;
743 gate_size_t len_parsed;
744
745 ✗ while (len != 0)
746 {
747 ✗ if (*ptr == '\\')
748 {
749 ✗ len_parsed = 2;
750 ✗ if (len < 2)
751 {
752 ✗ ret = GATE_RESULT_INVALIDDATA;
753 ✗ break;
754 }
755 ✗ buffer_used = 1;
756 ✗ switch (ptr[1])
757 {
758 ✗ case '\\': buffer[0] = '\\'; break;
759 ✗ case '\"': buffer[0] = '\"'; break;
760 ✗ case '?': buffer[0] = '\?'; break;
761 ✗ case 'a': buffer[0] = '\a'; break;
762 ✗ case 'b': buffer[0] = '\b'; break;
763 ✗ case 'e': buffer[0] = 0x1b; break;
764 ✗ case 'f': buffer[0] = '\f'; break;
765 ✗ case 'n': buffer[0] = '\n'; break;
766 ✗ case 'r': buffer[0] = '\r'; break;
767 ✗ case 't': buffer[0] = '\t'; break;
768 ✗ case 'v': buffer[0] = '\v'; break;
769 ✗ case 'x':
770 {
771 ✗ buffer_used = 0;
772 ✗ if (len >= 4)
773 {
774 ✗ if (gate_str_parse_hex_byte(&ptr[2], &u8))
775 {
776 ✗ buffer[0] = (char)u8;
777 ✗ buffer_used = 1;
778 ✗ len_parsed = 4;
779 }
780 }
781 ✗ break;
782 }
783 ✗ case 'u':
784 {
785 ✗ buffer_used = 0;
786 ✗ if (len >= 6)
787 {
788 ✗ if (4 == gate_str_parse_hex_buffer(&ptr[2], 4, &buffer[0], 2))
789 {
790 ✗ buffer_used = 2;
791 ✗ len_parsed = 6;
792 }
793 }
794 ✗ break;
795 }
796 ✗ case 'U':
797 {
798 ✗ buffer_used = 0;
799 ✗ if (len >= 10)
800 {
801 ✗ if (8 == gate_str_parse_hex_buffer(&ptr[2], 8, &buffer[0], 4))
802 {
803 ✗ buffer_used = 4;
804 ✗ len_parsed = 10;
805 }
806 }
807 ✗ break;
808 }
809 ✗ case '0':
810 case '1':
811 case '2':
812 case '3':
813 {
814 ✗ buffer_used = 0;
815 ✗ if (len >= 4)
816 {
817 ✗ if (gate_str_parse_oct_byte(&ptr[1], &u8))
818 {
819 ✗ buffer[0] = (char)u8;
820 ✗ buffer_used = 1;
821 }
822 }
823 ✗ break;
824 }
825 ✗ default:
826 {
827 ✗ buffer[0] = ptr[0];
828 ✗ buffer[1] = ptr[1];
829 ✗ buffer_used = 2;
830 ✗ break;
831 }
832 }
833 ✗ if (buffer_used == 0)
834 {
835 ✗ ret = GATE_RESULT_INVALIDDATA;
836 ✗ break;
837 }
838 ✗ gate_strbuilder_append_text(dst, buffer, buffer_used);
839 ✗ ptr += len_parsed;
840 ✗ len -= len_parsed;
841 }
842 else
843 {
844 ✗ gate_strbuilder_append_text(dst, ptr, 1);
845 ✗ ++ptr;
846 ✗ --len;
847 }
848 }
849 ✗ return ret;
850 }
851 ✗ gate_size_t gate_text_c_escape_str(gate_char8_t const* src, gate_size_t srclen, gate_char8_t* dst, gate_size_t dstlen)
852 {
853 ✗ gate_size_t ret = 0;
854 ✗ gate_size_t coded_len = 0;
855
856 ✗ while ((srclen != 0) && (dstlen > 1))
857 {
858 ✗ coded_len = 2;
859 ✗ switch (*src)
860 {
861 ✗ case '\\': dst[0] = '\\'; dst[1] = '\\'; break;
862 ✗ case '\"': dst[0] = '\\'; dst[1] = '\"'; break;
863 ✗ case '\a': dst[0] = '\\'; dst[1] = 'a'; break;
864 ✗ case '\b': dst[0] = '\\'; dst[1] = 'b'; break;
865 ✗ case 0x1b: dst[0] = '\\'; dst[1] = 'e'; break;
866 ✗ case '\f': dst[0] = '\\'; dst[1] = 'f'; break;
867 ✗ case '\n': dst[0] = '\\'; dst[1] = 'n'; break;
868 ✗ case '\r': dst[0] = '\\'; dst[1] = 'r'; break;
869 ✗ case '\t': dst[0] = '\\'; dst[1] = 't'; break;
870 ✗ case '\v': dst[0] = '\\'; dst[1] = 'v'; break;
871 ✗ default: dst[0] = *src; coded_len = 1; break;
872 }
873 ✗ ++src;
874 ✗ --srclen;
875 ✗ dst += coded_len;
876 ✗ dstlen -= coded_len;
877 ✗ ret += coded_len;
878 }
879 ✗ if (dstlen > 0)
880 {
881 ✗ *dst = 0;
882 }
883 ✗ return ret;
884 }
885 ✗ gate_size_t gate_text_c_unescape_str(gate_char8_t const* src, gate_size_t srclen, gate_char8_t* dst, gate_size_t dstlen)
886 {
887 ✗ gate_size_t ret = 0;
888 ✗ char buffer[8] = GATE_INIT_EMPTY;
889 gate_uint8_t u8;
890 ✗ gate_size_t buffer_used = 8;
891 gate_size_t len_parsed;
892
893 ✗ while ((srclen != 0) && (dstlen != 0))
894 {
895 ✗ if (*src == '\\')
896 {
897 ✗ len_parsed = 2;
898 ✗ if (srclen < 2)
899 {
900 ✗ break;
901 }
902 ✗ buffer_used = 1;
903 ✗ switch (src[1])
904 {
905 ✗ case '\\': buffer[0] = '\\'; break;
906 ✗ case '\"': buffer[0] = '\"'; break;
907 ✗ case '?': buffer[0] = '\?'; break;
908 ✗ case 'a': buffer[0] = '\a'; break;
909 ✗ case 'b': buffer[0] = '\b'; break;
910 ✗ case 'e': buffer[0] = 0x1b; break;
911 ✗ case 'f': buffer[0] = '\f'; break;
912 ✗ case 'n': buffer[0] = '\n'; break;
913 ✗ case 'r': buffer[0] = '\r'; break;
914 ✗ case 't': buffer[0] = '\t'; break;
915 ✗ case 'v': buffer[0] = '\v'; break;
916 ✗ case 'x':
917 {
918 ✗ buffer_used = 0;
919 ✗ if (srclen >= 4)
920 {
921 ✗ if (gate_str_parse_hex_byte(&src[2], &u8))
922 {
923 ✗ buffer[0] = (char)u8;
924 ✗ buffer_used = 1;
925 ✗ len_parsed = 4;
926 }
927 }
928 ✗ break;
929 }
930 ✗ case 'u':
931 {
932 ✗ buffer_used = 0;
933 ✗ if (srclen >= 6)
934 {
935 ✗ if (4 == gate_str_parse_hex_buffer(&src[2], 4, &buffer[0], 2))
936 {
937 ✗ buffer_used = 2;
938 ✗ len_parsed = 6;
939 }
940 }
941 ✗ break;
942 }
943 ✗ case 'U':
944 {
945 ✗ buffer_used = 0;
946 ✗ if (srclen >= 10)
947 {
948 ✗ if (8 == gate_str_parse_hex_buffer(&src[2], 8, &buffer[0], 4))
949 {
950 ✗ buffer_used = 4;
951 ✗ len_parsed = 10;
952 }
953 }
954 ✗ break;
955 }
956 ✗ case '0':
957 case '1':
958 case '2':
959 case '3':
960 {
961 ✗ buffer_used = 0;
962 ✗ if (srclen >= 4)
963 {
964 ✗ if (gate_str_parse_oct_byte(&src[1], &u8))
965 {
966 ✗ buffer[0] = (char)u8;
967 ✗ buffer_used = 1;
968 ✗ len_parsed = 4;
969 }
970 }
971 ✗ break;
972 }
973 ✗ default:
974 {
975 ✗ buffer[0] = src[0];
976 ✗ buffer[1] = src[1];
977 ✗ buffer_used = 2;
978 ✗ break;
979 }
980 }
981
982 ✗ if (dstlen < buffer_used)
983 {
984 ✗ break;
985 }
986
987 ✗ if (buffer_used == 0)
988 {
989 ✗ *dst = *src;
990 ✗ ++dst;
991 ✗ ++src;
992 ✗ ++ret;
993 ✗ --srclen;
994 ✗ --dstlen;
995 }
996 else
997 {
998 ✗ gate_mem_copy(dst, buffer, buffer_used);
999
1000 ✗ dst += buffer_used;
1001 ✗ dstlen -= buffer_used;
1002 ✗ ret += buffer_used;
1003 ✗ src += len_parsed;
1004 ✗ srclen -= len_parsed;
1005 }
1006 }
1007 else
1008 {
1009 ✗ *dst = *src;
1010 ✗ ++dst;
1011 ✗ ++src;
1012 ✗ ++ret;
1013 ✗ --srclen;
1014 ✗ --dstlen;
1015 }
1016 }
1017 ✗ return ret;
1018 }
1019
1020 ✗ gate_result_t gate_text_print_vartoken(gate_strbuilder_t* target, gate_string_t const* varname)
1021 {
1022 ✗ gate_result_t ret = GATE_RESULT_OK;
1023 ✗ gate_size_t varnamelen = gate_string_length(varname);
1024 do
1025 {
1026 ✗ if (gate_strbuilder_append_cstr(target, "${") < 2)
1027 {
1028 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1029 ✗ break;
1030 }
1031 ✗ if (gate_strbuilder_append_string(target, varname) < varnamelen)
1032 {
1033 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1034 ✗ break;
1035 }
1036 ✗ if (gate_strbuilder_append_cstr(target, "}") < 1)
1037 {
1038 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1039 ✗ break;
1040 }
1041 } while (0);
1042 ✗ return ret;
1043 }
1044
1045 ✗ static gate_size_t gate_text_resolve_var(gate_string_t const* postdollartoken, gate_map_t const* strmap, gate_string_t* replace)
1046 {
1047 ✗ gate_size_t ret = 0;
1048 gate_string_t const* ptr_str;
1049 gate_size_t pos;
1050 ✗ gate_string_t var_name = GATE_STRING_INIT_EMPTY;
1051 gate_map_iterator_t iter;
1052
1053 do
1054 {
1055 ✗ if (gate_string_starts_with_char(postdollartoken, '{'))
1056 {
1057 ✗ pos = gate_string_char_pos(postdollartoken, '}', 1);
1058 ✗ if (pos == GATE_STR_NPOS)
1059 {
1060 ✗ break;
1061 }
1062 ✗ gate_string_substr(&var_name, postdollartoken, 1, pos - 1);
1063
1064 ✗ ptr_str = (gate_string_t const*)gate_map_get_value(strmap, &var_name);
1065 ✗ if (!ptr_str)
1066 {
1067 /* no match */
1068 ✗ break;
1069 }
1070 ✗ gate_string_duplicate(replace, ptr_str);
1071 ✗ ret = pos + 1;
1072 ✗ break;
1073 }
1074
1075 ✗ iter = gate_map_first(strmap);
1076 ✗ while (gate_map_iterator_valid(iter))
1077 {
1078 ✗ ptr_str = (gate_string_t const*)gate_map_iterator_key(iter);
1079 ✗ if (gate_string_starts_with(postdollartoken, ptr_str))
1080 {
1081 ✗ gate_string_duplicate(replace, (gate_string_t const*)gate_map_iterator_value(iter));
1082 ✗ ret = gate_string_length(ptr_str);
1083 ✗ break;
1084 }
1085 ✗ iter = gate_map_iterator_next(iter);
1086 }
1087
1088 } while (0);
1089
1090 ✗ gate_string_release(&var_name);
1091 ✗ return ret;
1092 }
1093
1094 ✗ gate_result_t gate_text_print_vars(gate_strbuilder_t* target, gate_string_t const* src, gate_map_t const* strmap)
1095 {
1096 ✗ gate_result_t ret = GATE_RESULT_OK;
1097 ✗ gate_size_t start_at = 0;
1098 gate_size_t match_pos;
1099 gate_size_t len;
1100 ✗ gate_size_t src_len = gate_string_length(src);
1101 ✗ char const* ptr = gate_string_ptr(src, 0);
1102 ✗ gate_string_t dollartoken = GATE_STRING_INIT_EMPTY;
1103 ✗ gate_string_t replacement = GATE_STRING_INIT_EMPTY;
1104
1105 for (;;)
1106 {
1107 ✗ match_pos = gate_string_char_pos(src, '$', start_at);
1108 ✗ if (match_pos == GATE_STR_NPOS)
1109 {
1110 /* no further occurance */
1111 ✗ len = src_len - start_at;
1112 ✗ if (len != gate_strbuilder_append_text(target, &ptr[start_at], len))
1113 {
1114 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1115 }
1116 ✗ break;
1117 }
1118
1119 ✗ len = match_pos - start_at;
1120 ✗ if (len != gate_strbuilder_append_text(target, &ptr[start_at], len))
1121 {
1122 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1123 ✗ break;
1124 }
1125 ✗ gate_string_substr(&dollartoken, src, match_pos + 1, src_len - match_pos - 1);
1126 ✗ len = gate_text_resolve_var(&dollartoken, strmap, &replacement);
1127 ✗ start_at = match_pos + 1 + len;
1128 ✗ if (len == 0)
1129 {
1130 ✗ if (1 != gate_strbuilder_append_chars(target, 1, '$'))
1131 {
1132 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1133 ✗ break;
1134 }
1135 }
1136 else
1137 {
1138 ✗ len = gate_strbuilder_append_string(target, &replacement);
1139 ✗ if (len != gate_string_length(&replacement))
1140 {
1141 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1142 ✗ break;
1143 }
1144 }
1145 ✗ gate_string_release(&dollartoken);
1146 ✗ gate_string_release(&replacement);
1147 }
1148 ✗ gate_string_release(&dollartoken);
1149 ✗ gate_string_release(&replacement);
1150
1151 ✗ return ret;
1152 }
1153
1154
1155
1156 ✗ gate_result_t gate_text_format_create(gate_text_formater_t* formater, gate_string_t const* format)
1157 {
1158 ✗ gate_result_t ret = GATE_RESULT_FAILED;
1159 ✗ gate_size_t len = gate_string_length(format);
1160 do
1161 {
1162 ✗ gate_mem_clear(formater, sizeof(gate_text_formater_t));
1163 ✗ gate_strbuilder_create(&formater->format, len * 4 / 3 + 2);
1164 ✗ if (len != gate_strbuilder_append_string(&formater->format, format))
1165 {
1166 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1167 ✗ break;
1168 }
1169 ✗ formater->counter = 0;
1170
1171 ✗ ret = GATE_RESULT_OK;
1172 } while (0);
1173 ✗ return ret;
1174 }
1175 ✗ gate_result_t gate_text_format_create_str(gate_text_formater_t* formater, char const* format)
1176 {
1177 ✗ gate_result_t ret = GATE_RESULT_FAILED;
1178 ✗ gate_size_t len = gate_str_length(format);
1179 do
1180 {
1181 ✗ gate_mem_clear(formater, sizeof(gate_text_formater_t));
1182 ✗ gate_strbuilder_create(&formater->format, len * 4 / 3 + 2);
1183 ✗ if (len != gate_strbuilder_append_text(&formater->format, format, len))
1184 {
1185 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1186 ✗ break;
1187 }
1188 ✗ formater->counter = 0;
1189
1190 ✗ ret = GATE_RESULT_OK;
1191 } while (0);
1192 ✗ return ret;
1193 }
1194 ✗ gate_result_t gate_text_format_destroy(gate_text_formater_t* formater)
1195 {
1196 ✗ if (formater)
1197 {
1198 ✗ gate_strbuilder_release(&formater->format);
1199 ✗ gate_mem_clear(formater, sizeof(gate_text_formater_t));
1200 }
1201 ✗ return GATE_RESULT_OK;
1202 }
1203
1204
1205 typedef gate_size_t(*gate_text_format_replacer_t)(
1206 gate_text_formater_t* formater, gate_size_t replace_at, gate_size_t replace_len,
1207 void const* replace_to, gate_string_t const* format_param);
1208
1209
1210 ✗ static gate_size_t gate_text_format_replace(gate_text_formater_t* formater, gate_text_format_replacer_t replacer, void const* replace_to)
1211 {
1212 ✗ gate_size_t ret = 0;
1213 static char const* end_chars = "}:{";
1214 static gate_size_t end_char_count = 3;
1215 //char token1[32] = GATE_INIT_EMPTY;
1216 //char token2[32] = GATE_INIT_EMPTY;
1217 ✗ gate_size_t start_at = 0;
1218 char const* format_ptr;
1219 gate_size_t format_len;
1220 gate_size_t pos;
1221 gate_size_t pos_end;
1222 ✗ gate_string_t replace_param = GATE_STRING_INIT_EMPTY;
1223 gate_size_t replaced_chars;
1224 gate_size_t total_end_pos;
1225 ✗ gate_bool_t continue_replacing = true;
1226 ✗ gate_uint64_t current_counter = formater->counter++;
1227 gate_uint64_t parsed_counter;
1228 gate_size_t len;
1229
1230 ✗ while (continue_replacing)
1231 {
1232 ✗ format_ptr = gate_strbuilder_ptr(&formater->format, 0);
1233 ✗ format_len = gate_strbuilder_length(&formater->format);
1234
1235 ✗ pos = gate_str_char_pos(format_ptr, format_len, '{', start_at);
1236 ✗ if (pos == GATE_STR_NPOS)
1237 {
1238 ✗ break;
1239 }
1240
1241 ✗ pos_end = gate_str_find_first_of(format_ptr, format_len, end_chars, end_char_count, pos + 1);
1242 ✗ if (pos == GATE_STR_NPOS)
1243 {
1244 ✗ break;
1245 }
1246
1247 ✗ start_at = pos_end; /* if parsing failed, just skip this token */
1248
1249 ✗ switch (format_ptr[pos_end])
1250 {
1251 ✗ case '}':
1252 {
1253 /* simple replace */
1254 ✗ len = pos_end - pos - 1;
1255 ✗ if (len == gate_str_parse_uint64(&format_ptr[pos + 1], len, &parsed_counter))
1256 {
1257 ✗ if (parsed_counter == current_counter)
1258 {
1259 ✗ gate_string_create_empty(&replace_param);
1260 ✗ replaced_chars = replacer(formater, pos, pos_end + 1 - pos, replace_to, &replace_param);
1261 ✗ ret += replaced_chars;
1262 ✗ start_at = pos + replaced_chars;
1263 }
1264 }
1265 ✗ break;
1266 }
1267 ✗ case ':':
1268 {
1269 /* formated replace */
1270 ✗ len = pos_end - pos - 1;
1271 ✗ if (len == gate_str_parse_uint64(&format_ptr[pos + 1], len, &parsed_counter))
1272 {
1273 ✗ if (parsed_counter == current_counter)
1274 {
1275 ✗ total_end_pos = gate_str_char_pos(format_ptr, format_len, '}', pos_end + 1);
1276 ✗ if (total_end_pos == GATE_STR_NPOS)
1277 {
1278 ✗ continue_replacing = false;
1279 ✗ break;
1280 }
1281 ✗ gate_string_create_static_len(&replace_param, &format_ptr[pos_end + 1], total_end_pos - pos_end - 1);
1282 ✗ replaced_chars = replacer(formater, pos, total_end_pos + 1 - pos, replace_to, &replace_param);
1283 ✗ ret += replaced_chars;
1284 ✗ start_at = pos + replaced_chars;
1285 ✗ gate_string_release(&replace_param);
1286 }
1287 }
1288 ✗ break;
1289 }
1290 ✗ case '{':
1291 {
1292 /* next replacement */
1293 ✗ start_at = pos_end;
1294 ✗ break;
1295 }
1296 }
1297 ✗ }
1298 ✗ return ret;
1299 }
1300
1301
1302
1303 ✗ static gate_size_t gate_text_format_string_impl(gate_text_formater_t* formater,
1304 gate_size_t replace_at, gate_size_t replace_len,
1305 void const* replace_to, gate_string_t const* format_param)
1306 {
1307 gate_size_t colon_pos;
1308 ✗ gate_int64_t substr_begin_at = 0;
1309 ✗ gate_int64_t substr_length = -1;
1310 ✗ gate_string_t const* ptr_value = (gate_string_t const*)replace_to;
1311 ✗ char const* ptr_text = gate_string_ptr(ptr_value, 0);
1312 ✗ gate_size_t len = gate_string_length(ptr_value);
1313
1314 do
1315 {
1316 ✗ if (gate_string_is_empty(format_param))
1317 {
1318 // no further substring formating required
1319 ✗ break;
1320 }
1321 ✗ colon_pos = gate_string_char_pos(format_param, ':', 0);
1322
1323 ✗ if (colon_pos == GATE_STR_NPOS)
1324 {
1325 ✗ gate_str_parse_int64(format_param->str, format_param->length, &substr_begin_at);
1326 }
1327 else
1328 {
1329 ✗ gate_str_parse_int64(&format_param->str[0], colon_pos, &substr_begin_at);
1330 ✗ gate_str_parse_int64(&format_param->str[colon_pos + 1], format_param->length - colon_pos - 1, &substr_length);
1331 }
1332 ✗ if (substr_begin_at < 0)
1333 {
1334 ✗ substr_begin_at = (gate_int64_t)len + substr_begin_at;
1335 ✗ if (substr_begin_at < 0)
1336 {
1337 ✗ substr_begin_at = 0;
1338 }
1339 }
1340 ✗ if (substr_begin_at >= (gate_int64_t)len)
1341 {
1342 /* replace with NOTHING */
1343 ✗ len = 0;
1344 ✗ break;
1345 }
1346 ✗ ptr_text = gate_string_ptr(ptr_value, (gate_size_t)substr_begin_at);
1347 ✗ len -= (gate_size_t)substr_begin_at;
1348
1349 ✗ if (substr_length < 0)
1350 {
1351 ✗ substr_length += (gate_int64_t)len + 1;
1352 ✗ if (substr_length <= 0)
1353 {
1354 /* replace with NOTHING */
1355 ✗ len = 0;
1356 ✗ break;
1357 }
1358 }
1359 ✗ if (substr_length > (gate_int64_t)len)
1360 {
1361 ✗ len = (gate_size_t)substr_length;
1362 }
1363 } while (0);
1364
1365 ✗ gate_strbuilder_replace(&formater->format, replace_at, replace_len, ptr_text, len);
1366 ✗ return len;
1367 }
1368 ✗ gate_result_t gate_text_format_text(gate_text_formater_t* formater, gate_string_t const* text)
1369 {
1370 ✗ gate_result_t ret = GATE_RESULT_OK;
1371 ✗ gate_size_t len = gate_text_format_replace(formater, &gate_text_format_string_impl, text);
1372 (void)len;
1373 ✗ return ret;
1374 }
1375 ✗ gate_result_t gate_text_format_str(gate_text_formater_t* formater, char const* str)
1376 {
1377 gate_result_t ret;
1378 ✗ gate_string_t tmp = GATE_STRING_INIT_EMPTY;
1379 ✗ gate_string_create_static(&tmp, str);
1380 ✗ ret = gate_text_format_text(formater, &tmp);
1381 ✗ gate_string_release(&tmp);
1382 ✗ return ret;
1383 }
1384
1385
1386
1387 ✗ static gate_size_t gate_text_format_int_impl(gate_text_formater_t* formater,
1388 gate_size_t replace_at, gate_size_t replace_len,
1389 void const* replace_to, gate_string_t const* format_param)
1390 {
1391 ✗ char buffer[64] = GATE_INIT_EMPTY;
1392 ✗ gate_int64_t const* ptr_value = (gate_int64_t const*)replace_to;
1393 ✗ gate_size_t len = gate_str_print_int64(buffer, sizeof(buffer), *ptr_value);
1394 /* TODO: format_param */
1395
1396 ✗ gate_strbuilder_replace(&formater->format, replace_at, replace_len, buffer, len);
1397 ✗ return len;
1398 }
1399 ✗ gate_result_t gate_text_format_int(gate_text_formater_t* formater, gate_int64_t num)
1400 {
1401 ✗ gate_result_t ret = GATE_RESULT_OK;
1402 ✗ gate_size_t len = gate_text_format_replace(formater, &gate_text_format_int_impl, &num);
1403 (void)len;
1404 ✗ return ret;
1405 }
1406
1407
1408
1409 ✗ static gate_size_t gate_text_format_real_impl(gate_text_formater_t* formater,
1410 gate_size_t replace_at, gate_size_t replace_len,
1411 void const* replace_to, gate_string_t const* format_param)
1412 {
1413 ✗ char buffer[128] = GATE_INIT_EMPTY;
1414 ✗ gate_real64_t const* ptr_value = (gate_real64_t const*)replace_to;
1415 ✗ unsigned int_len = 0;
1416 ✗ unsigned decimal_len = 0;
1417 ✗ unsigned group_len = 0;
1418 ✗ gate_size_t len = gate_str_print_real(buffer, sizeof(buffer), *ptr_value, int_len, decimal_len, group_len);
1419 /* TODO: format_param */
1420 ✗ gate_strbuilder_replace(&formater->format, replace_at, replace_len, buffer, len);
1421 ✗ return len;
1422 }
1423 ✗ gate_result_t gate_text_format_real(gate_text_formater_t* formater, gate_real64_t num)
1424 {
1425 ✗ gate_result_t ret = GATE_RESULT_OK;
1426 ✗ gate_size_t len = gate_text_format_replace(formater, &gate_text_format_real_impl, &num);
1427 (void)len;
1428 ✗ return ret;
1429 }
1430
1431
1432
1433 ✗ gate_result_t gate_text_format_vars(gate_text_formater_t* formater, ...)
1434 {
1435 ✗ gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
1436 ✗ return ret;
1437 }
1438
1439
1440 ✗ gate_result_t gate_text_format_extract(gate_text_formater_t const* formater, gate_string_t* output)
1441 {
1442 ✗ gate_result_t ret = GATE_RESULT_FAILED;
1443
1444 do
1445 {
1446 ✗ if (NULL == gate_strbuilder_copy_to_string(&formater->format, output))
1447 {
1448 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1449 ✗ break;
1450 }
1451 ✗ ret = GATE_RESULT_OK;
1452 } while (0);
1453 ✗ return ret;
1454 }
1455
1456
1457 ✗ gate_result_t gate_text_format_print(gate_text_formater_t* formater, gate_string_t* output)
1458 {
1459 ✗ gate_result_t ret = GATE_RESULT_FAILED;
1460
1461 do
1462 {
1463 ✗ if (NULL == gate_strbuilder_to_string(&formater->format, output))
1464 {
1465 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1466 ✗ break;
1467 }
1468 ✗ ret = GATE_RESULT_OK;
1469 } while (0);
1470 ✗ return ret;
1471 }
1472