[FL-2312] Flipper format: insert OR update (#1009)
* Flipper format: seek_to_end, key_exist * Flipper Format: insert_or_update
This commit is contained in:
		
							parent
							
								
									966b400f8b
								
							
						
					
					
						commit
						c42cce3c6c
					
				| @ -11,22 +11,30 @@ static const uint32_t test_version = 666; | ||||
| static const char* test_string_key = "String data"; | ||||
| static const char* test_string_data = "String"; | ||||
| static const char* test_string_updated_data = "New string"; | ||||
| static const char* test_string_updated_2_data = "And some more"; | ||||
| 
 | ||||
| static const char* test_int_key = "Int32 data"; | ||||
| static const int32_t test_int_data[] = {1234, -6345, 7813, 0}; | ||||
| static const int32_t test_int_updated_data[] = {-1337, 69}; | ||||
| static const int32_t test_int_updated_2_data[] = {-3, -2, -1, 0, 1, 2, 3}; | ||||
| 
 | ||||
| static const char* test_uint_key = "Uint32 data"; | ||||
| static const uint32_t test_uint_data[] = {1234, 0, 5678, 9098, 7654321}; | ||||
| static const uint32_t test_uint_updated_data[] = {8, 800, 555, 35, 35}; | ||||
| static const uint32_t test_uint_updated_2_data[] = {20, 21}; | ||||
| 
 | ||||
| static const char* test_float_key = "Float data"; | ||||
| static const float test_float_data[] = {1.5f, 1000.0f}; | ||||
| static const float test_float_updated_data[] = {1.2f}; | ||||
| static const float test_float_updated_2_data[] = {0.01f, 0.0f, -51.6f}; | ||||
| 
 | ||||
| static const char* test_hex_key = "Hex data"; | ||||
| static const uint8_t test_hex_data[] = {0xDE, 0xAD, 0xBE}; | ||||
| static const uint8_t test_hex_updated_data[] = {0xFE, 0xCA}; | ||||
| static const uint8_t test_hex_updated_2_data[] = {0xCA, 0xCA, 0x05}; | ||||
| 
 | ||||
| static const char* test_hex_new_key = "New Hex data"; | ||||
| static const uint8_t test_hex_new_data[] = {0xFF, 0x6A, 0x91}; | ||||
| 
 | ||||
| static const char* test_data_nix = "Filetype: Flipper Format test\n" | ||||
|                                    "Version: 666\n" | ||||
| @ -59,7 +67,40 @@ MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) { | ||||
| 
 | ||||
|     uint32_t count; | ||||
| 
 | ||||
|     // key exist test
 | ||||
|     size_t position_before = stream_tell(flipper_format_get_raw_stream(flipper_format)); | ||||
|     mu_check(flipper_format_key_exist(flipper_format, test_hex_key)); | ||||
|     mu_assert_int_eq(position_before, stream_tell(flipper_format_get_raw_stream(flipper_format))); | ||||
| 
 | ||||
|     mu_check(!flipper_format_key_exist(flipper_format, "invalid key")); | ||||
|     mu_assert_int_eq(position_before, stream_tell(flipper_format_get_raw_stream(flipper_format))); | ||||
| 
 | ||||
|     // stream seek to end test
 | ||||
|     mu_check(flipper_format_seek_to_end(flipper_format)); | ||||
|     mu_assert_int_eq( | ||||
|         stream_size(flipper_format_get_raw_stream(flipper_format)), | ||||
|         stream_tell(flipper_format_get_raw_stream(flipper_format))); | ||||
| 
 | ||||
|     // key exist test
 | ||||
|     position_before = stream_tell(flipper_format_get_raw_stream(flipper_format)); | ||||
|     mu_check(flipper_format_key_exist(flipper_format, test_hex_key)); | ||||
|     mu_assert_int_eq(position_before, stream_tell(flipper_format_get_raw_stream(flipper_format))); | ||||
| 
 | ||||
|     mu_check(!flipper_format_key_exist(flipper_format, "invalid key")); | ||||
|     mu_assert_int_eq(position_before, stream_tell(flipper_format_get_raw_stream(flipper_format))); | ||||
| 
 | ||||
|     // rewind
 | ||||
|     mu_check(flipper_format_rewind(flipper_format)); | ||||
| 
 | ||||
|     // key exist test
 | ||||
|     position_before = stream_tell(flipper_format_get_raw_stream(flipper_format)); | ||||
|     mu_check(flipper_format_key_exist(flipper_format, test_hex_key)); | ||||
|     mu_assert_int_eq(position_before, stream_tell(flipper_format_get_raw_stream(flipper_format))); | ||||
| 
 | ||||
|     mu_check(!flipper_format_key_exist(flipper_format, "invalid key")); | ||||
|     mu_assert_int_eq(position_before, stream_tell(flipper_format_get_raw_stream(flipper_format))); | ||||
| 
 | ||||
|     // read test
 | ||||
|     string_init(tmpstr); | ||||
| 
 | ||||
|     mu_check(flipper_format_read_header(flipper_format, tmpstr, &version)); | ||||
| @ -94,6 +135,7 @@ MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) { | ||||
| 
 | ||||
|     string_clear(tmpstr); | ||||
| 
 | ||||
|     // update data
 | ||||
|     mu_check(flipper_format_rewind(flipper_format)); | ||||
|     mu_check(flipper_format_update_string_cstr( | ||||
|         flipper_format, test_string_key, test_string_updated_data)); | ||||
| @ -106,6 +148,7 @@ MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) { | ||||
|     mu_check(flipper_format_update_hex( | ||||
|         flipper_format, test_hex_key, ARRAY_W_COUNT(test_hex_updated_data))); | ||||
| 
 | ||||
|     // read updated data test
 | ||||
|     uint32_t uint32_updated_data[COUNT_OF(test_uint_updated_data)]; | ||||
|     int32_t int32_updated_data[COUNT_OF(test_int_updated_data)]; | ||||
|     float float_updated_data[COUNT_OF(test_float_updated_data)]; | ||||
| @ -149,9 +192,76 @@ MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) { | ||||
| 
 | ||||
|     string_clear(tmpstr); | ||||
| 
 | ||||
|     // update data
 | ||||
|     mu_check(flipper_format_rewind(flipper_format)); | ||||
|     mu_check(flipper_format_insert_or_update_string_cstr( | ||||
|         flipper_format, test_string_key, test_string_updated_2_data)); | ||||
|     mu_check(flipper_format_insert_or_update_int32( | ||||
|         flipper_format, test_int_key, ARRAY_W_COUNT(test_int_updated_2_data))); | ||||
|     mu_check(flipper_format_insert_or_update_uint32( | ||||
|         flipper_format, test_uint_key, ARRAY_W_COUNT(test_uint_updated_2_data))); | ||||
|     mu_check(flipper_format_insert_or_update_float( | ||||
|         flipper_format, test_float_key, ARRAY_W_COUNT(test_float_updated_2_data))); | ||||
|     mu_check(flipper_format_insert_or_update_hex( | ||||
|         flipper_format, test_hex_key, ARRAY_W_COUNT(test_hex_updated_2_data))); | ||||
|     mu_check(flipper_format_insert_or_update_hex( | ||||
|         flipper_format, test_hex_new_key, ARRAY_W_COUNT(test_hex_new_data))); | ||||
| 
 | ||||
|     uint32_t uint32_updated_2_data[COUNT_OF(test_uint_updated_2_data)]; | ||||
|     int32_t int32_updated_2_data[COUNT_OF(test_int_updated_2_data)]; | ||||
|     float float_updated_2_data[COUNT_OF(test_float_updated_2_data)]; | ||||
|     uint8_t hex_updated_2_data[COUNT_OF(test_hex_updated_2_data)]; | ||||
|     uint8_t hex_new_data[COUNT_OF(test_hex_new_data)]; | ||||
| 
 | ||||
|     mu_check(flipper_format_rewind(flipper_format)); | ||||
|     string_init(tmpstr); | ||||
| 
 | ||||
|     mu_check(flipper_format_read_header(flipper_format, tmpstr, &version)); | ||||
|     mu_assert_string_eq(test_filetype, string_get_cstr(tmpstr)); | ||||
|     mu_assert_int_eq(test_version, version); | ||||
| 
 | ||||
|     mu_check(flipper_format_read_string(flipper_format, test_string_key, tmpstr)); | ||||
|     mu_assert_string_eq(test_string_updated_2_data, string_get_cstr(tmpstr)); | ||||
| 
 | ||||
|     mu_check(flipper_format_get_value_count(flipper_format, test_int_key, &count)); | ||||
|     mu_assert_int_eq(COUNT_OF(test_int_updated_2_data), count); | ||||
|     mu_check(flipper_format_read_int32( | ||||
|         flipper_format, test_int_key, ARRAY_W_COUNT(int32_updated_2_data))); | ||||
|     mu_check(memcmp(test_int_updated_2_data, ARRAY_W_BSIZE(int32_updated_2_data)) == 0); | ||||
| 
 | ||||
|     mu_check(flipper_format_get_value_count(flipper_format, test_uint_key, &count)); | ||||
|     mu_assert_int_eq(COUNT_OF(test_uint_updated_2_data), count); | ||||
|     mu_check(flipper_format_read_uint32( | ||||
|         flipper_format, test_uint_key, ARRAY_W_COUNT(uint32_updated_2_data))); | ||||
|     mu_check(memcmp(test_uint_updated_2_data, ARRAY_W_BSIZE(uint32_updated_2_data)) == 0); | ||||
| 
 | ||||
|     mu_check(flipper_format_get_value_count(flipper_format, test_float_key, &count)); | ||||
|     mu_assert_int_eq(COUNT_OF(test_float_updated_2_data), count); | ||||
|     mu_check(flipper_format_read_float( | ||||
|         flipper_format, test_float_key, ARRAY_W_COUNT(float_updated_2_data))); | ||||
|     mu_check(memcmp(test_float_updated_2_data, ARRAY_W_BSIZE(float_updated_2_data)) == 0); | ||||
| 
 | ||||
|     mu_check(flipper_format_get_value_count(flipper_format, test_hex_key, &count)); | ||||
|     mu_assert_int_eq(COUNT_OF(test_hex_updated_2_data), count); | ||||
|     mu_check( | ||||
|         flipper_format_read_hex(flipper_format, test_hex_key, ARRAY_W_COUNT(hex_updated_2_data))); | ||||
|     mu_check(memcmp(test_hex_updated_2_data, ARRAY_W_BSIZE(hex_updated_2_data)) == 0); | ||||
| 
 | ||||
|     mu_check(flipper_format_get_value_count(flipper_format, test_hex_new_key, &count)); | ||||
|     mu_assert_int_eq(COUNT_OF(test_hex_new_data), count); | ||||
|     mu_check( | ||||
|         flipper_format_read_hex(flipper_format, test_hex_new_key, ARRAY_W_COUNT(hex_new_data))); | ||||
|     mu_check(memcmp(test_hex_new_data, ARRAY_W_BSIZE(hex_new_data)) == 0); | ||||
| 
 | ||||
|     mu_check(!flipper_format_read_string(flipper_format, "Key that doesn't exist", tmpstr)); | ||||
| 
 | ||||
|     string_clear(tmpstr); | ||||
| 
 | ||||
|     // delete key test
 | ||||
|     mu_check(flipper_format_rewind(flipper_format)); | ||||
|     mu_check(flipper_format_delete_key(flipper_format, test_uint_key)); | ||||
| 
 | ||||
|     // deleted key read test
 | ||||
|     mu_check(flipper_format_rewind(flipper_format)); | ||||
|     mu_check(!flipper_format_read_uint32( | ||||
|         flipper_format, test_uint_key, ARRAY_W_COUNT(uint32_updated_data))); | ||||
|  | ||||
| @ -102,6 +102,20 @@ bool flipper_format_rewind(FlipperFormat* flipper_format) { | ||||
|     return stream_rewind(flipper_format->stream); | ||||
| } | ||||
| 
 | ||||
| bool flipper_format_seek_to_end(FlipperFormat* flipper_format) { | ||||
|     furi_assert(flipper_format); | ||||
|     return stream_seek(flipper_format->stream, 0, StreamOffsetFromEnd); | ||||
| } | ||||
| 
 | ||||
| bool flipper_format_key_exist(FlipperFormat* flipper_format, const char* key) { | ||||
|     size_t pos = stream_tell(flipper_format->stream); | ||||
|     stream_seek(flipper_format->stream, 0, StreamOffsetFromStart); | ||||
|     bool result = flipper_format_stream_seek_to_key(flipper_format->stream, key, false); | ||||
|     stream_seek(flipper_format->stream, pos, StreamOffsetFromStart); | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| bool flipper_format_read_header( | ||||
|     FlipperFormat* flipper_format, | ||||
|     string_t filetype, | ||||
| @ -320,7 +334,7 @@ bool flipper_format_update_string(FlipperFormat* flipper_format, const char* key | ||||
|     FlipperStreamWriteData write_data = { | ||||
|         .key = key, | ||||
|         .type = FlipperStreamValueStr, | ||||
|         .data = data, | ||||
|         .data = string_get_cstr(data), | ||||
|         .data_size = 1, | ||||
|     }; | ||||
|     bool result = flipper_format_stream_delete_key_and_write( | ||||
| @ -408,3 +422,103 @@ bool flipper_format_update_hex( | ||||
|         flipper_format->stream, &write_data, flipper_format->strict_mode); | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| bool flipper_format_insert_or_update_string( | ||||
|     FlipperFormat* flipper_format, | ||||
|     const char* key, | ||||
|     string_t data) { | ||||
|     bool result = false; | ||||
| 
 | ||||
|     if(!flipper_format_key_exist(flipper_format, key)) { | ||||
|         flipper_format_seek_to_end(flipper_format); | ||||
|         result = flipper_format_write_string(flipper_format, key, data); | ||||
|     } else { | ||||
|         result = flipper_format_update_string(flipper_format, key, data); | ||||
|     } | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| bool flipper_format_insert_or_update_string_cstr( | ||||
|     FlipperFormat* flipper_format, | ||||
|     const char* key, | ||||
|     const char* data) { | ||||
|     bool result = false; | ||||
| 
 | ||||
|     if(!flipper_format_key_exist(flipper_format, key)) { | ||||
|         flipper_format_seek_to_end(flipper_format); | ||||
|         result = flipper_format_write_string_cstr(flipper_format, key, data); | ||||
|     } else { | ||||
|         result = flipper_format_update_string_cstr(flipper_format, key, data); | ||||
|     } | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| bool flipper_format_insert_or_update_uint32( | ||||
|     FlipperFormat* flipper_format, | ||||
|     const char* key, | ||||
|     const uint32_t* data, | ||||
|     const uint16_t data_size) { | ||||
|     bool result = false; | ||||
| 
 | ||||
|     if(!flipper_format_key_exist(flipper_format, key)) { | ||||
|         flipper_format_seek_to_end(flipper_format); | ||||
|         result = flipper_format_write_uint32(flipper_format, key, data, data_size); | ||||
|     } else { | ||||
|         result = flipper_format_update_uint32(flipper_format, key, data, data_size); | ||||
|     } | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| bool flipper_format_insert_or_update_int32( | ||||
|     FlipperFormat* flipper_format, | ||||
|     const char* key, | ||||
|     const int32_t* data, | ||||
|     const uint16_t data_size) { | ||||
|     bool result = false; | ||||
| 
 | ||||
|     if(!flipper_format_key_exist(flipper_format, key)) { | ||||
|         flipper_format_seek_to_end(flipper_format); | ||||
|         result = flipper_format_write_int32(flipper_format, key, data, data_size); | ||||
|     } else { | ||||
|         result = flipper_format_update_int32(flipper_format, key, data, data_size); | ||||
|     } | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| bool flipper_format_insert_or_update_float( | ||||
|     FlipperFormat* flipper_format, | ||||
|     const char* key, | ||||
|     const float* data, | ||||
|     const uint16_t data_size) { | ||||
|     bool result = false; | ||||
| 
 | ||||
|     if(!flipper_format_key_exist(flipper_format, key)) { | ||||
|         flipper_format_seek_to_end(flipper_format); | ||||
|         result = flipper_format_write_float(flipper_format, key, data, data_size); | ||||
|     } else { | ||||
|         result = flipper_format_update_float(flipper_format, key, data, data_size); | ||||
|     } | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| bool flipper_format_insert_or_update_hex( | ||||
|     FlipperFormat* flipper_format, | ||||
|     const char* key, | ||||
|     const uint8_t* data, | ||||
|     const uint16_t data_size) { | ||||
|     bool result = false; | ||||
| 
 | ||||
|     if(!flipper_format_key_exist(flipper_format, key)) { | ||||
|         flipper_format_seek_to_end(flipper_format); | ||||
|         result = flipper_format_write_hex(flipper_format, key, data, data_size); | ||||
|     } else { | ||||
|         result = flipper_format_update_hex(flipper_format, key, data, data_size); | ||||
|     } | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| @ -179,6 +179,22 @@ void flipper_format_set_strict_mode(FlipperFormat* flipper_format, bool strict_m | ||||
|  */ | ||||
| bool flipper_format_rewind(FlipperFormat* flipper_format); | ||||
| 
 | ||||
| /**
 | ||||
|  * Move the RW pointer at the end. Can be useful if you want to add some data after reading. | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance | ||||
|  * @return True on success | ||||
|  */ | ||||
| bool flipper_format_seek_to_end(FlipperFormat* flipper_format); | ||||
| 
 | ||||
| /**
 | ||||
|  * Check if the key exists. | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance | ||||
|  * @param key Key | ||||
|  * @return true key exists | ||||
|  * @return false key is not exists | ||||
|  */ | ||||
| bool flipper_format_key_exist(FlipperFormat* flipper_format, const char* key); | ||||
| 
 | ||||
| /**
 | ||||
|  * Read the header (file type and version). | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance | ||||
| @ -466,6 +482,89 @@ bool flipper_format_update_hex( | ||||
|     const uint8_t* data, | ||||
|     const uint16_t data_size); | ||||
| 
 | ||||
| /**
 | ||||
|  * Updates the value of the first matching key to a string value, or adds the key and value if the key did not exist.  | ||||
|  * Sets the RW pointer to a position at the end of inserted data. | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance  | ||||
|  * @param key Key | ||||
|  * @param data Value | ||||
|  * @return True on success | ||||
|  */ | ||||
| bool flipper_format_insert_or_update_string( | ||||
|     FlipperFormat* flipper_format, | ||||
|     const char* key, | ||||
|     string_t data); | ||||
| 
 | ||||
| /**
 | ||||
|  * Updates the value of the first matching key to a string value, or adds the key and value if the key did not exist.   | ||||
|  * Plain C version.  | ||||
|  * Sets the RW pointer to a position at the end of inserted data. | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance  | ||||
|  * @param key Key | ||||
|  * @param data Value | ||||
|  * @return True on success | ||||
|  */ | ||||
| bool flipper_format_insert_or_update_string_cstr( | ||||
|     FlipperFormat* flipper_format, | ||||
|     const char* key, | ||||
|     const char* data); | ||||
| 
 | ||||
| /**
 | ||||
|  * Updates the value of the first matching key to a uint32 array value, or adds the key and value if the key did not exist.  | ||||
|  *  Sets the RW pointer to a position at the end of inserted data. | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance  | ||||
|  * @param key Key | ||||
|  * @param data Value | ||||
|  * @return True on success | ||||
|  */ | ||||
| bool flipper_format_insert_or_update_uint32( | ||||
|     FlipperFormat* flipper_format, | ||||
|     const char* key, | ||||
|     const uint32_t* data, | ||||
|     const uint16_t data_size); | ||||
| 
 | ||||
| /**
 | ||||
|  * Updates the value of the first matching key to a int32 array value, or adds the key and value if the key did not exist.  | ||||
|  * Sets the RW pointer to a position at the end of inserted data. | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance  | ||||
|  * @param key Key | ||||
|  * @param data Value | ||||
|  * @return True on success | ||||
|  */ | ||||
| bool flipper_format_insert_or_update_int32( | ||||
|     FlipperFormat* flipper_format, | ||||
|     const char* key, | ||||
|     const int32_t* data, | ||||
|     const uint16_t data_size); | ||||
| 
 | ||||
| /**
 | ||||
|  * Updates the value of the first matching key to a float array value, or adds the key and value if the key did not exist.  | ||||
|  * Sets the RW pointer to a position at the end of inserted data. | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance  | ||||
|  * @param key Key | ||||
|  * @param data Value | ||||
|  * @return True on success | ||||
|  */ | ||||
| bool flipper_format_insert_or_update_float( | ||||
|     FlipperFormat* flipper_format, | ||||
|     const char* key, | ||||
|     const float* data, | ||||
|     const uint16_t data_size); | ||||
| 
 | ||||
| /**
 | ||||
|  * Updates the value of the first matching key to an array of hex-formatted bytes, or adds the key and value if the key did not exist.   | ||||
|  *Sets the RW pointer to a position at the end of inserted data. | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance  | ||||
|  * @param key Key | ||||
|  * @param data Value | ||||
|  * @return True on success | ||||
|  */ | ||||
| bool flipper_format_insert_or_update_hex( | ||||
|     FlipperFormat* flipper_format, | ||||
|     const char* key, | ||||
|     const uint8_t* data, | ||||
|     const uint16_t data_size); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -93,7 +93,7 @@ static bool flipper_format_stream_read_valid_key(Stream* stream, string_t key) { | ||||
|     return found; | ||||
| } | ||||
| 
 | ||||
| static bool flipper_format_stream_seek_to_key(Stream* stream, const char* key, bool strict_mode) { | ||||
| bool flipper_format_stream_seek_to_key(Stream* stream, const char* key, bool strict_mode) { | ||||
|     bool found = false; | ||||
|     string_t read_key; | ||||
| 
 | ||||
|  | ||||
| @ -18,6 +18,17 @@ extern "C" { | ||||
|  */ | ||||
| bool flipper_format_stream_write_eol(Stream* stream); | ||||
| 
 | ||||
| /**
 | ||||
|  * Seek to the key from the current position of the stream. | ||||
|  * Position will be at the beginning of the value corresponding to the key, if the key is found,, or at the end of the stream. | ||||
|  * @param stream  | ||||
|  * @param key  | ||||
|  * @param strict_mode  | ||||
|  * @return true key is found | ||||
|  * @return false key is not found | ||||
|  */ | ||||
| bool flipper_format_stream_seek_to_key(Stream* stream, const char* key, bool strict_mode); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 SG
						SG