eolib 0.5.0
A core C library for writing applications related to Endless Online
Loading...
Searching...
No Matches
data.c
Go to the documentation of this file.
1#include "eolib/data.h"
2#include "eolib/result.h"
3
4#include <limits.h>
5#include <stdlib.h>
6#include <string.h>
7#include <stdio.h>
8
9#if defined(_WIN32)
10#define strdup _strdup
11#endif
12
13static size_t eo_reader_next_break_index(const EoReader *reader);
14
15/*
16 * Unicode code points for Windows-1252 bytes 0x80-0x9F.
17 * Index 0 maps to byte 0x80, index 31 maps to byte 0x9F.
18 * A value of 0 means the byte is undefined in Windows-1252.
19 */
20static const uint32_t cp1252_unicode_extras[32] = {
21 0x20AC,
22 0,
23 0x201A,
24 0x0192,
25 0x201E,
26 0x2026,
27 0x2020,
28 0x2021,
29 0x02C6,
30 0x2030,
31 0x0160,
32 0x2039,
33 0x0152,
34 0,
35 0x017D,
36 0,
37 0,
38 0x2018,
39 0x2019,
40 0x201C,
41 0x201D,
42 0x2022,
43 0x2013,
44 0x2014,
45 0x02DC,
46 0x2122,
47 0x0161,
48 0x203A,
49 0x0153,
50 0,
51 0x017E,
52 0x0178,
53};
54
55static uint8_t unicode_to_cp1252(uint32_t codepoint)
56{
57 if (codepoint <= 0x7F)
58 return (uint8_t)codepoint;
59
60 if (codepoint >= 0xA0 && codepoint <= 0xFF)
61 return (uint8_t)codepoint;
62
63 for (int i = 0; i < 32; ++i)
64 {
65 if (cp1252_unicode_extras[i] == codepoint)
66 return (uint8_t)(0x80 + i);
67 }
68
69 return '?';
70}
71
72/*
73 * Converts a UTF-8 string to Windows-1252 in-place into `output`.
74 * `output` must be at least `input_len + 1` bytes.
75 * Returns the number of bytes written (excluding the null terminator).
76 * Valid UTF-8 multi-byte sequences are decoded and mapped to Windows-1252.
77 * Characters with no Windows-1252 representation are replaced with '?'.
78 * Bytes that do not form a valid UTF-8 sequence are passed through as-is.
79 */
80static size_t normalize_to_cp1252(const char *input, char *output, size_t input_len)
81{
82 size_t out_pos = 0;
83 size_t i = 0;
84
85 while (i < input_len)
86 {
87 uint8_t b0 = (uint8_t)input[i];
88
89 if (b0 < 0x80)
90 {
91 output[out_pos++] = (char)b0;
92 i++;
93 }
94 else if (b0 >= 0xC2 && b0 <= 0xDF && i + 1 < input_len)
95 {
96 uint8_t b1 = (uint8_t)input[i + 1];
97 if ((b1 & 0xC0) == 0x80)
98 {
99 uint32_t cp = ((uint32_t)(b0 & 0x1F) << 6) | (b1 & 0x3F);
100 output[out_pos++] = (char)unicode_to_cp1252(cp);
101 i += 2;
102 }
103 else
104 {
105 output[out_pos++] = (char)b0;
106 i++;
107 }
108 }
109 else if (b0 >= 0xE0 && b0 <= 0xEF && i + 2 < input_len)
110 {
111 uint8_t b1 = (uint8_t)input[i + 1];
112 uint8_t b2 = (uint8_t)input[i + 2];
113 if ((b1 & 0xC0) == 0x80 && (b2 & 0xC0) == 0x80)
114 {
115 uint32_t cp = ((uint32_t)(b0 & 0x0F) << 12) | ((uint32_t)(b1 & 0x3F) << 6) | (b2 & 0x3F);
116 output[out_pos++] = (char)unicode_to_cp1252(cp);
117 i += 3;
118 }
119 else
120 {
121 output[out_pos++] = (char)b0;
122 i++;
123 }
124 }
125 else if (b0 >= 0xF0 && b0 <= 0xF4 && i + 3 < input_len)
126 {
127 uint8_t b1 = (uint8_t)input[i + 1];
128 uint8_t b2 = (uint8_t)input[i + 2];
129 uint8_t b3 = (uint8_t)input[i + 3];
130 if ((b1 & 0xC0) == 0x80 && (b2 & 0xC0) == 0x80 && (b3 & 0xC0) == 0x80)
131 {
132 /* Code points above U+FFFF have no Windows-1252 representation. */
133 output[out_pos++] = '?';
134 i += 4;
135 }
136 else
137 {
138 output[out_pos++] = (char)b0;
139 i++;
140 }
141 }
142 else
143 {
144 /* Continuation byte in isolation, or other non-UTF-8 byte: treat as raw CP1252. */
145 output[out_pos++] = (char)b0;
146 i++;
147 }
148 }
149
150 output[out_pos] = '\0';
151 return out_pos;
152}
153
154EoResult eo_string_to_windows_1252(const char *value, char **out_value)
155{
156 if (!out_value)
157 return EO_NULL_PTR;
158
159 if (!value)
160 {
161 *out_value = NULL;
162 return EO_SUCCESS;
163 }
164
165 size_t in_len = strlen(value);
166 char *out = (char *)malloc(in_len + 1);
167 if (!out)
168 return EO_ALLOC_FAILED;
169
170 normalize_to_cp1252(value, out, in_len);
171 *out_value = out;
172 return EO_SUCCESS;
173}
174
175const char *eo_result_string(EoResult result)
176{
177 switch (result)
178 {
179 case EO_SUCCESS:
180 return "EO_SUCCESS: operation completed successfully";
181 case EO_NULL_PTR:
182 return "EO_NULL_PTR: a required pointer argument was NULL";
183 case EO_OVERFLOW:
184 return "EO_OVERFLOW: internal size calculation would overflow";
185 case EO_ALLOC_FAILED:
186 return "EO_ALLOC_FAILED: memory allocation failed";
188 return "EO_NUMBER_TOO_LARGE: numeric value exceeds EO encoding range";
190 return "EO_BUFFER_UNDERRUN: not enough bytes available for read";
192 return "EO_CHUNKED_MODE_DISABLED: chunked reading mode is not active";
194 return "EO_INVALID_SEQUENCE_RANGE: calculated sequence range is empty";
196 return "EO_SEQUENCE_OUT_OF_RANGE: sequence value out of encodable range";
197 case EO_INVALID_DATA:
198 return "EO_INVALID_DATA: data is structurally invalid";
200 return "EO_STR_OUT_OF_RANGE: string exceeds the allowed fixed length";
201 case EO_STR_TOO_SHORT:
202 return "EO_STR_TOO_SHORT: string is shorter than the required fixed length";
203 case EO_INVALID_CHAR:
204 return "EO_INVALID_CHAR: character value is outside the valid range";
205 case EO_INVALID_SHORT:
206 return "EO_INVALID_SHORT: short integer value is outside the valid range";
207 case EO_INVALID_THREE:
208 return "EO_INVALID_THREE: three-byte integer value is outside the valid range";
209 case EO_INVALID_INT:
210 return "EO_INVALID_INT: integer value is outside the valid range";
211 default:
212 return "unknown EoResult value";
213 }
214}
215
217{
219}
220
222{
223 EoWriter writer;
224 writer.string_sanitization_mode = false;
225 writer.length = 0;
226 writer.capacity = capacity;
227 writer.data = capacity > 0 ? (uint8_t *)malloc(capacity) : NULL;
228 return writer;
229}
230
232{
233 if (!writer)
234 {
235 return;
236 }
237 free(writer->data);
238 writer->data = NULL;
239 writer->length = 0;
240 writer->capacity = 0;
241}
242
243EoResult eo_writer_ensure_capacity(EoWriter *writer, size_t additional)
244{
245 if (!writer)
246 {
247 return EO_NULL_PTR;
248 }
249
250 if (SIZE_MAX - writer->length < additional)
251 {
252 return EO_OVERFLOW;
253 }
254
255 size_t required = writer->length + additional;
256 if (writer->capacity >= required)
257 {
258 return EO_SUCCESS;
259 }
260
261 size_t new_capacity = required == 0 ? 1 : required;
262 uint8_t *new_data = (uint8_t *)realloc(writer->data, new_capacity);
263 if (!new_data)
264 {
265 return EO_ALLOC_FAILED;
266 }
267
268 writer->data = new_data;
269 writer->capacity = new_capacity;
270 return EO_SUCCESS;
271}
272
273EoResult eo_encode_number(int32_t number, uint8_t out_bytes[4])
274{
275 if (!out_bytes)
276 {
277 return EO_NULL_PTR;
278 }
279
280 out_bytes[0] = EO_NUMBER_PADDING;
281 out_bytes[1] = EO_NUMBER_PADDING;
282 out_bytes[2] = EO_NUMBER_PADDING;
283 out_bytes[3] = EO_NUMBER_PADDING;
284
285 uint32_t value = (uint32_t)number;
286 uint32_t original = value;
287 if (original >= (uint32_t)EO_INT_MAX)
288 {
289 return EO_NUMBER_TOO_LARGE;
290 }
291
292 if (original >= (uint32_t)EO_THREE_MAX)
293 {
294 out_bytes[3] = (uint8_t)(value / (uint32_t)EO_THREE_MAX) + 1;
295 value %= (uint32_t)EO_THREE_MAX;
296 }
297
298 if (original >= (uint32_t)EO_SHORT_MAX)
299 {
300 out_bytes[2] = (uint8_t)(value / (uint32_t)EO_SHORT_MAX) + 1;
301 value %= (uint32_t)EO_SHORT_MAX;
302 }
303
304 if (original >= (uint32_t)EO_CHAR_MAX)
305 {
306 out_bytes[1] = (uint8_t)(value / (uint32_t)EO_CHAR_MAX) + 1;
307 value %= (uint32_t)EO_CHAR_MAX;
308 }
309
310 out_bytes[0] = (uint8_t)value + 1;
311 return EO_SUCCESS;
312}
313
314int32_t eo_decode_number(const uint8_t *bytes, size_t length)
315{
317
318 for (size_t i = 0; i < 4; ++i)
319 {
320 if (bytes && length > i && bytes[i] != 0)
321 {
322 data[i] = bytes[i];
323 }
324
325 if (data[i] == EO_NUMBER_PADDING)
326 {
327 data[i] = 1;
328 }
329
330 data[i] -= 1;
331 }
332
333 uint32_t result = (uint32_t)data[3] * (uint32_t)EO_THREE_MAX;
334 result += (uint32_t)data[2] * (uint32_t)EO_SHORT_MAX;
335 result += (uint32_t)data[1] * (uint32_t)EO_CHAR_MAX;
336 result += data[0];
337 return (int32_t)result;
338}
339
340void eo_decode_string(uint8_t *buf, size_t length)
341{
342 if (!buf || length == 0)
343 {
344 return;
345 }
346
347 for (size_t i = 0; i < length / 2; ++i)
348 {
349 uint8_t tmp = buf[i];
350 buf[i] = buf[length - 1 - i];
351 buf[length - 1 - i] = tmp;
352 }
353
354 size_t parity = (length + 1) % 2;
355 for (size_t i = 0; i < length; ++i)
356 {
357 uint8_t ch = buf[i];
358 int odd = ((i % 2) != parity);
359
360 if (odd && ch >= 34 && ch <= 125)
361 {
362 buf[i] = (uint8_t)(125 - ch + 34);
363 }
364 else if (!odd && ch >= 34 && ch <= 79)
365 {
366 buf[i] = (uint8_t)(79 - ch + 34);
367 }
368 else if (!odd && ch >= 80 && ch <= 125)
369 {
370 buf[i] = (uint8_t)(125 - ch + 80);
371 }
372 }
373}
374
375void eo_encode_string(uint8_t *buf, size_t length)
376{
377 if (!buf || length == 0)
378 {
379 return;
380 }
381
382 size_t parity = (length + 1) % 2;
383 for (size_t i = 0; i < length; ++i)
384 {
385 uint8_t ch = buf[i];
386 int odd = ((i % 2) != parity);
387
388 if (odd && ch >= 34 && ch <= 125)
389 {
390 buf[i] = (uint8_t)(125 - ch + 34);
391 }
392 else if (!odd && ch >= 34 && ch <= 79)
393 {
394 buf[i] = (uint8_t)(79 - ch + 34);
395 }
396 else if (!odd && ch >= 80 && ch <= 125)
397 {
398 buf[i] = (uint8_t)(125 - ch + 80);
399 }
400 }
401
402 for (size_t i = 0; i < length / 2; ++i)
403 {
404 uint8_t tmp = buf[i];
405 buf[i] = buf[length - 1 - i];
406 buf[length - 1 - i] = tmp;
407 }
408}
409
411{
412 return writer ? writer->string_sanitization_mode : false;
413}
414
416{
417 if (writer)
418 {
419 writer->string_sanitization_mode = enabled;
420 }
421}
422
423EoResult eo_writer_add_byte(EoWriter *writer, uint8_t value)
424{
425 if (!writer)
426 {
427 return EO_NULL_PTR;
428 }
429
430 EoResult result;
431 if ((result = eo_writer_ensure_capacity(writer, 1)) != EO_SUCCESS)
432 {
433 return result;
434 }
435
436 writer->data[writer->length++] = value;
437 return EO_SUCCESS;
438}
439
440EoResult eo_writer_add_char(EoWriter *writer, int32_t value)
441{
442 if (!writer)
443 {
444 return EO_NULL_PTR;
445 }
446
447 if (value < 0 || value > EO_CHAR_MAX)
448 {
449 return EO_INVALID_CHAR;
450 }
451
452 EoResult result;
453 if ((result = eo_writer_ensure_capacity(writer, 1)) != EO_SUCCESS)
454 {
455 return result;
456 }
457
458 uint8_t bytes[4];
459 if ((result = eo_encode_number(value, bytes)) != EO_SUCCESS)
460 {
461 return result;
462 }
463
464 writer->data[writer->length++] = bytes[0];
465
466 return EO_SUCCESS;
467}
468
469EoResult eo_writer_add_short(EoWriter *writer, int32_t value)
470{
471 if (!writer)
472 {
473 return EO_NULL_PTR;
474 }
475
476 if (value < 0 || value > EO_SHORT_MAX)
477 {
478 return EO_INVALID_SHORT;
479 }
480
481 EoResult result;
482 if ((result = eo_writer_ensure_capacity(writer, 2)) != EO_SUCCESS)
483 {
484 return result;
485 }
486
487 uint8_t bytes[4];
488 if ((result = eo_encode_number(value, bytes)) != EO_SUCCESS)
489 {
490 return result;
491 }
492
493 writer->data[writer->length++] = bytes[0];
494 writer->data[writer->length++] = bytes[1];
495
496 return EO_SUCCESS;
497}
498
499EoResult eo_writer_add_three(EoWriter *writer, int32_t value)
500{
501 if (!writer)
502 {
503 return EO_NULL_PTR;
504 }
505
506 if (value < 0 || value > EO_THREE_MAX)
507 {
508 return EO_INVALID_THREE;
509 }
510
511 EoResult result;
512 if ((result = eo_writer_ensure_capacity(writer, 3)) != EO_SUCCESS)
513 {
514 return result;
515 }
516
517 uint8_t bytes[4];
518 if ((result = eo_encode_number(value, bytes)) != EO_SUCCESS)
519 {
520 return result;
521 }
522
523 writer->data[writer->length++] = bytes[0];
524 writer->data[writer->length++] = bytes[1];
525 writer->data[writer->length++] = bytes[2];
526 return EO_SUCCESS;
527}
528
529EoResult eo_writer_add_int(EoWriter *writer, int32_t value)
530{
531 if (!writer)
532 {
533 return EO_NULL_PTR;
534 }
535
536 if (value < 0 && (uint32_t)value >= (uint32_t)EO_INT_MAX)
537 {
538 return EO_INVALID_INT;
539 }
540
541 EoResult result;
542 if ((result = eo_writer_ensure_capacity(writer, 4)) != EO_SUCCESS)
543 {
544 return result;
545 }
546
547 uint8_t bytes[4];
548 if ((result = eo_encode_number(value, bytes)) != EO_SUCCESS)
549 {
550 return result;
551 }
552
553 writer->data[writer->length++] = bytes[0];
554 writer->data[writer->length++] = bytes[1];
555 writer->data[writer->length++] = bytes[2];
556 writer->data[writer->length++] = bytes[3];
557
558 return EO_SUCCESS;
559}
560
561EoResult eo_writer_add_string(EoWriter *writer, const char *value)
562{
563 if (!writer)
564 {
565 return EO_NULL_PTR;
566 }
567
568 // Ignore NULL strings, treat them as empty strings
569 if (!value)
570 {
571 return EO_SUCCESS;
572 }
573
574 size_t in_len = strlen(value);
575 char *normalized = (char *)malloc(in_len + 1);
576 if (!normalized)
577 {
578 return EO_ALLOC_FAILED;
579 }
580 size_t length = normalize_to_cp1252(value, normalized, in_len);
581
582 EoResult result;
583 if ((result = eo_writer_ensure_capacity(writer, length)) != EO_SUCCESS)
584 {
585 free(normalized);
586 return result;
587 }
588
589 if (writer->string_sanitization_mode)
590 {
591 for (size_t k = 0; k < length; ++k)
592 {
593 writer->data[writer->length++] =
594 (normalized[k] == (char)EO_BREAK_BYTE) ? 0x79 : (uint8_t)normalized[k];
595 }
596 }
597 else
598 {
599 memcpy(writer->data + writer->length, normalized, length);
600 writer->length += length;
601 }
602
603 free(normalized);
604 return EO_SUCCESS;
605}
606
608{
609 if (!writer)
610 {
611 return EO_NULL_PTR;
612 }
613
614 // Ignore NULL strings, treat them as empty strings
615 if (!value)
616 {
617 return EO_SUCCESS;
618 }
619
620 size_t in_len = strlen(value);
621 char *normalized = (char *)malloc(in_len + 1);
622 if (!normalized)
623 {
624 return EO_ALLOC_FAILED;
625 }
626 size_t length = normalize_to_cp1252(value, normalized, in_len);
627
628 EoResult result;
629 if ((result = eo_writer_ensure_capacity(writer, length)) != EO_SUCCESS)
630 {
631 free(normalized);
632 return result;
633 }
634
635 uint8_t *encoded = (uint8_t *)malloc(length);
636 if (!encoded)
637 {
638 free(normalized);
639 return EO_ALLOC_FAILED;
640 }
641
642 if (writer->string_sanitization_mode)
643 {
644 for (size_t k = 0; k < length; ++k)
645 {
646 encoded[k] = (normalized[k] == (char)EO_BREAK_BYTE) ? 0x79 : (uint8_t)normalized[k];
647 }
648 }
649 else
650 {
651 memcpy(encoded, normalized, length);
652 }
653
654 free(normalized);
655
656 eo_encode_string(encoded, length);
657 memcpy(writer->data + writer->length, encoded, length);
658 writer->length += length;
659
660 free(encoded);
661
662 return EO_SUCCESS;
663}
664
665EoResult eo_writer_add_fixed_string(EoWriter *writer, const char *value, size_t length, bool padded)
666{
667 if (!writer)
668 {
669 return EO_NULL_PTR;
670 }
671
672 // Ignore NULL strings, treat them as empty strings
673 if (!value)
674 {
675 return EO_SUCCESS;
676 }
677
678 size_t in_len = strlen(value);
679 char *normalized = (char *)malloc(in_len + 1);
680 if (!normalized)
681 {
682 return EO_ALLOC_FAILED;
683 }
684 size_t value_len = normalize_to_cp1252(value, normalized, in_len);
685
686 if (padded && value_len > length)
687 {
688 free(normalized);
689 return EO_STR_OUT_OF_RANGE;
690 }
691
692 if (!padded && value_len != length)
693 {
694 free(normalized);
695 return EO_STR_TOO_SHORT;
696 }
697
698 EoResult result;
699 if ((result = eo_writer_ensure_capacity(writer, length)) != EO_SUCCESS)
700 {
701 free(normalized);
702 return result;
703 }
704
705 if (writer->string_sanitization_mode)
706 {
707 for (size_t k = 0; k < value_len; ++k)
708 {
709 writer->data[writer->length++] =
710 (normalized[k] == (char)EO_BREAK_BYTE) ? 0x79 : (uint8_t)normalized[k];
711 }
712 }
713 else
714 {
715 size_t to_copy = padded ? value_len : length;
716 memcpy(writer->data + writer->length, normalized, to_copy);
717 writer->length += to_copy;
718 }
719
720 free(normalized);
721
722 if (padded)
723 {
724 size_t remaining = length > value_len ? length - value_len : 0;
725 for (size_t i = 0; i < remaining; ++i)
726 {
727 writer->data[writer->length++] = EO_BREAK_BYTE;
728 }
729 }
730
731 return EO_SUCCESS;
732}
733
734EoResult eo_writer_add_fixed_encoded_string(EoWriter *writer, const char *value, size_t length, bool padded)
735{
736 if (!writer)
737 {
738 return EO_NULL_PTR;
739 }
740
741 // Ignore NULL strings, treat them as empty strings
742 if (!value)
743 {
744 return EO_SUCCESS;
745 }
746
747 size_t in_len = strlen(value);
748 char *normalized = (char *)malloc(in_len + 1);
749 if (!normalized)
750 {
751 return EO_ALLOC_FAILED;
752 }
753 size_t value_len = normalize_to_cp1252(value, normalized, in_len);
754
755 if (padded && value_len > length)
756 {
757 free(normalized);
758 return EO_STR_OUT_OF_RANGE;
759 }
760
761 if (!padded && value_len != length)
762 {
763 free(normalized);
764 return EO_STR_TOO_SHORT;
765 }
766
767 EoResult result;
768 if ((result = eo_writer_ensure_capacity(writer, length)) != EO_SUCCESS)
769 {
770 free(normalized);
771 return result;
772 }
773
774 uint8_t *encoded = (uint8_t *)malloc(length);
775 if (!encoded)
776 {
777 free(normalized);
778 return EO_ALLOC_FAILED;
779 }
780
781 if (writer->string_sanitization_mode)
782 {
783 for (size_t k = 0; k < value_len; ++k)
784 {
785 encoded[k] = (normalized[k] == (char)EO_BREAK_BYTE) ? 0x79 : (uint8_t)normalized[k];
786 }
787 }
788 else
789 {
790 size_t to_copy = padded ? value_len : length;
791 memcpy(encoded, normalized, to_copy);
792 }
793
794 free(normalized);
795
796 if (padded)
797 {
798 size_t remaining = length > value_len ? length - value_len : 0;
799 for (size_t i = 0; i < remaining; ++i)
800 {
801 encoded[value_len + i] = EO_BREAK_BYTE;
802 }
803 }
804
805 eo_encode_string(encoded, length);
806
807 memcpy(writer->data + writer->length, encoded, length);
808 writer->length += length;
809
810 free(encoded);
811
812 return EO_SUCCESS;
813}
814
815EoResult eo_writer_add_bytes(EoWriter *writer, const uint8_t *data, size_t length)
816{
817 if (!writer || !data)
818 {
819 return EO_NULL_PTR;
820 }
821
822 EoResult result;
823 if ((result = eo_writer_ensure_capacity(writer, length)) != EO_SUCCESS)
824 {
825 return result;
826 }
827
828 memcpy(writer->data + writer->length, data, length);
829 writer->length += length;
830
831 return EO_SUCCESS;
832}
833
834EoReader eo_reader_init(const uint8_t *data, size_t length)
835{
836 EoReader reader;
837 reader.data = data;
838 reader.length = length;
839 reader.offset = 0;
840 reader.chunked_reading_mode = false;
841 reader.chunk_offset = 0;
842 reader.next_chunk_offset = 0;
843 return reader;
844}
845
847{
848 return reader ? reader->chunked_reading_mode : false;
849}
850
852{
853 if (reader)
854 {
855 reader->chunked_reading_mode = enabled;
856 if (!reader->next_chunk_offset)
857 {
859 }
860 }
861}
862
863size_t eo_reader_remaining(const EoReader *reader)
864{
865 if (!reader)
866 {
867 return 0;
868 }
869
870 if (reader->offset >= reader->length)
871 {
872 return 0;
873 }
874
875 if (reader->chunked_reading_mode)
876 {
877 size_t next_break = reader->next_chunk_offset;
878 if (next_break < reader->offset)
879 {
880 return 0;
881 }
882
883 return next_break - reader->offset;
884 }
885
886 return reader->length - reader->offset;
887}
888
890{
891 if (!reader)
892 {
893 return EO_NULL_PTR;
894 }
895
896 if (!reader->chunked_reading_mode)
897 {
899 }
900
901 reader->offset = reader->next_chunk_offset;
902 if (reader->offset < reader->length)
903 {
904 reader->offset += 1; // Skip the EO_BREAK_BYTE break byte
905 }
906
907 reader->chunk_offset = reader->offset;
909
910 return EO_SUCCESS;
911}
912
913static size_t eo_reader_next_break_index(const EoReader *reader)
914{
915 if (!reader || !reader->chunked_reading_mode)
916 {
917 return reader ? reader->length : 0;
918 }
919
920 for (size_t i = reader->chunk_offset; i < reader->length; ++i)
921 {
922 if (reader->data[i] == (uint8_t)EO_BREAK_BYTE)
923 {
924 return i;
925 }
926 }
927
928 return reader->length;
929}
930
931EoResult eo_reader_get_byte(EoReader *reader, uint8_t *out_value)
932{
933 if (!reader || !out_value)
934 {
935 return EO_NULL_PTR;
936 }
937
938 if (reader->offset > reader->length || reader->length - reader->offset < 1)
939 {
940 if (reader->chunked_reading_mode)
941 {
942 *out_value = 0;
943 return EO_SUCCESS;
944 }
945
946 return EO_BUFFER_UNDERRUN;
947 }
948
949 uint8_t value = reader->data[reader->offset++];
950 if (out_value)
951 {
952 *out_value = value;
953 }
954
955 return EO_SUCCESS;
956}
957
958EoResult eo_reader_get_char(EoReader *reader, int32_t *out_value)
959{
960 if (!reader || !out_value)
961 {
962 return EO_NULL_PTR;
963 }
964
965 if (reader->offset > reader->length || reader->length - reader->offset < 1)
966 {
967 if (reader->chunked_reading_mode)
968 {
969 *out_value = 0;
970 return EO_SUCCESS;
971 }
972
973 return EO_BUFFER_UNDERRUN;
974 }
975
976 uint8_t bytes[1] = {reader->data[reader->offset++]};
977 if (out_value)
978 {
979 *out_value = eo_decode_number(bytes, 1);
980 }
981
982 return EO_SUCCESS;
983}
984
985EoResult eo_reader_get_short(EoReader *reader, int32_t *out_value)
986{
987 if (!reader || !out_value)
988 {
989 return EO_NULL_PTR;
990 }
991
992 if (reader->offset > reader->length || reader->length - reader->offset < 2)
993 {
994 if (reader->chunked_reading_mode)
995 {
996 *out_value = 0;
997 return EO_SUCCESS;
998 }
999
1000 return EO_BUFFER_UNDERRUN;
1001 }
1002
1003 uint8_t bytes[2] = {reader->data[reader->offset++], reader->data[reader->offset++]};
1004 if (out_value)
1005 {
1006 *out_value = eo_decode_number(bytes, 2);
1007 }
1008
1009 return EO_SUCCESS;
1010}
1011
1012EoResult eo_reader_get_three(EoReader *reader, int32_t *out_value)
1013{
1014 if (!reader || !out_value)
1015 {
1016 return EO_NULL_PTR;
1017 }
1018
1019 if (reader->offset > reader->length || reader->length - reader->offset < 3)
1020 {
1021 if (reader->chunked_reading_mode)
1022 {
1023 *out_value = 0;
1024 return EO_SUCCESS;
1025 }
1026
1027 return EO_BUFFER_UNDERRUN;
1028 }
1029
1030 uint8_t bytes[3] = {
1031 reader->data[reader->offset++],
1032 reader->data[reader->offset++],
1033 reader->data[reader->offset++]};
1034 if (out_value)
1035 {
1036 *out_value = eo_decode_number(bytes, 3);
1037 }
1038
1039 return EO_SUCCESS;
1040}
1041
1042EoResult eo_reader_get_int(EoReader *reader, int32_t *out_value)
1043{
1044 if (!reader || !out_value)
1045 {
1046 return EO_NULL_PTR;
1047 }
1048
1049 if (reader->offset > reader->length || reader->length - reader->offset < 4)
1050 {
1051 if (reader->chunked_reading_mode)
1052 {
1053 *out_value = 0;
1054 return EO_SUCCESS;
1055 }
1056
1057 return EO_BUFFER_UNDERRUN;
1058 }
1059
1060 uint8_t bytes[4] = {
1061 reader->data[reader->offset++],
1062 reader->data[reader->offset++],
1063 reader->data[reader->offset++],
1064 reader->data[reader->offset++]};
1065 if (out_value)
1066 {
1067 *out_value = eo_decode_number(bytes, 4);
1068 }
1069
1070 return EO_SUCCESS;
1071}
1072
1073EoResult eo_reader_get_string(EoReader *reader, char **out_value)
1074{
1075 if (!reader || !out_value)
1076 {
1077 return EO_NULL_PTR;
1078 }
1079
1080 size_t length = eo_reader_remaining(reader);
1081 if (length == 0)
1082 {
1083 *out_value = strdup("");
1084 return EO_SUCCESS;
1085 }
1086
1087 return eo_reader_get_fixed_string(reader, length, out_value);
1088}
1089
1091{
1092 if (!reader || !out_value)
1093 {
1094 return EO_NULL_PTR;
1095 }
1096
1097 size_t length = eo_reader_remaining(reader);
1098 if (length == 0)
1099 {
1100 *out_value = strdup("");
1101 return EO_SUCCESS;
1102 }
1103
1104 return eo_reader_get_fixed_encoded_string(reader, length, out_value);
1105}
1106
1107EoResult eo_reader_get_fixed_string(EoReader *reader, size_t length, char **out_value)
1108{
1109 if (!reader || !out_value)
1110 {
1111 return EO_NULL_PTR;
1112 }
1113
1114 if (reader->offset > reader->length ||
1115 reader->length - reader->offset < length)
1116 {
1117 if (reader->chunked_reading_mode)
1118 {
1119 *out_value = strdup("");
1120 return EO_SUCCESS;
1121 }
1122
1123 return EO_BUFFER_UNDERRUN;
1124 }
1125
1126 *out_value = (char *)malloc(length + 1);
1127 if (!*out_value)
1128 {
1129 return EO_ALLOC_FAILED;
1130 }
1131
1132 memcpy(*out_value, reader->data + reader->offset, length);
1133 (*out_value)[length] = '\0';
1134 reader->offset += length;
1135 return EO_SUCCESS;
1136}
1137
1138EoResult eo_reader_get_fixed_encoded_string(EoReader *reader, size_t length, char **out_value)
1139{
1140 if (!reader || !out_value)
1141 {
1142 return EO_NULL_PTR;
1143 }
1144
1145 if (reader->offset > reader->length || reader->length - reader->offset < length)
1146 {
1147 if (reader->chunked_reading_mode)
1148 {
1149 *out_value = strdup("");
1150 return EO_SUCCESS;
1151 }
1152
1153 return EO_BUFFER_UNDERRUN;
1154 }
1155
1156 *out_value = (char *)malloc(length + 1);
1157 if (!*out_value)
1158 {
1159 return EO_ALLOC_FAILED;
1160 }
1161
1162 memcpy(*out_value, reader->data + reader->offset, length);
1163 eo_decode_string((uint8_t *)*out_value, length);
1164 (*out_value)[length] = '\0';
1165 reader->offset += length;
1166 return EO_SUCCESS;
1167}
1168
1169EoResult eo_reader_get_bytes(EoReader *reader, size_t length, uint8_t **out_value)
1170{
1171 if (!reader || !out_value)
1172 {
1173 return EO_NULL_PTR;
1174 }
1175
1176 if (reader->offset > reader->length || reader->length - reader->offset < length)
1177 {
1178 if (reader->chunked_reading_mode)
1179 {
1180 *out_value = NULL;
1181 return EO_SUCCESS;
1182 }
1183
1184 return EO_BUFFER_UNDERRUN;
1185 }
1186
1187 *out_value = (uint8_t *)malloc(length);
1188 if (!*out_value)
1189 {
1190 return EO_ALLOC_FAILED;
1191 }
1192
1193 memcpy(*out_value, reader->data + reader->offset, length);
1194 reader->offset += length;
1195 return EO_SUCCESS;
1196}
EoResult eo_writer_add_string(EoWriter *writer, const char *value)
Definition data.c:561
static const uint32_t cp1252_unicode_extras[32]
Definition data.c:20
EoResult eo_string_to_windows_1252(const char *value, char **out_value)
Definition data.c:154
EoResult eo_reader_get_fixed_encoded_string(EoReader *reader, size_t length, char **out_value)
Definition data.c:1138
bool eo_reader_get_chunked_reading_mode(const EoReader *reader)
Definition data.c:846
EoResult eo_reader_get_string(EoReader *reader, char **out_value)
Definition data.c:1073
EoResult eo_reader_get_encoded_string(EoReader *reader, char **out_value)
Definition data.c:1090
EoResult eo_writer_add_encoded_string(EoWriter *writer, const char *value)
Definition data.c:607
EoResult eo_writer_add_fixed_string(EoWriter *writer, const char *value, size_t length, bool padded)
Definition data.c:665
EoResult eo_reader_get_int(EoReader *reader, int32_t *out_value)
Definition data.c:1042
int32_t eo_decode_number(const uint8_t *bytes, size_t length)
Definition data.c:314
EoResult eo_writer_add_byte(EoWriter *writer, uint8_t value)
Definition data.c:423
EoWriter eo_writer_init_with_capacity(size_t capacity)
Definition data.c:221
static size_t eo_reader_next_break_index(const EoReader *reader)
Definition data.c:913
EoResult eo_reader_get_short(EoReader *reader, int32_t *out_value)
Definition data.c:985
const char * eo_result_string(EoResult result)
Definition data.c:175
void eo_reader_set_chunked_reading_mode(EoReader *reader, bool enabled)
Definition data.c:851
EoResult eo_reader_next_chunk(EoReader *reader)
Definition data.c:889
static uint8_t unicode_to_cp1252(uint32_t codepoint)
Definition data.c:55
EoResult eo_reader_get_char(EoReader *reader, int32_t *out_value)
Definition data.c:958
static size_t normalize_to_cp1252(const char *input, char *output, size_t input_len)
Definition data.c:80
EoResult eo_writer_add_short(EoWriter *writer, int32_t value)
Definition data.c:469
void eo_encode_string(uint8_t *buf, size_t length)
Definition data.c:375
EoResult eo_writer_add_bytes(EoWriter *writer, const uint8_t *data, size_t length)
Definition data.c:815
bool eo_writer_get_string_sanitization_mode(const EoWriter *writer)
Definition data.c:410
EoResult eo_writer_add_char(EoWriter *writer, int32_t value)
Definition data.c:440
EoResult eo_writer_ensure_capacity(EoWriter *writer, size_t additional)
Definition data.c:243
EoWriter eo_writer_init(void)
Definition data.c:216
EoResult eo_reader_get_three(EoReader *reader, int32_t *out_value)
Definition data.c:1012
EoResult eo_writer_add_three(EoWriter *writer, int32_t value)
Definition data.c:499
EoResult eo_writer_add_int(EoWriter *writer, int32_t value)
Definition data.c:529
EoResult eo_writer_add_fixed_encoded_string(EoWriter *writer, const char *value, size_t length, bool padded)
Definition data.c:734
void eo_writer_free(EoWriter *writer)
Definition data.c:231
EoReader eo_reader_init(const uint8_t *data, size_t length)
Definition data.c:834
void eo_decode_string(uint8_t *buf, size_t length)
Definition data.c:340
EoResult eo_reader_get_bytes(EoReader *reader, size_t length, uint8_t **out_value)
Definition data.c:1169
void eo_writer_set_string_sanitization_mode(EoWriter *writer, bool enabled)
Definition data.c:415
size_t eo_reader_remaining(const EoReader *reader)
Definition data.c:863
EoResult eo_reader_get_fixed_string(EoReader *reader, size_t length, char **out_value)
Definition data.c:1107
EoResult eo_encode_number(int32_t number, uint8_t out_bytes[4])
Definition data.c:273
EoResult eo_reader_get_byte(EoReader *reader, uint8_t *out_value)
Definition data.c:931
#define EO_NUMBER_PADDING
Definition data.h:19
#define EO_BREAK_BYTE
Definition data.h:21
#define EO_CHAR_MAX
Definition data.h:11
#define EO_THREE_MAX
Definition data.h:15
#define EO_SHORT_MAX
Definition data.h:13
#define EO_INT_MAX
Definition data.h:17
EoResult
Definition result.h:12
@ EO_NULL_PTR
Definition result.h:22
@ EO_INVALID_INT
Definition result.h:137
@ EO_INVALID_SHORT
Definition result.h:121
@ EO_OVERFLOW
Definition result.h:30
@ EO_INVALID_CHAR
Definition result.h:113
@ EO_INVALID_THREE
Definition result.h:129
@ EO_BUFFER_UNDERRUN
Definition result.h:55
@ EO_INVALID_SEQUENCE_RANGE
Definition result.h:72
@ EO_SEQUENCE_OUT_OF_RANGE
Definition result.h:80
@ EO_INVALID_DATA
Definition result.h:89
@ EO_STR_TOO_SHORT
Definition result.h:105
@ EO_ALLOC_FAILED
Definition result.h:38
@ EO_NUMBER_TOO_LARGE
Definition result.h:47
@ EO_SUCCESS
Definition result.h:14
@ EO_CHUNKED_MODE_DISABLED
Definition result.h:63
@ EO_STR_OUT_OF_RANGE
Definition result.h:97
size_t next_chunk_offset
Definition data.h:40
size_t offset
Definition data.h:37
size_t chunk_offset
Definition data.h:39
const uint8_t * data
Definition data.h:35
size_t length
Definition data.h:36
bool chunked_reading_mode
Definition data.h:38
bool string_sanitization_mode
Definition data.h:28
size_t length
Definition data.h:27
size_t capacity
Definition data.h:29
uint8_t * data
Definition data.h:26