57 if (codepoint <= 0x7F)
58 return (uint8_t)codepoint;
60 if (codepoint >= 0xA0 && codepoint <= 0xFF)
61 return (uint8_t)codepoint;
63 for (
int i = 0; i < 32; ++i)
66 return (uint8_t)(0x80 + i);
87 uint8_t b0 = (uint8_t)input[i];
91 output[out_pos++] = (char)b0;
94 else if (b0 >= 0xC2 && b0 <= 0xDF && i + 1 < input_len)
96 uint8_t b1 = (uint8_t)input[i + 1];
97 if ((b1 & 0xC0) == 0x80)
99 uint32_t cp = ((uint32_t)(b0 & 0x1F) << 6) | (b1 & 0x3F);
105 output[out_pos++] = (char)b0;
109 else if (b0 >= 0xE0 && b0 <= 0xEF && i + 2 < input_len)
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)
115 uint32_t cp = ((uint32_t)(b0 & 0x0F) << 12) | ((uint32_t)(b1 & 0x3F) << 6) | (b2 & 0x3F);
121 output[out_pos++] = (char)b0;
125 else if (b0 >= 0xF0 && b0 <= 0xF4 && i + 3 < input_len)
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)
133 output[out_pos++] =
'?';
138 output[out_pos++] = (char)b0;
145 output[out_pos++] = (char)b0;
150 output[out_pos] =
'\0';
165 size_t in_len = strlen(value);
166 char *out = (
char *)malloc(in_len + 1);
180 return "EO_SUCCESS: operation completed successfully";
182 return "EO_NULL_PTR: a required pointer argument was NULL";
184 return "EO_OVERFLOW: internal size calculation would overflow";
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";
198 return "EO_INVALID_DATA: data is structurally invalid";
200 return "EO_STR_OUT_OF_RANGE: string exceeds the allowed fixed length";
202 return "EO_STR_TOO_SHORT: string is shorter than the required fixed length";
204 return "EO_INVALID_CHAR: character value is outside the valid range";
206 return "EO_INVALID_SHORT: short integer value is outside the valid range";
208 return "EO_INVALID_THREE: three-byte integer value is outside the valid range";
210 return "EO_INVALID_INT: integer value is outside the valid range";
212 return "unknown EoResult value";
227 writer.
data = capacity > 0 ? (uint8_t *)malloc(capacity) : NULL;
250 if (SIZE_MAX - writer->
length < additional)
255 size_t required = writer->
length + additional;
261 size_t new_capacity = required == 0 ? 1 : required;
262 uint8_t *new_data = (uint8_t *)realloc(writer->
data, new_capacity);
268 writer->
data = new_data;
285 uint32_t value = (uint32_t)number;
286 uint32_t original = value;
294 out_bytes[3] = (uint8_t)(value / (uint32_t)
EO_THREE_MAX) + 1;
300 out_bytes[2] = (uint8_t)(value / (uint32_t)
EO_SHORT_MAX) + 1;
306 out_bytes[1] = (uint8_t)(value / (uint32_t)
EO_CHAR_MAX) + 1;
310 out_bytes[0] = (uint8_t)value + 1;
318 for (
size_t i = 0; i < 4; ++i)
320 if (bytes && length > i && bytes[i] != 0)
333 uint32_t result = (uint32_t)data[3] * (uint32_t)
EO_THREE_MAX;
335 result += (uint32_t)data[1] * (uint32_t)
EO_CHAR_MAX;
337 return (int32_t)result;
342 if (!buf || length == 0)
347 for (
size_t i = 0; i < length / 2; ++i)
349 uint8_t tmp = buf[i];
350 buf[i] = buf[length - 1 - i];
351 buf[length - 1 - i] = tmp;
354 size_t parity = (length + 1) % 2;
355 for (
size_t i = 0; i < length; ++i)
358 int odd = ((i % 2) != parity);
360 if (odd && ch >= 34 && ch <= 125)
362 buf[i] = (uint8_t)(125 - ch + 34);
364 else if (!odd && ch >= 34 && ch <= 79)
366 buf[i] = (uint8_t)(79 - ch + 34);
368 else if (!odd && ch >= 80 && ch <= 125)
370 buf[i] = (uint8_t)(125 - ch + 80);
377 if (!buf || length == 0)
382 size_t parity = (length + 1) % 2;
383 for (
size_t i = 0; i < length; ++i)
386 int odd = ((i % 2) != parity);
388 if (odd && ch >= 34 && ch <= 125)
390 buf[i] = (uint8_t)(125 - ch + 34);
392 else if (!odd && ch >= 34 && ch <= 79)
394 buf[i] = (uint8_t)(79 - ch + 34);
396 else if (!odd && ch >= 80 && ch <= 125)
398 buf[i] = (uint8_t)(125 - ch + 80);
402 for (
size_t i = 0; i < length / 2; ++i)
404 uint8_t tmp = buf[i];
405 buf[i] = buf[length - 1 - i];
406 buf[length - 1 - i] = tmp;
536 if (value < 0 && (uint32_t)value >= (uint32_t)
EO_INT_MAX)
574 size_t in_len = strlen(value);
575 char *normalized = (
char *)malloc(in_len + 1);
591 for (
size_t k = 0; k < length; ++k)
594 (normalized[k] == (char)
EO_BREAK_BYTE) ? 0x79 : (uint8_t)normalized[k];
599 memcpy(writer->
data + writer->
length, normalized, length);
620 size_t in_len = strlen(value);
621 char *normalized = (
char *)malloc(in_len + 1);
635 uint8_t *encoded = (uint8_t *)malloc(length);
644 for (
size_t k = 0; k < length; ++k)
646 encoded[k] = (normalized[k] == (char)
EO_BREAK_BYTE) ? 0x79 : (uint8_t)normalized[k];
651 memcpy(encoded, normalized, length);
657 memcpy(writer->
data + writer->
length, encoded, length);
678 size_t in_len = strlen(value);
679 char *normalized = (
char *)malloc(in_len + 1);
686 if (padded && value_len > length)
692 if (!padded && value_len != length)
707 for (
size_t k = 0; k < value_len; ++k)
710 (normalized[k] == (char)
EO_BREAK_BYTE) ? 0x79 : (uint8_t)normalized[k];
715 size_t to_copy = padded ? value_len : length;
716 memcpy(writer->
data + writer->
length, normalized, to_copy);
717 writer->
length += to_copy;
724 size_t remaining = length > value_len ? length - value_len : 0;
725 for (
size_t i = 0; i < remaining; ++i)
747 size_t in_len = strlen(value);
748 char *normalized = (
char *)malloc(in_len + 1);
755 if (padded && value_len > length)
761 if (!padded && value_len != length)
774 uint8_t *encoded = (uint8_t *)malloc(length);
783 for (
size_t k = 0; k < value_len; ++k)
785 encoded[k] = (normalized[k] == (char)
EO_BREAK_BYTE) ? 0x79 : (uint8_t)normalized[k];
790 size_t to_copy = padded ? value_len : length;
791 memcpy(encoded, normalized, to_copy);
798 size_t remaining = length > value_len ? length - value_len : 0;
799 for (
size_t i = 0; i < remaining; ++i)
807 memcpy(writer->
data + writer->
length, encoded, length);
817 if (!writer || !data)
828 memcpy(writer->
data + writer->
length, data, length);
878 if (next_break < reader->offset)
883 return next_break - reader->
offset;
917 return reader ? reader->
length : 0;
920 for (
size_t i = reader->
chunk_offset; i < reader->length; ++i)
933 if (!reader || !out_value)
949 uint8_t value = reader->
data[reader->
offset++];
960 if (!reader || !out_value)
976 uint8_t bytes[1] = {reader->
data[reader->
offset++]};
987 if (!reader || !out_value)
1014 if (!reader || !out_value)
1030 uint8_t bytes[3] = {
1044 if (!reader || !out_value)
1060 uint8_t bytes[4] = {
1075 if (!reader || !out_value)
1083 *out_value = strdup(
"");
1092 if (!reader || !out_value)
1100 *out_value = strdup(
"");
1109 if (!reader || !out_value)
1119 *out_value = strdup(
"");
1126 *out_value = (
char *)malloc(length + 1);
1132 memcpy(*out_value, reader->
data + reader->
offset, length);
1133 (*out_value)[length] =
'\0';
1134 reader->
offset += length;
1140 if (!reader || !out_value)
1149 *out_value = strdup(
"");
1156 *out_value = (
char *)malloc(length + 1);
1162 memcpy(*out_value, reader->
data + reader->
offset, length);
1164 (*out_value)[length] =
'\0';
1165 reader->
offset += length;
1171 if (!reader || !out_value)
1187 *out_value = (uint8_t *)malloc(length);
1193 memcpy(*out_value, reader->
data + reader->
offset, length);
1194 reader->
offset += length;
EoResult eo_writer_add_string(EoWriter *writer, const char *value)
static const uint32_t cp1252_unicode_extras[32]
EoResult eo_string_to_windows_1252(const char *value, char **out_value)
EoResult eo_reader_get_fixed_encoded_string(EoReader *reader, size_t length, char **out_value)
bool eo_reader_get_chunked_reading_mode(const EoReader *reader)
EoResult eo_reader_get_string(EoReader *reader, char **out_value)
EoResult eo_reader_get_encoded_string(EoReader *reader, char **out_value)
EoResult eo_writer_add_encoded_string(EoWriter *writer, const char *value)
EoResult eo_writer_add_fixed_string(EoWriter *writer, const char *value, size_t length, bool padded)
EoResult eo_reader_get_int(EoReader *reader, int32_t *out_value)
int32_t eo_decode_number(const uint8_t *bytes, size_t length)
EoResult eo_writer_add_byte(EoWriter *writer, uint8_t value)
EoWriter eo_writer_init_with_capacity(size_t capacity)
static size_t eo_reader_next_break_index(const EoReader *reader)
EoResult eo_reader_get_short(EoReader *reader, int32_t *out_value)
const char * eo_result_string(EoResult result)
void eo_reader_set_chunked_reading_mode(EoReader *reader, bool enabled)
EoResult eo_reader_next_chunk(EoReader *reader)
static uint8_t unicode_to_cp1252(uint32_t codepoint)
EoResult eo_reader_get_char(EoReader *reader, int32_t *out_value)
static size_t normalize_to_cp1252(const char *input, char *output, size_t input_len)
EoResult eo_writer_add_short(EoWriter *writer, int32_t value)
void eo_encode_string(uint8_t *buf, size_t length)
EoResult eo_writer_add_bytes(EoWriter *writer, const uint8_t *data, size_t length)
bool eo_writer_get_string_sanitization_mode(const EoWriter *writer)
EoResult eo_writer_add_char(EoWriter *writer, int32_t value)
EoResult eo_writer_ensure_capacity(EoWriter *writer, size_t additional)
EoWriter eo_writer_init(void)
EoResult eo_reader_get_three(EoReader *reader, int32_t *out_value)
EoResult eo_writer_add_three(EoWriter *writer, int32_t value)
EoResult eo_writer_add_int(EoWriter *writer, int32_t value)
EoResult eo_writer_add_fixed_encoded_string(EoWriter *writer, const char *value, size_t length, bool padded)
void eo_writer_free(EoWriter *writer)
EoReader eo_reader_init(const uint8_t *data, size_t length)
void eo_decode_string(uint8_t *buf, size_t length)
EoResult eo_reader_get_bytes(EoReader *reader, size_t length, uint8_t **out_value)
void eo_writer_set_string_sanitization_mode(EoWriter *writer, bool enabled)
size_t eo_reader_remaining(const EoReader *reader)
EoResult eo_reader_get_fixed_string(EoReader *reader, size_t length, char **out_value)
EoResult eo_encode_number(int32_t number, uint8_t out_bytes[4])
EoResult eo_reader_get_byte(EoReader *reader, uint8_t *out_value)
#define EO_NUMBER_PADDING
@ EO_INVALID_SEQUENCE_RANGE
@ EO_SEQUENCE_OUT_OF_RANGE
@ EO_CHUNKED_MODE_DISABLED
bool chunked_reading_mode
bool string_sanitization_mode