From 47856b1da6e9100f36bbed1650ba4d9d0db936c5 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Thu, 30 Apr 2020 22:36:45 -0500 Subject: [PATCH] Update: implement missing serialized functions and fix bugs Implement fl_unserialize_simple() and fl_unserialize_simple_get(). The last character in the last string in the unserialized array gets cut off. - This happened because the stopping point was incorrectly compensating for the splitter character for the last character in the string. The width (UTF-8 character width) is not part of the locations size. --- build/level_1/settings | 2 +- build/monolithic/settings | 2 +- level_1/fl_serialized/c/private-serialized.c | 61 +++++++++++ level_1/fl_serialized/c/private-serialized.h | 45 ++++++++ level_1/fl_serialized/c/serialized.c | 152 +++++++++++++++++++-------- level_1/fl_serialized/c/serialized.h | 56 +++++++++- level_1/fl_serialized/data/build/settings | 2 +- 7 files changed, 272 insertions(+), 48 deletions(-) create mode 100644 level_1/fl_serialized/c/private-serialized.c create mode 100644 level_1/fl_serialized/c/private-serialized.h diff --git a/build/level_1/settings b/build/level_1/settings index 9b7c26d..8ab7eb5 100644 --- a/build/level_1/settings +++ b/build/level_1/settings @@ -12,7 +12,7 @@ build_linker ar build_libraries -lc build_libraries_fll -lfll_0 build_libraries_fll-level -lfll_0 -build_sources_library color.c console.c directory.c file.c fss.c fss_basic.c fss_basic_list.c fss_extended.c fss_extended_list.c print.c serialized.c socket.c status.c string.c utf.c private-string.c private-utf.c +build_sources_library color.c console.c directory.c file.c fss.c fss_basic.c fss_basic_list.c fss_extended.c fss_extended_list.c print.c serialized.c private-serialized.c socket.c status.c string.c utf.c private-string.c private-utf.c build_sources_program build_sources_headers color.h console.h directory.h file.h fss.h fss_basic.h fss_basic_list.h fss_status.h fss_extended.h fss_extended_list.h fss_macro.h print.h serialized.h socket.h status.h string.h utf.h build_shared yes diff --git a/build/monolithic/settings b/build/monolithic/settings index 68d14a6..dec2e3c 100644 --- a/build/monolithic/settings +++ b/build/monolithic/settings @@ -11,7 +11,7 @@ build_compiler gcc build_linker ar build_libraries -lc build_libraries_fll -build_sources_library level_0/console.c level_0/conversion.c level_0/file.c level_0/memory.c level_0/pipe.c level_0/print.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/directory.c level_1/file.c level_1/fss.c level_1/fss_basic.c level_1/fss_basic_list.c level_1/fss_extended.c level_1/fss_extended_list.c level_1/serialized.c level_1/socket.c level_1/status.c level_1/string.c level_1/utf.c level_1/print.c level_1/private-string.c level_1/private-utf.c level_2/execute.c level_2/file.c level_2/fss_basic.c level_2/fss_basic_list.c level_2/fss_extended.c level_2/fss_extended_list.c level_2/fss_status.c level_2/program.c level_2/status.c +build_sources_library level_0/console.c level_0/conversion.c level_0/file.c level_0/memory.c level_0/pipe.c level_0/print.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/directory.c level_1/file.c level_1/fss.c level_1/fss_basic.c level_1/fss_basic_list.c level_1/fss_extended.c level_1/fss_extended_list.c level_1/serialized.c level_1/private-serialized.c level_1/socket.c level_1/status.c level_1/string.c level_1/utf.c level_1/print.c level_1/private-string.c level_1/private-utf.c level_2/execute.c level_2/file.c level_2/fss_basic.c level_2/fss_basic_list.c level_2/fss_extended.c level_2/fss_extended_list.c level_2/fss_status.c level_2/program.c level_2/status.c build_sources_program build_sources_headers level_0/color.h level_0/console.h level_0/conversion.h level_0/file.h level_0/fss.h level_0/memory.h level_0/path_fll.h level_0/path_filesystem.h level_0/pipe.h level_0/print.h level_0/serialized.h level_0/socket.h level_0/status.h level_0/string.h level_0/type.h level_0/type_array.h level_0/utf.h level_1/color.h level_1/console.h level_1/directory.h level_1/file.h level_1/fss.h level_1/fss_basic.h level_1/fss_basic_list.h level_1/fss_status.h level_1/fss_extended.h level_1/fss_extended_list.h level_1/fss_macro.h level_1/serialized.h level_1/socket.h level_1/status.h level_1/string.h level_1/utf.h level_1/print.h level_2/execute.h level_2/file.h level_2/fss_basic.h level_2/fss_basic_list.h level_2/fss_extended.h level_2/fss_extended_list.h level_2/fss_status.h level_2/program.h level_2/status.h build_sources_bash diff --git a/level_1/fl_serialized/c/private-serialized.c b/level_1/fl_serialized/c/private-serialized.c new file mode 100644 index 0000000..46982b4 --- /dev/null +++ b/level_1/fl_serialized/c/private-serialized.c @@ -0,0 +1,61 @@ +#include +#include "private-serialized.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(_di_fl_unserialize_simple_find_) || !defined(_di_fl_unserialize_simple_get_) + f_return_status private_fl_unserialize_simple_find(const f_string_dynamic serialized, const f_array_length index, f_string_location *location) { + f_status status = f_none; + + f_array_length i = 0; + f_array_length start = 0; + f_array_length current = 0; + + unsigned short width = 0; + + while (i < serialized.used) { + width = f_macro_utf_byte_width(serialized.string[i]); + + if (serialized.string[i] == f_serialized_simple_splitter) { + if (current == index) { + if (start == i) { + // provide an invalid start to stop range to communicate that there is no data. + location->start = 1; + location->stop = 0; + } + else { + location->start = start; + location->stop = i - 1; + } + + return f_none; + } + + start = i + width; + current++; + } + else if (i == serialized.used) { + if (current == index) { + location->start = start; + location->stop = i - 1; + } + + return f_none_on_eos; + } + + if (i + width > serialized.used) { + return f_status_set_error(f_incomplete_utf_on_eos); + } + + i += width; + } // while + + return f_no_data_on_eos; + } +#endif // !defined(_di_fl_unserialize_simple_find_) || !defined(_di_fl_unserialize_simple_get_) + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_1/fl_serialized/c/private-serialized.h b/level_1/fl_serialized/c/private-serialized.h new file mode 100644 index 0000000..cd61998 --- /dev/null +++ b/level_1/fl_serialized/c/private-serialized.h @@ -0,0 +1,45 @@ +/** + * FLL - Level 1 + * + * Project: Serialized + * API Version: 0.5 + * Licenses: lgplv2.1 + * + * These are provided for internal reduction in redundant code. + * These should not be exposed/used outside of this project. + */ +#ifndef _PRIVATE_FL_serialized_h +#define _PRIVATE_FL_serialized_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Private implementation of fl_unserialize_simple_get(). + * + * Intended to be shared to each of the different implementation variations. + * + * @param serialized + * A serialized string to de-serialize. + * @param index + * An index position within the serialized string to get the deserialized positions of. + * @param location + * A location within the serialized string representing the string at the given index. + * + * @return + * f_none on success. + * f_none_on_eos on success at end of string. + * f_no_data_on_eos if end of string reached before index was reached. + * f_incomplete_utf_on_eos (with error bit) if end of string is reached before a complete UTF-8 character can be processed. + * f_invalid_parameter (with error bit) if a parameter is invalid. + */ +#if !defined(_di_fl_unserialize_simple_find_) || !defined(_di_fl_unserialize_simple_get_) + extern f_return_status private_fl_unserialize_simple_find(const f_string_dynamic serialized, const f_array_length index, f_string_location *location) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_fl_unserialize_simple_find_) || !defined(_di_fl_unserialize_simple_get_) + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _PRIVATE_FL_serialized_h diff --git a/level_1/fl_serialized/c/serialized.c b/level_1/fl_serialized/c/serialized.c index 1a5a79f..10aae56 100644 --- a/level_1/fl_serialized/c/serialized.c +++ b/level_1/fl_serialized/c/serialized.c @@ -1,4 +1,5 @@ #include +#include "private-serialized.h" #ifdef __cplusplus extern "C" { @@ -32,9 +33,80 @@ extern "C" { } #endif // _di_fl_serialize_simple_ +#ifndef _di_fl_unserialize_simple_ + f_return_status fl_unserialize_simple(const f_string_dynamic serialized, f_string_dynamics *strings) { + #ifndef _di_level_0_parameter_checking_ + if (serialized.used == 0) return f_status_set_error(f_invalid_parameter); + if (strings == 0) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_0_parameter_checking_ + + f_status status = f_none; + + f_array_length i = 0; + f_array_length start = 0; + + uint8_t width = 0; + + while (i < serialized.used) { + width = f_macro_utf_byte_width(serialized.string[i]); + + if (serialized.string[i] == f_serialized_simple_splitter || i + 1 >= serialized.used) { + if (strings->used >= strings->size) { + f_macro_string_dynamics_resize(status, (*strings), strings->size + f_serialized_default_allocation_step); + + if (f_status_is_error(status)) return status; + } + + if (start == i) { + strings->array[strings->used].used = 0; + strings->used++; + } + else { + f_string_length total; + + if (i + 1 >= serialized.used) { + total = (i - start) + 1; + } + else { + // subtract one from stop point to disclused the f_serialized_simple_splitter character. + total = ((i - 1) - start) + 1; + } + + if (total > strings->array[strings->used].size) { + f_macro_string_dynamic_new(status, strings->array[strings->used], total); + + if (f_status_is_error(status)) return status; + + strings->array[strings->used].size = total; + } + + memcpy(strings->array[strings->used].string, serialized.string + start, total); + + strings->array[strings->used].used = total; + strings->used++; + } + + if (i + width > serialized.used) { + return f_status_set_error(f_incomplete_utf_on_eos); + } + + start = i + width; + } + else if (i + width > serialized.used) { + return f_status_set_error(f_incomplete_utf_on_eos); + } + + i += width; + } // while + + return f_none; + } +#endif // _di_fl_unserialize_simple_ + #ifndef _di_fl_unserialize_simple_map_ f_return_status fl_unserialize_simple_map(const f_string_dynamic serialized, f_string_locations *locations) { #ifndef _di_level_0_parameter_checking_ + if (serialized.used == 0) return f_status_set_error(f_invalid_parameter); if (locations == 0) return f_status_set_error(f_invalid_parameter); #endif // _di_level_0_parameter_checking_ @@ -43,13 +115,13 @@ extern "C" { f_array_length i = 0; f_array_length start = 0; - unsigned short width = 0; + uint8_t width = 0; while (i < serialized.used) { width = f_macro_utf_byte_width(serialized.string[i]); - if (serialized.string[i] == f_serialized_simple_splitter || i == serialized.used) { - if (locations->used + width >= locations->size) { + if (serialized.string[i] == f_serialized_simple_splitter || i + 1 >= serialized.used) { + if (locations->used >= locations->size) { f_macro_string_locations_resize(status, (*locations), locations->size + f_serialized_default_allocation_step); if (f_status_is_error(status)) return status; @@ -59,14 +131,19 @@ extern "C" { // provide an invalid start to stop range to communicate that there is no data. locations->array[locations->used].start = 1; locations->array[locations->used].stop = 0; - locations->used++; + } + else if (i + 1 >= serialized.used) { + locations->array[locations->used].start = start; + locations->array[locations->used].stop = i; } else { + // subtract one from stop point to disclused the f_serialized_simple_splitter character. locations->array[locations->used].start = start; locations->array[locations->used].stop = i - 1; - locations->used++; } + locations->used++; + if (i + width > serialized.used) { return f_status_set_error(f_incomplete_utf_on_eos); } @@ -87,57 +164,48 @@ extern "C" { #ifndef _di_fl_unserialize_simple_find_ f_return_status fl_unserialize_simple_find(const f_string_dynamic serialized, const f_array_length index, f_string_location *location) { #ifndef _di_level_0_parameter_checking_ + if (serialized.used == 0) return f_status_set_error(f_invalid_parameter); if (location == 0) return f_status_set_error(f_invalid_parameter); #endif // _di_level_0_parameter_checking_ - f_status status = f_none; + return private_fl_unserialize_simple_find(serialized, index, location); + } +#endif // _di_fl_unserialize_simple_find_ - f_array_length i = 0; - f_array_length start = 0; - f_array_length current = 0; +#ifndef _di_fl_unserialize_simple_get_ + f_return_status fl_unserialize_simple_get(const f_string_dynamic serialized, const f_array_length index, f_string_dynamic *dynamic) { + #ifndef _di_level_0_parameter_checking_ + if (serialized.used == 0) return f_status_set_error(f_invalid_parameter); + if (dynamic == 0) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_0_parameter_checking_ - unsigned short width = 0; + f_string_location location = f_string_location_initialize; - while (i < serialized.used) { - width = f_macro_utf_byte_width(serialized.string[i]); + f_status status = private_fl_unserialize_simple_find(serialized, index, &location); - if (serialized.string[i] == f_serialized_simple_splitter) { - if (current == index) { - if (start == i) { - // provide an invalid start to stop range to communicate that there is no data. - location->start = 1; - location->stop = 0; - } - else { - location->start = start; - location->stop = i - 1; - } + if (f_status_is_error(status)) return status; - return f_none; - } + if (status == f_no_data_on_eos) { + dynamic->used = 0; + return status; + } - start = i + width; - current++; - } - else if (i == serialized.used) { - if (current == index) { - location->start = start; - location->stop = i - 1; - } + f_string_length total = (location.stop - location.start) + 1; - return f_none_on_eos; - } + if (total >= dynamic->size) { + f_status status_allocation = f_none; - if (i + width > serialized.used) { - return f_status_set_error(f_incomplete_utf_on_eos); - } + f_macro_string_dynamic_resize(status_allocation, (*dynamic), total); - i += width; - } // while + if (f_status_is_error(status_allocation)) return status_allocation; + } - return f_no_data_on_eos; + memcpy(dynamic->string, serialized.string + location.start, total); + dynamic->used = total; + + return status; } -#endif // _di_fl_unserialize_simple_find_ +#endif // _di_fl_unserialize_simple_get_ #ifdef __cplusplus } // extern "C" diff --git a/level_1/fl_serialized/c/serialized.h b/level_1/fl_serialized/c/serialized.h index d5d92b1..f2e4185 100644 --- a/level_1/fl_serialized/c/serialized.h +++ b/level_1/fl_serialized/c/serialized.h @@ -50,7 +50,30 @@ extern "C" { extern f_return_status fl_serialize_simple(const f_string_dynamic value, f_string_dynamic *serialized); #endif // _di_fl_serialize_simple_ -// @todo: implement fl_unserialize_simple() such that a new array of strings is allocated. +/** + * De-serialized the entire serialized string into multiple separate strings using the Simple serialize algorithm. + * + * The simple Serialize algorithm is akin to the PATH environment variable, example: PATH="/bin:/sbin:/usr/bin". + * + * After processing the above example, there would be the following positions: + * 1) start = 0, stop = 3. + * 2) start = 5, stop = 9. + * 3) start = 11, stop = 18. + * + * @param serialized + * A serialized string to de-serialize. + * @param strings + * An array of strings de-serialized from serialized. + * + * @return + * f_none on success. + * f_incomplete_utf_on_eos if end of sting is reached before a complete UTF-8 character can be processed. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_error_reallocation (with error bit) on memory reallocation error. + */ +#ifndef _di_fl_unserialize_simple_ + extern f_return_status fl_unserialize_simple(const f_string_dynamic serialized, f_string_dynamics *strings); +#endif // _di_fl_unserialize_simple_ /** * Identify string positions within a serialized string using the Simple serialize algorithm. @@ -78,7 +101,7 @@ extern "C" { #endif // _di_fl_unserialize_simple_map_ /** - * Unserialize a specific string using the Simple serialize algorithm. + * Unserialize and find the address for a specific string using the Simple serialize algorithm. * * The simple Serialize algorithm is akin to the PATH environment variable, example: PATH="/bin:/sbin:/usr/bin". * @@ -105,7 +128,34 @@ extern "C" { extern f_return_status fl_unserialize_simple_find(const f_string_dynamic serialized, const f_array_length index, f_string_location *location); #endif // _di_fl_unserialize_simple_find_ -// @todo: implement fl_unserialize_simple_get() such that a new string is allocated, if found. +/** + * Unserialize and get a copy of a specific string using the Simple serialize algorithm. + * + * The simple Serialize algorithm is akin to the PATH environment variable, example: PATH="/bin:/sbin:/usr/bin". + * + * After processing the above example, there would be the following positions, for the given index: + * 1) with index = 0, start = 0, stop = 3. + * 2) with index = 1, start = 5, stop = 9. + * 3) with index = 2, start = 11, stop = 18. + * + * @param serialized + * A serialized string to de-serialize. + * @param index + * An index position within the serialized string to get the deserialized positions of. + * @param dynamic + * The unserialized string from the specified index. + * + * @return + * f_none on success. + * f_none_on_eos on success at end of string. + * f_no_data_on_eos if end of string reached before index was reached (dynamic->used is set to 0). + * f_incomplete_utf_on_eos (with error bit) if end of string is reached before a complete UTF-8 character can be processed. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_error_reallocation (with error bit) on memory reallocation error. + */ +#ifndef _di_fl_unserialize_simple_get_ + extern f_return_status fl_unserialize_simple_get(const f_string_dynamic serialized, const f_array_length index, f_string_dynamic *dynamic); +#endif // _di_fl_unserialize_simple_get_ #ifdef __cplusplus } // extern "C" diff --git a/level_1/fl_serialized/data/build/settings b/level_1/fl_serialized/data/build/settings index d29f63f..bac7c1c 100644 --- a/level_1/fl_serialized/data/build/settings +++ b/level_1/fl_serialized/data/build/settings @@ -11,7 +11,7 @@ build_compiler gcc build_linker ar build_libraries -lc build_libraries_fll -lf_utf -lf_memory -build_sources_library serialized.c +build_sources_library serialized.c private-serialized.c build_sources_program build_sources_headers serialized.h build_sources_bash -- 1.8.3.1