[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);
|
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) {
|
MU_TEST(stream_buffered_large_file_test) {
|
||||||
string_t input_data;
|
string_t input_data;
|
||||||
string_t output_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_write_read_save_load_test);
|
||||||
MU_RUN_TEST(stream_composite_test);
|
MU_RUN_TEST(stream_composite_test);
|
||||||
MU_RUN_TEST(stream_split_test);
|
MU_RUN_TEST(stream_split_test);
|
||||||
|
MU_RUN_TEST(stream_buffered_write_after_read_test);
|
||||||
MU_RUN_TEST(stream_buffered_large_file_test);
|
MU_RUN_TEST(stream_buffered_large_file_test);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "buffered_file_stream.h"
|
#include "buffered_file_stream.h"
|
||||||
|
|
||||||
|
#include "core/check.h"
|
||||||
#include "stream_i.h"
|
#include "stream_i.h"
|
||||||
#include "file_stream.h"
|
#include "file_stream.h"
|
||||||
#include "stream_cache.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,
|
.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) {
|
Stream* buffered_file_stream_alloc(Storage* storage) {
|
||||||
BufferedFileStream* stream = malloc(sizeof(BufferedFileStream));
|
BufferedFileStream* stream = malloc(sizeof(BufferedFileStream));
|
||||||
|
|
||||||
@ -125,8 +128,12 @@ static size_t buffered_file_stream_size(BufferedFileStream* stream) {
|
|||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
buffered_file_stream_write(BufferedFileStream* stream, const uint8_t* data, size_t size) {
|
buffered_file_stream_write(BufferedFileStream* stream, const uint8_t* data, size_t size) {
|
||||||
stream_cache_drop(stream->cache);
|
size_t need_to_write = size;
|
||||||
return stream_write(stream->file_stream, data, 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) {
|
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,
|
size_t delete_size,
|
||||||
StreamWriteCB write_callback,
|
StreamWriteCB write_callback,
|
||||||
const void* ctx) {
|
const void* ctx) {
|
||||||
stream_cache_drop(stream->cache);
|
return buffered_file_stream_unread(stream) &&
|
||||||
return stream_delete_and_insert(stream->file_stream, delete_size, write_callback, ctx);
|
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…
Reference in New Issue
Block a user