GCC Code Coverage Report


Directory: src/gate/
File: src/gate/encode/texts.c
Date: 2025-09-14 13:10:38
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