[FL-2713] Buffered file streams fix (#1515)
* Fix incorrect buffered stream behaviour * Add specific tests * Make the test fail on wrong behaviour * Better names Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									f9745b4141
								
							
						
					
					
						commit
						01afb289c0
					
				| @ -387,6 +387,34 @@ MU_TEST(stream_split_test) { | ||||
|     furi_record_close(RECORD_STORAGE); | ||||
| } | ||||
| 
 | ||||
| MU_TEST(stream_buffered_write_after_read_test) { | ||||
|     const char* prefix = "I write "; | ||||
|     const char* substr = "Hello there"; | ||||
| 
 | ||||
|     const size_t substr_len = strlen(substr); | ||||
|     const size_t prefix_len = strlen(prefix); | ||||
|     const size_t buf_size = substr_len + 1; | ||||
| 
 | ||||
|     char buf[buf_size]; | ||||
|     memset(buf, 0, buf_size); | ||||
| 
 | ||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||
|     Stream* stream = buffered_file_stream_alloc(storage); | ||||
|     mu_check(buffered_file_stream_open( | ||||
|         stream, EXT_PATH("filestream.str"), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS)); | ||||
|     mu_assert_int_eq(strlen(stream_test_data), stream_write_cstring(stream, stream_test_data)); | ||||
|     mu_check(stream_rewind(stream)); | ||||
|     mu_assert_int_eq(prefix_len, stream_read(stream, (uint8_t*)buf, prefix_len)); | ||||
|     mu_assert_string_eq(prefix, buf); | ||||
|     mu_assert_int_eq(substr_len, stream_write(stream, (uint8_t*)substr, substr_len)); | ||||
|     mu_check(stream_seek(stream, prefix_len, StreamOffsetFromStart)); | ||||
|     mu_assert_int_eq(substr_len, stream_read(stream, (uint8_t*)buf, substr_len)); | ||||
|     mu_assert_string_eq(substr, buf); | ||||
| 
 | ||||
|     stream_free(stream); | ||||
|     furi_record_close(RECORD_STORAGE); | ||||
| } | ||||
| 
 | ||||
| MU_TEST(stream_buffered_large_file_test) { | ||||
|     string_t input_data; | ||||
|     string_t output_data; | ||||
| @ -470,6 +498,7 @@ MU_TEST_SUITE(stream_suite) { | ||||
|     MU_RUN_TEST(stream_write_read_save_load_test); | ||||
|     MU_RUN_TEST(stream_composite_test); | ||||
|     MU_RUN_TEST(stream_split_test); | ||||
|     MU_RUN_TEST(stream_buffered_write_after_read_test); | ||||
|     MU_RUN_TEST(stream_buffered_large_file_test); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| #include "buffered_file_stream.h" | ||||
| 
 | ||||
| #include "core/check.h" | ||||
| #include "stream_i.h" | ||||
| #include "file_stream.h" | ||||
| #include "stream_cache.h" | ||||
| @ -38,6 +39,8 @@ const StreamVTable buffered_file_stream_vtable = { | ||||
|     .delete_and_insert = (StreamDeleteAndInsertFn)buffered_file_stream_delete_and_insert, | ||||
| }; | ||||
| 
 | ||||
| static bool buffered_file_stream_unread(BufferedFileStream* stream); | ||||
| 
 | ||||
| Stream* buffered_file_stream_alloc(Storage* storage) { | ||||
|     BufferedFileStream* stream = malloc(sizeof(BufferedFileStream)); | ||||
| 
 | ||||
| @ -125,8 +128,12 @@ static size_t buffered_file_stream_size(BufferedFileStream* stream) { | ||||
| 
 | ||||
| static size_t | ||||
|     buffered_file_stream_write(BufferedFileStream* stream, const uint8_t* data, size_t size) { | ||||
|     stream_cache_drop(stream->cache); | ||||
|     return stream_write(stream->file_stream, data, size); | ||||
|     size_t need_to_write = size; | ||||
|     do { | ||||
|         if(!buffered_file_stream_unread(stream)) break; | ||||
|         need_to_write -= stream_write(stream->file_stream, data, size); | ||||
|     } while(false); | ||||
|     return size - need_to_write; | ||||
| } | ||||
| 
 | ||||
| static size_t buffered_file_stream_read(BufferedFileStream* stream, uint8_t* data, size_t size) { | ||||
| @ -150,6 +157,19 @@ static bool buffered_file_stream_delete_and_insert( | ||||
|     size_t delete_size, | ||||
|     StreamWriteCB write_callback, | ||||
|     const void* ctx) { | ||||
|     stream_cache_drop(stream->cache); | ||||
|     return stream_delete_and_insert(stream->file_stream, delete_size, write_callback, ctx); | ||||
|     return buffered_file_stream_unread(stream) && | ||||
|            stream_delete_and_insert(stream->file_stream, delete_size, write_callback, ctx); | ||||
| } | ||||
| 
 | ||||
| // Drop read cache and adjust the underlying stream seek position
 | ||||
| static bool buffered_file_stream_unread(BufferedFileStream* stream) { | ||||
|     bool success = true; | ||||
|     const size_t cache_size = stream_cache_size(stream->cache); | ||||
|     const size_t cache_pos = stream_cache_pos(stream->cache); | ||||
|     if(cache_pos < cache_size) { | ||||
|         const int32_t offset = cache_size - cache_pos; | ||||
|         success = stream_seek(stream->file_stream, -offset, StreamOffsetFromCurrent); | ||||
|     } | ||||
|     stream_cache_drop(stream->cache); | ||||
|     return success; | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Georgii Surkov
						Georgii Surkov