From 4a7dccb55b9c0e3861a3f95d9157e15a6fcf6a0c Mon Sep 17 00:00:00 2001 From: Enno Boland Date: Tue, 15 Aug 2023 09:31:05 +0200 Subject: [PATCH 1/9] Revert "buffer: remove unused _drain method" This reverts commit b3f42f994ca6fc9e1a1c67a0837d66a571de7964. --- include/sqsh_primitive_private.h | 13 +++++++++++++ lib/primitive/buffer.c | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/include/sqsh_primitive_private.h b/include/sqsh_primitive_private.h index ebd0fc763..a46955aa9 100644 --- a/include/sqsh_primitive_private.h +++ b/include/sqsh_primitive_private.h @@ -137,6 +137,19 @@ SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__buffer_append( SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__buffer_move(struct SqshBuffer *buffer, struct SqshBuffer *source); +/** + * @internal + * @memberof SqshBuffer + * @brief resets the buffer size to 0. + * + * This does not free the memory allocated by the buffer so that + * the buffer can be reused. + * + * @param[in,out] buffer The SqshBuffer to drain. + */ + +void sqsh__buffer_drain(struct SqshBuffer *buffer); + /** * @internal * @memberof SqshBuffer diff --git a/lib/primitive/buffer.c b/lib/primitive/buffer.c index 3ddeb5407..c7cc11c03 100644 --- a/lib/primitive/buffer.c +++ b/lib/primitive/buffer.c @@ -114,6 +114,11 @@ sqsh__buffer_move(struct SqshBuffer *buffer, struct SqshBuffer *source) { return 0; } +void +sqsh__buffer_drain(struct SqshBuffer *buffer) { + buffer->size = 0; +} + const uint8_t * sqsh__buffer_data(const struct SqshBuffer *buffer) { return buffer->data; From 6dd6db605c17e67f5d21f46b61a8357b24558f71 Mon Sep 17 00:00:00 2001 From: Enno Boland Date: Wed, 16 Aug 2023 17:43:40 +0200 Subject: [PATCH 2/9] reader: reimplementation the reader without _skip Currently, there is an issue with a subtle incompatibility between different iterators. The old SqshReader expected, that all blocks (except the last one) are of the same size. This is not true for SqshFileIterator when iterating over sparse files. The new SqshReader2 does not have this limitation. --- include/sqsh_reader_private.h | 193 +++++++++++++++++++++ lib/meson.build | 1 + lib/reader/reader2.c | 241 ++++++++++++++++++++++++++ test/meson.build | 1 + test/reader/reader2.c | 318 ++++++++++++++++++++++++++++++++++ 5 files changed, 754 insertions(+) create mode 100644 include/sqsh_reader_private.h create mode 100644 lib/reader/reader2.c create mode 100644 test/reader/reader2.c diff --git a/include/sqsh_reader_private.h b/include/sqsh_reader_private.h new file mode 100644 index 000000000..73070cad9 --- /dev/null +++ b/include/sqsh_reader_private.h @@ -0,0 +1,193 @@ +/****************************************************************************** + * * + * Copyright (c) 2023, Enno Boland * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are * + * met: * + * * + * * Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + ******************************************************************************/ + +/** + * @author Enno Boland (mail@eboland.de) + * @file sqsh_reader_private.h + */ + +#ifndef SQSH_READER_PRIVATE_H +#define SQSH_READER_PRIVATE_H + +#include "sqsh_common.h" +#include "sqsh_primitive_private.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************** + * reader/reader2.c + */ + +struct SqshReader2IteratorImpl { + int (*next)(void *iterator, size_t desired_size); + const uint8_t *(*data)(const void *iterator); + size_t (*size)(const void *iterator); +}; + +/** + * @brief An iterator over extended attributes. + */ +struct SqshReader2 { + /** + * @privatesection + */ + + /** + * @brief The for this reader. + */ + void *iterator; + + /** + * @brief interface to the iterator. + */ + const struct SqshReader2IteratorImpl *iterator_impl; + + /** + * @brief The offset of the iterator. + * + * A value of "0" indicates, that the reader currently directly maps data + * from the iterator. That means, that `data` points into memory managed by + * the iterator. + * + * A non-zero value indicates, that the reader has copied data from the + * iterator into the buffer. That means, that `data` points into memory + * managed by the buffer. The actual value of iterator_offset is the offset + * between the buffer and the iterator. + * + * example: + * + * ``` + * 0123456789 + * buffer: ########## + * iterator: #### + * ``` + * + * in this case, the iterator_offset is 6. + */ + sqsh_index_t iterator_offset; + + /** + * @brief The offset of mapped data. + * + * This value is set to zero if the reader uses buffered data. + * + * Otherwise is indicates the offset of the data in the iterator. + */ + sqsh_index_t offset; + + /** + * @brief The buffer to store data in if they cannot be directly mapped. + */ + struct SqshBuffer buffer; + + /** + * @brief The data that is presented to the user. + * + * This pointer has the offset already applied if in mapped mode. + * + * Otherwise it points to the beginning of the buffer. + */ + const uint8_t *data; + /** + * @brief The size of the data that is presented to the user. + */ + size_t size; +}; + +/** + * @internal + * @memberof SqshReader2 + * @brief Initializes a reader. + * + * @param[out] reader Pointer to the metablock reader to be initialized. + * @param[in] iterator_impl Implementation of the iterator. + * @param[in] iterator Iterator to use for the reader. + * + * @return 0 on success, less than zero on error. + */ +SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__reader2_init( + struct SqshReader2 *reader, + const struct SqshReader2IteratorImpl *iterator_impl, void *iterator); + +/** + * @internal + * @memberof SqshReader2 + * @brief Advances the reader by the given offset and size. + * + * @param[in,out] reader Pointer to the metablock reader to be advanced. + * @param[in] offset Offset to advance the reader by. + * @param[in] size Size of the block to advance the reader by. + * + * @return 0 on success, less than zero on error. + */ +SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__reader2_advance( + struct SqshReader2 *reader, sqsh_index_t offset, size_t size); + +/** + * @internal + * @memberof SqshReader2 + * @brief Returns a pointer to the data at the current position of the metablock + * reader. + * + * @param[in] reader Pointer to the metablock reader. + * + * @return Pointer to the data at the current position of the metablock reader. + */ +SQSH_NO_EXPORT const uint8_t * +sqsh__reader2_data(const struct SqshReader2 *reader); + +/** + * @internal + * @memberof SqshReader2 + * @brief Returns the size of the data at the current position of the metablock + * reader. + * + * @param[in] reader Pointer to the metablock reader. + * + * @return Size of the data at the current position of the metablock reader. + */ +SQSH_NO_EXPORT size_t sqsh__reader2_size(const struct SqshReader2 *reader); + +/** + * @internal + * @memberof SqshReader2 + * @brief Cleans up and frees the resources used by the metablock reader. + * + * @param[in,out] reader Pointer to the metablock reader to be cleaned up. + * + * @return 0 on success, less than zero on error. + */ +SQSH_NO_EXPORT int sqsh__reader2_cleanup(struct SqshReader2 *reader); + +#ifdef __cplusplus +} +#endif +#endif /* SQSH_READER_PRIVATE_H */ diff --git a/lib/meson.build b/lib/meson.build index 7f564518d..b84654520 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -1,4 +1,5 @@ libsqsh_sources = files( + 'reader/reader2.c', 'archive/archive.c', 'archive/compression_options.c', 'archive/inode_map.c', diff --git a/lib/reader/reader2.c b/lib/reader/reader2.c new file mode 100644 index 000000000..052036bd3 --- /dev/null +++ b/lib/reader/reader2.c @@ -0,0 +1,241 @@ +/****************************************************************************** + * * + * Copyright (c) 2023, Enno Boland * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are * + * met: * + * * + * * Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + ******************************************************************************/ + +/** + * @author Enno Boland (mail@eboland.de) + * @file xattr_iterator.c + */ + +#include "../../include/sqsh_reader_private.h" + +#include "../../include/sqsh_error.h" +#include "../utils/utils.h" + +#include + +static int +reader_iterator_next(struct SqshReader2 *reader, size_t desired_size) { + int rv = reader->iterator_impl->next(reader->iterator, desired_size); + if (rv == 0) { + rv = -SQSH_ERROR_OUT_OF_BOUNDS; + } + return rv; +} + +/** + * @brief Skips the iterator until the offset is reached. + * + * This is a naiv implementation that just calls next until the offset is + * reached. + * + * TODO: Implement a iterator specific skip function. + * + * @param reader The reader + * @param offset The offset + * @param[in] desired_size The desired size + * + * @return 0 on success, negative on error. + */ +static int +reader_iterator_skip( + struct SqshReader2 *reader, sqsh_index_t *offset, size_t desired_size) { + int rv = 0; + void *iterator = reader->iterator; + const struct SqshReader2IteratorImpl *impl = reader->iterator_impl; + + size_t current_size = impl->size(iterator); + + while (current_size <= *offset) { + *offset -= current_size; + rv = reader_iterator_next(reader, desired_size); + if (rv < 0) { + goto out; + } + current_size = impl->size(iterator); + } + + rv = 0; +out: + return rv; +} + +int +sqsh__reader2_init( + struct SqshReader2 *reader, + const struct SqshReader2IteratorImpl *iterator_impl, void *iterator) { + reader->data = NULL; + reader->size = 0; + reader->offset = 0; + reader->iterator_offset = 0; + reader->iterator_impl = iterator_impl; + reader->iterator = iterator; + return sqsh__buffer_init(&reader->buffer); +} + +/** + * @brief copies data from the iterator to the buffer until the buffer + * reaches the desired size. + * + * @param reader The reader + * @param offset The offset + * @param size The size + * + * @return 0 on success, negative on error. + */ +static int +reader_fill_buffer(struct SqshReader2 *reader, size_t size) { + int rv = 0; + void *iterator = reader->iterator; + const struct SqshReader2IteratorImpl *impl = reader->iterator_impl; + struct SqshBuffer *buffer = &reader->buffer; + sqsh_index_t offset = reader->offset; + + size_t buffer_size = sqsh__buffer_size(buffer); + for (;;) { + const uint8_t *data = impl->data(iterator); + const size_t data_size = impl->size(iterator); + const size_t copy_size = + SQSH_MIN(data_size - offset, size - buffer_size); + rv = sqsh__buffer_append(buffer, &data[offset], copy_size); + if (rv < 0) { + goto out; + } + + offset = 0; + buffer_size += copy_size; + if (size <= buffer_size) { + assert(size == buffer_size); + break; + } + + rv = reader_iterator_next(reader, size); + if (rv < 0) { + goto out; + } + reader->iterator_offset = buffer_size; + } + + reader->offset = 0; + reader->data = sqsh__buffer_data(buffer); + reader->size = size; +out: + return rv; +} + +static int +handle_buffered(struct SqshReader2 *reader, sqsh_index_t offset, size_t size) { + int rv = 0; + struct SqshBuffer new_buffer = {0}; + sqsh_index_t iterator_offset = reader->iterator_offset; + + struct SqshBuffer *buffer = &reader->buffer; + const uint8_t *buffer_data = sqsh__buffer_data(buffer); + const size_t copy_size = iterator_offset - offset; + + if (offset != 0) { + rv = sqsh__buffer_init(&new_buffer); + if (rv < 0) { + goto out; + } + rv = sqsh__buffer_append(&new_buffer, &buffer_data[offset], copy_size); + if (rv < 0) { + goto out; + } + rv = sqsh__buffer_move(buffer, &new_buffer); + if (rv < 0) { + goto out; + } + } + rv = reader_fill_buffer(reader, size); + +out: + return rv; +} + +static int +handle_mapped(struct SqshReader2 *reader, sqsh_index_t offset, size_t size) { + int rv = 0; + void *iterator = reader->iterator; + const struct SqshReader2IteratorImpl *impl = reader->iterator_impl; + + if (SQSH_ADD_OVERFLOW(offset, reader->offset, &offset)) { + rv = -SQSH_ERROR_INTEGER_OVERFLOW; + goto out; + } + + rv = reader_iterator_skip(reader, &offset, size); + if (rv < 0) { + goto out; + } + + reader->offset = offset; + sqsh_index_t end_offset; + if (SQSH_ADD_OVERFLOW(offset, size, &end_offset)) { + rv = -SQSH_ERROR_INTEGER_OVERFLOW; + goto out; + } + if (end_offset < impl->size(iterator)) { + const uint8_t *data = impl->data(iterator); + reader->data = &data[offset]; + reader->size = size; + } else { + struct SqshBuffer *buffer = &reader->buffer; + sqsh__buffer_drain(buffer); + rv = reader_fill_buffer(reader, size); + } + +out: + return rv; +} + +int +sqsh__reader2_advance( + struct SqshReader2 *reader, sqsh_index_t offset, size_t size) { + if (offset >= reader->iterator_offset) { + offset -= reader->iterator_offset; + reader->iterator_offset = 0; + return handle_mapped(reader, offset, size); + } else { + return handle_buffered(reader, offset, size); + } +} + +const uint8_t * +sqsh__reader2_data(const struct SqshReader2 *reader) { + return reader->data; +} + +size_t +sqsh__reader2_size(const struct SqshReader2 *reader) { + return reader->size; +} + +int +sqsh__reader2_cleanup(struct SqshReader2 *reader) { + return sqsh__buffer_cleanup(&reader->buffer); +} diff --git a/test/meson.build b/test/meson.build index a24dfdd71..6cef9f6bd 100644 --- a/test/meson.build +++ b/test/meson.build @@ -28,6 +28,7 @@ sqsh_test = [ 'metablock/metablock_iterator.c', 'metablock/metablock_reader.c', 'nasty.c', + 'reader/reader2.c', 'primitive/buffer.c', 'primitive/lru.c', 'primitive/rc_hash_map.c', diff --git a/test/reader/reader2.c b/test/reader/reader2.c new file mode 100644 index 000000000..4e7e7d2c0 --- /dev/null +++ b/test/reader/reader2.c @@ -0,0 +1,318 @@ +/****************************************************************************** + * * + * Copyright (c) 2023, Enno Boland * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are * + * met: * + * * + * * Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + ******************************************************************************/ + +/** + * @author Enno Boland (mail@eboland.de) + * @file integration.c + */ + +#include "../include/sqsh_reader_private.h" +#include "common.h" +#include +#include + +struct TestIterator { + char *data; + int remaining; + int block_size; + int size; +}; + +static const uint8_t * +test_iter_data(const void *data) { + struct TestIterator *iter = (struct TestIterator *)data; + return (uint8_t *)iter->data; +} + +static size_t +test_iter_size(const void *data) { + struct TestIterator *iter = (struct TestIterator *)data; + return iter->size; +} + +static int +test_iter_next(void *data, size_t desired_size) { + struct TestIterator *iter = (struct TestIterator *)data; + (void)desired_size; + if (iter->remaining == 0) { + iter->data = ""; + } + if (iter->remaining == 0) { + return -1; + } + iter->remaining--; + iter->size = strlen(iter->data); + return iter->size; +} + +static const struct SqshReader2IteratorImpl test_iter = { + .next = test_iter_next, + .data = test_iter_data, + .size = test_iter_size, +}; + +static void +test_reader2_init(void) { + struct SqshReader2 reader = {0}; + struct TestIterator iter = { + .data = "test", + .remaining = 4, + }; + + int rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + sqsh__reader2_cleanup(&reader); +} + +static void +test_reader2_advance_with_offset(void) { + struct SqshReader2 reader = {0}; + struct TestIterator iter = { + .data = "test", + .remaining = 1, + }; + + int rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader2_advance(&reader, 1, 2); + assert(rv == 0); + + const uint8_t *data = sqsh__reader2_data(&reader); + size_t size = sqsh__reader2_size(&reader); + assert(size == 2); + assert(memcmp(data, "es", 2) == 0); + + sqsh__reader2_cleanup(&reader); +} + +static void +test_reader2_advance_to_block(void) { + struct SqshReader2 reader = {0}; + struct TestIterator iter = { + .data = "test", + .remaining = 1, + }; + + int rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader2_advance(&reader, 0, 4); + assert(rv == 0); + + const uint8_t *data = sqsh__reader2_data(&reader); + size_t size = sqsh__reader2_size(&reader); + assert(size == 4); + assert(memcmp(data, "test", 4) == 0); + + sqsh__reader2_cleanup(&reader); +} + +static void +test_reader2_advance_to_two_blocks() { + struct SqshReader2 reader = {0}; + struct TestIterator iter = { + .data = "test", + .remaining = 4, + }; + + int rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader2_advance(&reader, 0, 8); + assert(rv == 0); + + const uint8_t *data = sqsh__reader2_data(&reader); + size_t size = sqsh__reader2_size(&reader); + assert(size == 8); + assert(memcmp(data, "testtest", 8) == 0); + + sqsh__reader2_cleanup(&reader); +} + +static void +test_reader2_advance_to_two_blocks_with_offset() { + struct SqshReader2 reader = {0}; + struct TestIterator iter = { + .data = "test", + .remaining = 4, + }; + + int rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader2_advance(&reader, 1, 6); + assert(rv == 0); + + const uint8_t *data = sqsh__reader2_data(&reader); + size_t size = sqsh__reader2_size(&reader); + assert(size == 6); + assert(memcmp(data, "esttes", 6) == 0); + + sqsh__reader2_cleanup(&reader); +} + +static void +test_reader2_from_buffered_to_mapped() { + struct SqshReader2 reader = {0}; + struct TestIterator iter = { + .data = "test", + .remaining = 4, + }; + + int rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + // Trigger a buffered result + rv = sqsh__reader2_advance(&reader, 1, 6); + assert(rv == 0); + + const uint8_t *data = sqsh__reader2_data(&reader); + size_t size = sqsh__reader2_size(&reader); + assert(size == 6); + assert(memcmp(data, "esttes", 6) == 0); + + // Trigger back to a mapped result + rv = sqsh__reader2_advance(&reader, 4, 3); + assert(rv == 0); + + data = sqsh__reader2_data(&reader); + size = sqsh__reader2_size(&reader); + assert(size == 3); + assert(memcmp(data, "est", 3) == 0); + + sqsh__reader2_cleanup(&reader); +} + +static void +test_reader2_from_buffered_to_buffered() { + struct SqshReader2 reader = {0}; + struct TestIterator iter = { + .data = "test", + .remaining = 4, + }; + + int rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + // Trigger a buffered result + rv = sqsh__reader2_advance(&reader, 1, 6); + assert(rv == 0); + + const uint8_t *data = sqsh__reader2_data(&reader); + size_t size = sqsh__reader2_size(&reader); + assert(size == 6); + assert(memcmp(data, "esttes", 6) == 0); + + // Trigger back to a mapped result + rv = sqsh__reader2_advance(&reader, 8, 6); + assert(rv == 0); + + data = sqsh__reader2_data(&reader); + size = sqsh__reader2_size(&reader); + assert(size == 6); + assert(memcmp(data, "esttes", 6) == 0); + + sqsh__reader2_cleanup(&reader); +} + +static void +test_reader2_advance_inside_buffered() { + struct SqshReader2 reader = {0}; + struct TestIterator iter = { + .data = "test", + .remaining = 4, + }; + + int rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + // Trigger a buffered result + rv = sqsh__reader2_advance(&reader, 1, 6); + assert(rv == 0); + + const uint8_t *data = sqsh__reader2_data(&reader); + size_t size = sqsh__reader2_size(&reader); + assert(size == 6); + assert(memcmp(data, "esttes", 6) == 0); + + // Trigger back to a mapped result + rv = sqsh__reader2_advance(&reader, 1, 6); + assert(rv == 0); + + data = sqsh__reader2_data(&reader); + size = sqsh__reader2_size(&reader); + assert(size == 6); + assert(memcmp(data, "sttest", 6) == 0); + + sqsh__reader2_cleanup(&reader); +} + +static void +test_reader2_advance_with_zero_size() { + struct SqshReader2 reader = {0}; + struct TestIterator iter = { + .data = "test", + .remaining = 4, + }; + + int rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader2_advance(&reader, 3, 0); + assert(rv == 0); + + const uint8_t *data = sqsh__reader2_data(&reader); + size_t size = sqsh__reader2_size(&reader); + assert(size == 0); + + // Trigger back to a mapped result + rv = sqsh__reader2_advance(&reader, 0, 4); + assert(rv == 0); + + data = sqsh__reader2_data(&reader); + size = sqsh__reader2_size(&reader); + assert(size == 4); + assert(memcmp(data, "ttes", 4) == 0); + + sqsh__reader2_cleanup(&reader); +} + +DECLARE_TESTS +TEST(test_reader2_init) +TEST(test_reader2_advance_to_block) +TEST(test_reader2_advance_with_offset) +TEST(test_reader2_advance_to_two_blocks) +TEST(test_reader2_advance_to_two_blocks_with_offset) +TEST(test_reader2_from_buffered_to_mapped) +TEST(test_reader2_from_buffered_to_buffered) +TEST(test_reader2_from_buffered_to_buffered) +TEST(test_reader2_advance_inside_buffered) +TEST(test_reader2_advance_with_zero_size) +END_TESTS From e95347e1580dd1f20c18a77cd02f82b919e6c5a6 Mon Sep 17 00:00:00 2001 From: Enno Boland Date: Wed, 16 Aug 2023 17:46:09 +0200 Subject: [PATCH 3/9] file_reader: use SqshReader2. --- include/sqsh_file_private.h | 3 ++- lib/file/file_reader.c | 24 +++++++----------------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/include/sqsh_file_private.h b/include/sqsh_file_private.h index 030e3ac78..c596cb14f 100644 --- a/include/sqsh_file_private.h +++ b/include/sqsh_file_private.h @@ -39,6 +39,7 @@ #include "sqsh_extract_private.h" #include "sqsh_mapper_private.h" #include "sqsh_metablock_private.h" +#include "sqsh_reader_private.h" #ifdef __cplusplus extern "C" { @@ -173,7 +174,7 @@ struct SqshFileReader { * @privatesection */ struct SqshFileIterator iterator; - struct SqshReader reader; + struct SqshReader2 reader; }; /** diff --git a/lib/file/file_reader.c b/lib/file/file_reader.c index ff13e9934..c26e2f697 100644 --- a/lib/file/file_reader.c +++ b/lib/file/file_reader.c @@ -35,7 +35,7 @@ #include "../../include/sqsh_archive_private.h" #include "../../include/sqsh_error.h" -#include "../../include/sqsh_primitive_private.h" +#include "../../include/sqsh_reader_private.h" #include "../utils/utils.h" @@ -43,14 +43,6 @@ static int file_iterator_next(void *iterator, size_t desired_size) { return sqsh_file_iterator_next(iterator, desired_size); } -static int -file_iterator_skip(void *iterator, size_t amount, size_t desired_size) { - return sqsh_file_iterator_skip(iterator, amount, desired_size); -} -static size_t -file_iterator_block_size(const void *iterator) { - return sqsh_file_iterator_block_size(iterator); -} static const uint8_t * file_iterator_data(const void *iterator) { return sqsh_file_iterator_data(iterator); @@ -60,10 +52,8 @@ file_iterator_size(const void *iterator) { return sqsh_file_iterator_size(iterator); } -static const struct SqshIteratorImpl file_reader_impl = { +static const struct SqshReader2IteratorImpl file_reader_impl = { .next = file_iterator_next, - .skip = file_iterator_skip, - .block_size = file_iterator_block_size, .data = file_iterator_data, .size = file_iterator_size, }; @@ -76,7 +66,7 @@ sqsh__file_reader_init( if (rv < 0) { goto out; } - rv = sqsh__reader_init( + rv = sqsh__reader2_init( &reader->reader, &file_reader_impl, &reader->iterator); out: return rv; @@ -105,22 +95,22 @@ sqsh_file_reader_new(const struct SqshFile *file, int *err) { int sqsh_file_reader_advance( struct SqshFileReader *reader, sqsh_index_t offset, size_t size) { - return sqsh__reader_advance(&reader->reader, offset, size); + return sqsh__reader2_advance(&reader->reader, offset, size); } const uint8_t * sqsh_file_reader_data(const struct SqshFileReader *reader) { - return sqsh__reader_data(&reader->reader); + return sqsh__reader2_data(&reader->reader); } size_t sqsh_file_reader_size(const struct SqshFileReader *reader) { - return sqsh__reader_size(&reader->reader); + return sqsh__reader2_size(&reader->reader); } int sqsh__file_reader_cleanup(struct SqshFileReader *reader) { - sqsh__reader_cleanup(&reader->reader); + sqsh__reader2_cleanup(&reader->reader); sqsh__file_iterator_cleanup(&reader->iterator); return 0; From 6757ae75aa56d876f7d45194857acbabd927863f Mon Sep 17 00:00:00 2001 From: Enno Boland Date: Wed, 16 Aug 2023 17:53:31 +0200 Subject: [PATCH 4/9] map_reader: use SqshReader2. --- include/sqsh_mapper_private.h | 3 ++- lib/mapper/map_reader.c | 25 +++++++------------------ 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/include/sqsh_mapper_private.h b/include/sqsh_mapper_private.h index c44df3acc..6271225b3 100644 --- a/include/sqsh_mapper_private.h +++ b/include/sqsh_mapper_private.h @@ -37,6 +37,7 @@ #include "sqsh_mapper.h" #include "sqsh_primitive_private.h" +#include "sqsh_reader_private.h" #include "sqsh_thread_private.h" #include @@ -480,7 +481,7 @@ struct SqshMapReader { uint64_t address; uint64_t upper_limit; struct SqshMapIterator iterator; - struct SqshReader reader; + struct SqshReader2 reader; }; /** diff --git a/lib/mapper/map_reader.c b/lib/mapper/map_reader.c index 443bc286b..2f9669790 100644 --- a/lib/mapper/map_reader.c +++ b/lib/mapper/map_reader.c @@ -41,15 +41,6 @@ map_iterator_next(void *iterator, size_t desired_size) { (void)desired_size; return sqsh__map_iterator_next(iterator); } -static int -map_iterator_skip(void *iterator, size_t amount, size_t desired_size) { - (void)desired_size; - return sqsh__map_iterator_skip(iterator, amount); -} -static size_t -map_iterator_block_size(const void *iterator) { - return sqsh__map_iterator_block_size(iterator); -} static const uint8_t * map_iterator_data(const void *iterator) { return sqsh__map_iterator_data(iterator); @@ -59,10 +50,8 @@ map_iterator_size(const void *iterator) { return sqsh__map_iterator_size(iterator); } -static const struct SqshIteratorImpl map_reader_impl = { +static const struct SqshReader2IteratorImpl map_reader_impl = { .next = map_iterator_next, - .skip = map_iterator_skip, - .block_size = map_iterator_block_size, .data = map_iterator_data, .size = map_iterator_size, }; @@ -85,7 +74,7 @@ sqsh__map_reader_init( if (rv < 0) { goto out; } - rv = sqsh__reader_init( + rv = sqsh__reader2_init( &reader->reader, &map_reader_impl, &reader->iterator); if (rv < 0) { goto out; @@ -93,7 +82,7 @@ sqsh__map_reader_init( reader->upper_limit = upper_limit; reader->address = start_address; - rv = sqsh__reader_advance(&reader->reader, offset, 0); + rv = sqsh__reader2_advance(&reader->reader, offset, 0); out: if (rv < 0) { sqsh__map_reader_cleanup(reader); @@ -117,7 +106,7 @@ int sqsh__map_reader_advance( struct SqshMapReader *reader, sqsh_index_t offset, size_t size) { reader->address += offset; - return sqsh__reader_advance(&reader->reader, offset, size); + return sqsh__reader2_advance(&reader->reader, offset, size); } int @@ -128,17 +117,17 @@ sqsh__map_reader_all(struct SqshMapReader *reader) { const uint8_t * sqsh__map_reader_data(const struct SqshMapReader *reader) { - return sqsh__reader_data(&reader->reader); + return sqsh__reader2_data(&reader->reader); } size_t sqsh__map_reader_size(const struct SqshMapReader *reader) { - return sqsh__reader_size(&reader->reader); + return sqsh__reader2_size(&reader->reader); } int sqsh__map_reader_cleanup(struct SqshMapReader *reader) { - sqsh__reader_cleanup(&reader->reader); + sqsh__reader2_cleanup(&reader->reader); sqsh__map_iterator_cleanup(&reader->iterator); return 0; From 82cd5edd928103e235f8d39c1b98762b65148dc3 Mon Sep 17 00:00:00 2001 From: Enno Boland Date: Wed, 16 Aug 2023 22:24:35 +0200 Subject: [PATCH 5/9] test/reader: import legacy reader tests --- test/reader/reader2.c | 227 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 224 insertions(+), 3 deletions(-) diff --git a/test/reader/reader2.c b/test/reader/reader2.c index 4e7e7d2c0..03d34a92e 100644 --- a/test/reader/reader2.c +++ b/test/reader/reader2.c @@ -61,9 +61,7 @@ test_iter_next(void *data, size_t desired_size) { (void)desired_size; if (iter->remaining == 0) { iter->data = ""; - } - if (iter->remaining == 0) { - return -1; + return 0; } iter->remaining--; iter->size = strlen(iter->data); @@ -304,6 +302,219 @@ test_reader2_advance_with_zero_size() { sqsh__reader2_cleanup(&reader); } +static void +test_reader2_advance_once(void) { + int rv; + struct SqshReader2 reader = {0}; + struct TestIterator iter = { + .data = "THIS IS A TEST STRING", .remaining = 1}; + + rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader2_advance(&reader, 0, 6); + assert(rv == 0); + + const uint8_t *data = sqsh__reader2_data(&reader); + assert(data == (void *)iter.data); + + sqsh__reader2_cleanup(&reader); +} + +static void +test_reader2_advance_once_with_offset(void) { + int rv; + struct SqshReader2 reader = {0}; + struct TestIterator iter = { + .data = "THIS IS A TEST STRING", .remaining = 1}; + rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader2_advance(&reader, 4, 6); + assert(rv == 0); + + const uint8_t *data = sqsh__reader2_data(&reader); + assert(data == (uint8_t *)&iter.data[4]); + + sqsh__reader2_cleanup(&reader); +} + +static void +test_reader2_advance_twice_with_offset(void) { + int rv; + struct SqshReader2 reader = {0}; + struct TestIterator iter = { + .data = "THIS IS A TEST STRING", .remaining = 1}; + + rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader2_advance(&reader, 4, 6); + assert(rv == 0); + + const uint8_t *data = sqsh__reader2_data(&reader); + assert(data == (uint8_t *)&iter.data[4]); + + rv = sqsh__reader2_advance(&reader, 6, 2); + assert(rv == 0); + + const uint8_t *data2 = sqsh__reader2_data(&reader); + assert(data2 == (uint8_t *)&iter.data[10]); + + sqsh__reader2_cleanup(&reader); +} + +static void +test_reader2_initial_advance(void) { + int rv; + struct SqshReader2 reader = {0}; + struct TestIterator iter = { + .data = "THIS IS A TEST STRING", .remaining = 1}; + rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader2_advance(&reader, 5, 3); + assert(rv == 0); + const uint8_t *data = sqsh__reader2_data(&reader); + assert(3 == sqsh__reader2_size(&reader)); + assert(memcmp(data, "IS ", 3) == 0); + assert(data == (uint8_t *)&iter.data[5]); + + sqsh__reader2_cleanup(&reader); +} + +static void +test_reader2_advance_to_out_of_bounds(void) { + int rv; + struct SqshReader2 reader = {0}; + struct TestIterator iter = { + .data = "THIS IS A TEST STRING", .remaining = 1}; + + rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader2_advance(&reader, strlen(iter.data), 1); + assert(rv < 0); + + sqsh__reader2_cleanup(&reader); +} + +static void +test_reader2_advance_over_boundary(void) { + int rv; + struct SqshReader2 reader = {0}; + struct TestIterator iter = {.data = "0123456789", .remaining = 2}; + + rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader2_advance(&reader, 9, 2); + assert(rv == 0); + const uint8_t *data = sqsh__reader2_data(&reader); + assert(2 == sqsh__reader2_size(&reader)); + assert(memcmp(data, "90", 2) == 0); + + sqsh__reader2_cleanup(&reader); +} + +static void +test_reader2_initial_advance_2(void) { + int rv; + struct SqshReader2 reader = {0}; + struct TestIterator iter = {.data = "ABCD", .remaining = 10}; + + rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader2_advance(&reader, 7, 5); + assert(rv == 0); + + const uint8_t *data = sqsh__reader2_data(&reader); + assert(sqsh__reader2_size(&reader) == 5); + assert(memcmp(data, "DABCD", 5) == 0); + + sqsh__reader2_cleanup(&reader); +} + +static void +test_reader2_error_1(void) { + int rv; + struct SqshReader2 reader = {0}; + struct TestIterator iter = {.data = "AB", .remaining = 10}; + + rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader2_advance(&reader, 0, 4); + assert(rv == 0); + + const uint8_t *data = sqsh__reader2_data(&reader); + assert(sqsh__reader2_size(&reader) == 4); + assert(memcmp(data, "ABAB", 4) == 0); + + iter.data = "12"; + rv = sqsh__reader2_advance(&reader, 4, 4); + assert(rv == 0); + + data = sqsh__reader2_data(&reader); + assert(sqsh__reader2_size(&reader) == 4); + assert(memcmp(data, "1212", 4) == 0); + + sqsh__reader2_cleanup(&reader); +} + +static void +test_reader2_map_into_buffer(void) { + int rv; + struct SqshReader2 reader = {0}; + struct TestIterator iter = {.data = "0123456789", .remaining = 2}; + + rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader2_advance(&reader, 8, 4); + assert(rv == 0); + + const uint8_t *data = sqsh__reader2_data(&reader); + assert(sqsh__reader2_size(&reader) == 4); + assert(memcmp(data, "8901", 4) == 0); + + rv = sqsh__reader2_advance(&reader, 1, 4); + assert(rv == 0); + + data = sqsh__reader2_data(&reader); + assert(sqsh__reader2_size(&reader) == 4); + assert(memcmp(data, "9012", 4) == 0); + + sqsh__reader2_cleanup(&reader); +} + +static void +test_reader2_map_into_buffer_twice(void) { + int rv; + struct SqshReader2 reader = {0}; + struct TestIterator iter = {.data = "0123456789", .remaining = 3}; + + rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader2_advance(&reader, 8, 4); + assert(rv == 0); + + const uint8_t *data = sqsh__reader2_data(&reader); + assert(sqsh__reader2_size(&reader) == 4); + assert(memcmp(data, "8901", 4) == 0); + + rv = sqsh__reader2_advance(&reader, 1, 14); + assert(rv == 0); + + data = sqsh__reader2_data(&reader); + assert(sqsh__reader2_size(&reader) == 14); + assert(memcmp(data, "90123456789012", 14) == 0); + + sqsh__reader2_cleanup(&reader); +} + DECLARE_TESTS TEST(test_reader2_init) TEST(test_reader2_advance_to_block) @@ -315,4 +526,14 @@ TEST(test_reader2_from_buffered_to_buffered) TEST(test_reader2_from_buffered_to_buffered) TEST(test_reader2_advance_inside_buffered) TEST(test_reader2_advance_with_zero_size) +TEST(test_reader2_advance_once) +TEST(test_reader2_advance_once_with_offset) +TEST(test_reader2_advance_twice_with_offset) +TEST(test_reader2_initial_advance) +TEST(test_reader2_advance_to_out_of_bounds) +TEST(test_reader2_advance_over_boundary) +TEST(test_reader2_initial_advance_2) +TEST(test_reader2_error_1) +TEST(test_reader2_map_into_buffer) +TEST(test_reader2_map_into_buffer_twice) END_TESTS From c336b2e17fa0cda9ea190bfa3f038a5a589c3451 Mon Sep 17 00:00:00 2001 From: Enno Boland Date: Thu, 17 Aug 2023 12:33:51 +0200 Subject: [PATCH 6/9] reader: fix when end offset aligns with block end This fixes a bug when the data storage wrongfully points to the iterator when it actually needs to read from the buffer. A safeguard `assert()` call has been added to the `reader_fill_buffer()` to detect this error in case of regression. Also a test case has been added to reproduce this error. --- lib/reader/reader2.c | 3 ++- test/reader/reader2.c | 58 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/lib/reader/reader2.c b/lib/reader/reader2.c index 052036bd3..c1b61ec41 100644 --- a/lib/reader/reader2.c +++ b/lib/reader/reader2.c @@ -143,6 +143,7 @@ reader_fill_buffer(struct SqshReader2 *reader, size_t size) { reader->offset = 0; reader->data = sqsh__buffer_data(buffer); reader->size = size; + assert(reader->iterator_offset != 0); out: return rv; } @@ -199,7 +200,7 @@ handle_mapped(struct SqshReader2 *reader, sqsh_index_t offset, size_t size) { rv = -SQSH_ERROR_INTEGER_OVERFLOW; goto out; } - if (end_offset < impl->size(iterator)) { + if (end_offset <= impl->size(iterator)) { const uint8_t *data = impl->data(iterator); reader->data = &data[offset]; reader->size = size; diff --git a/test/reader/reader2.c b/test/reader/reader2.c index 03d34a92e..0862fece5 100644 --- a/test/reader/reader2.c +++ b/test/reader/reader2.c @@ -31,6 +31,7 @@ * @file integration.c */ +#include "../include/sqsh_error.h" #include "../include/sqsh_reader_private.h" #include "common.h" #include @@ -38,21 +39,24 @@ struct TestIterator { char *data; + char *current_data; int remaining; - int block_size; - int size; }; static const uint8_t * test_iter_data(const void *data) { struct TestIterator *iter = (struct TestIterator *)data; - return (uint8_t *)iter->data; + return (uint8_t *)iter->current_data; } static size_t test_iter_size(const void *data) { struct TestIterator *iter = (struct TestIterator *)data; - return iter->size; + if (iter->current_data == NULL) { + return 0; + } else { + return strlen(iter->current_data); + } } static int @@ -60,12 +64,12 @@ test_iter_next(void *data, size_t desired_size) { struct TestIterator *iter = (struct TestIterator *)data; (void)desired_size; if (iter->remaining == 0) { - iter->data = ""; + iter->current_data = ""; return 0; } + iter->current_data = iter->data; iter->remaining--; - iter->size = strlen(iter->data); - return iter->size; + return strlen(iter->current_data); } static const struct SqshReader2IteratorImpl test_iter = { @@ -286,7 +290,6 @@ test_reader2_advance_with_zero_size() { rv = sqsh__reader2_advance(&reader, 3, 0); assert(rv == 0); - const uint8_t *data = sqsh__reader2_data(&reader); size_t size = sqsh__reader2_size(&reader); assert(size == 0); @@ -294,7 +297,7 @@ test_reader2_advance_with_zero_size() { rv = sqsh__reader2_advance(&reader, 0, 4); assert(rv == 0); - data = sqsh__reader2_data(&reader); + const uint8_t *data = sqsh__reader2_data(&reader); size = sqsh__reader2_size(&reader); assert(size == 4); assert(memcmp(data, "ttes", 4) == 0); @@ -515,6 +518,42 @@ test_reader2_map_into_buffer_twice(void) { sqsh__reader2_cleanup(&reader); } +static void +test_reader2_extend_size_till_end(void) { + int rv; + struct SqshReader2 reader = {0}; + struct TestIterator iter = {.data = "0123456789", .remaining = 2}; + + rv = sqsh__reader2_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader2_advance(&reader, 4, 4); + assert(rv == 0); + + const uint8_t *data = sqsh__reader2_data(&reader); + assert(sqsh__reader2_size(&reader) == 4); + assert(memcmp(data, "4567", 4) == 0); + + rv = sqsh__reader2_advance(&reader, 0, 6); + assert(rv == 0); + + data = sqsh__reader2_data(&reader); + assert(sqsh__reader2_size(&reader) == 6); + assert(memcmp(data, "456789", 6) == 0); + + iter.data = "ABCDEF"; + + rv = sqsh__reader2_advance(&reader, 0, 12); + data = sqsh__reader2_data(&reader); + assert(sqsh__reader2_size(&reader) == 12); + assert(memcmp(data, "456789ABCDEF", 12) == 0); + + // rv = sqsh__reader2_advance(&reader, 0, 13); + // assert(rv == -SQSH_ERROR_OUT_OF_BOUNDS); + + sqsh__reader2_cleanup(&reader); +} + DECLARE_TESTS TEST(test_reader2_init) TEST(test_reader2_advance_to_block) @@ -536,4 +575,5 @@ TEST(test_reader2_initial_advance_2) TEST(test_reader2_error_1) TEST(test_reader2_map_into_buffer) TEST(test_reader2_map_into_buffer_twice) +TEST(test_reader2_extend_size_till_end) END_TESTS From d94e41549543ce8ea8acb549ab8c84b99d705b4b Mon Sep 17 00:00:00 2001 From: Enno Boland Date: Thu, 17 Aug 2023 12:39:14 +0200 Subject: [PATCH 7/9] metablock_reader: use SqshReader2. --- include/sqsh_metablock_private.h | 2 +- lib/metablock/metablock_reader.c | 24 ++++++------------------ 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/include/sqsh_metablock_private.h b/include/sqsh_metablock_private.h index fa0d2823d..e61022d03 100644 --- a/include/sqsh_metablock_private.h +++ b/include/sqsh_metablock_private.h @@ -145,7 +145,7 @@ struct SqshMetablockReader { /** * @privatesection */ - struct SqshReader reader; + struct SqshReader2 reader; struct SqshMetablockIterator iterator; }; diff --git a/lib/metablock/metablock_reader.c b/lib/metablock/metablock_reader.c index 7e0e4a964..a1fe1250b 100644 --- a/lib/metablock/metablock_reader.c +++ b/lib/metablock/metablock_reader.c @@ -45,16 +45,6 @@ metablock_iterator_next(void *iterator, size_t desired_size) { (void)desired_size; return sqsh__metablock_iterator_next(iterator); } -static int -metablock_iterator_skip(void *iterator, size_t amount, size_t desired_size) { - (void)desired_size; - return sqsh__metablock_iterator_skip(iterator, amount); -} -static size_t -metablock_iterator_block_size(const void *iterator) { - (void)iterator; - return SQSH_METABLOCK_BLOCK_SIZE; -} static const uint8_t * metablock_iterator_data(const void *iterator) { return sqsh__metablock_iterator_data(iterator); @@ -64,10 +54,8 @@ metablock_iterator_size(const void *iterator) { return sqsh__metablock_iterator_size(iterator); } -static const struct SqshIteratorImpl metablock_reader_impl = { +static const struct SqshReader2IteratorImpl metablock_reader_impl = { .next = metablock_iterator_next, - .skip = metablock_iterator_skip, - .block_size = metablock_iterator_block_size, .data = metablock_iterator_data, .size = metablock_iterator_size, }; @@ -82,7 +70,7 @@ sqsh__metablock_reader_init( if (rv < 0) { goto out; } - rv = sqsh__reader_init( + rv = sqsh__reader2_init( &reader->reader, &metablock_reader_impl, &reader->iterator); out: return rv; @@ -91,22 +79,22 @@ sqsh__metablock_reader_init( int sqsh__metablock_reader_advance( struct SqshMetablockReader *reader, sqsh_index_t offset, size_t size) { - return sqsh__reader_advance(&reader->reader, offset, size); + return sqsh__reader2_advance(&reader->reader, offset, size); } const uint8_t * sqsh__metablock_reader_data(const struct SqshMetablockReader *reader) { - return sqsh__reader_data(&reader->reader); + return sqsh__reader2_data(&reader->reader); } size_t sqsh__metablock_reader_size(const struct SqshMetablockReader *reader) { - return sqsh__reader_size(&reader->reader); + return sqsh__reader2_size(&reader->reader); } int sqsh__metablock_reader_cleanup(struct SqshMetablockReader *reader) { - sqsh__reader_cleanup(&reader->reader); + sqsh__reader2_cleanup(&reader->reader); sqsh__metablock_iterator_cleanup(&reader->iterator); return 0; From d5dc3adc12819bdffd53f9420eaa98c5c9ff7ebf Mon Sep 17 00:00:00 2001 From: Enno Boland Date: Thu, 17 Aug 2023 12:42:44 +0200 Subject: [PATCH 8/9] primitive/reader: remove; replaced by reader2. --- include/sqsh_primitive_private.h | 104 ---------- lib/meson.build | 1 - lib/primitive/reader.c | 331 ------------------------------ test/meson.build | 1 - test/primitive/reader.c | 335 ------------------------------- 5 files changed, 772 deletions(-) delete mode 100644 lib/primitive/reader.c delete mode 100644 test/primitive/reader.c diff --git a/include/sqsh_primitive_private.h b/include/sqsh_primitive_private.h index a46955aa9..a592af21c 100644 --- a/include/sqsh_primitive_private.h +++ b/include/sqsh_primitive_private.h @@ -522,110 +522,6 @@ sqsh__lru_touch(struct SqshLru *lru, sqsh_index_t id); */ SQSH_NO_EXPORT int sqsh__lru_cleanup(struct SqshLru *lru); -/*************************************** - * primitive/reader.c - */ - -/** - * @internal - * @brief A buffer that is used to read data from a SqshReader. - */ -struct SqshIteratorImpl { - /** - * @privatesection - */ - int (*next)(void *iterator, size_t desired_size); - int (*skip)(void *iterator, size_t amount, size_t desired_size); - size_t (*block_size)(const void *iterator); - const uint8_t *(*data)(const void *iterator); - size_t (*size)(const void *iterator); -}; - -/** - * @internal - * @brief A buffer that is used to read data from a SqshReader. - */ -struct SqshReader { - /** - * @privatesection - */ - const struct SqshIteratorImpl *impl; - void *iterator; - - sqsh_index_t iterator_offset; - sqsh_index_t buffer_offset; - sqsh_index_t data_offset; - size_t size; - size_t data_size; - struct SqshBuffer buffer; - const uint8_t *data; -}; - -/** - * @internal - * @memberof SqshReader - * @brief Initializes a reader. - * - * @param[out] reader Pointer to the metablock reader to be initialized. - * @param[in] impl Implementation of the iterator. - * @param[in] iterator Iterator to use for the reader. - * - * @return 0 on success, less than zero on error. - */ -SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__reader_init( - struct SqshReader *reader, const struct SqshIteratorImpl *impl, - void *iterator); - -/** - * @internal - * @memberof SqshReader - * @brief Advances the reader by the given offset and size. - * - * @param[in,out] reader Pointer to the metablock reader to be advanced. - * @param[in] offset Offset to advance the reader by. - * @param[in] size Size of the block to advance the reader by. - * - * @return 0 on success, less than zero on error. - */ -SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__reader_advance( - struct SqshReader *reader, sqsh_index_t offset, size_t size); - -/** - * @internal - * @memberof SqshReader - * @brief Returns a pointer to the data at the current position of the metablock - * reader. - * - * @param[in] reader Pointer to the metablock reader. - * - * @return Pointer to the data at the current position of the metablock reader. - */ -SQSH_NO_EXPORT const uint8_t * -sqsh__reader_data(const struct SqshReader *reader); - -/** - * @internal - * @memberof SqshReader - * @brief Returns the size of the data at the current position of the metablock - * reader. - * - * @param[in] reader Pointer to the metablock reader. - * - * @return Size of the data at the current position of the metablock reader. - */ -SQSH_NO_EXPORT size_t sqsh__reader_size(const struct SqshReader *reader); - -/** - * @internal - * @memberof SqshReader - * @brief Cleans up and frees the resources used by the metablock reader. - * - * @param[in,out] reader Pointer to the metablock reader to be cleaned up. - * - * @return 0 on success, less than zero on error. - */ -SQSH_NO_EXPORT int sqsh__reader_cleanup(struct SqshReader *reader); - #ifdef __cplusplus } #endif diff --git a/lib/meson.build b/lib/meson.build index b84654520..95a3ec158 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -41,7 +41,6 @@ libsqsh_sources = files( 'primitive/lru.c', 'primitive/rc_hash_map.c', 'primitive/rc_map.c', - 'primitive/reader.c', 'table/export_table.c', 'table/fragment_table.c', 'table/id_table.c', diff --git a/lib/primitive/reader.c b/lib/primitive/reader.c deleted file mode 100644 index 499e8f46b..000000000 --- a/lib/primitive/reader.c +++ /dev/null @@ -1,331 +0,0 @@ -/****************************************************************************** - * * - * Copyright (c) 2023, Enno Boland * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are * - * met: * - * * - * * Redistributions of source code must retain the above copyright notice, * - * this list of conditions and the following disclaimer. * - * * Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * * - ******************************************************************************/ - -/** - * @author Enno Boland (mail@eboland.de) - * @file reader.c - */ - -#include "../../include/sqsh_primitive_private.h" - -#include "../../include/sqsh_archive_private.h" -#include "../../include/sqsh_error.h" - -#include "../utils/utils.h" - -/** - * # Algoritm - * - * The reader is a simple wrapper around an arbitrary iterator. In contrast - * to an iterator, that just presents chunks of data, the reader allows to - * read a specific range of data. The reader will try to map the requested - * range to the current data. If the requested range is not fully contained - * in the current data, the reader copy the data into a buffer and presents - * the data from the buffer. - * - * 1. Forward the iterator until the start of the requested range is reached. - * - * 2. Test if the requested range is fully contained in the current iterator - * block. If so, return the data directly. - * - * 3. If the requested range is not fully contained in the current iterator - * block, copy the data into a buffer until the end of the requested range - * is reached. - * - * - * ## Scenarios: - * - * ### Legend - * - * ``` - * ##### = directly mapped data - * - * ===== = data in buffer - * ``` - * - * ### Scenario 1: direct to direct - * - * Before: - * ``` - * Start End - * v v - * ########################## - * ``` - * After: - * ``` - * Start End - * v v - * ########################## - * ``` - * - * ### Scenario 2: direct to buffer - * - * Before: - * ``` - * Start End - * v v - * ########################## - * ``` - * After: - * ``` - * Start End - * v v - * ======= - * ########################## - * ``` - * ### Scenario 2: buffer to direct - * - * Before: - * ``` - * Start End - * v v - * ======= - * ########################## - * ``` - * After: - * ``` - * Start End - * v v - * ########################## - * ``` - * - * ### Scenario 3: buffer over multiple blocks - * Before: - * ``` - * Start End - * v v - * ########################## - * ``` - * After: - * ``` - * Start End - * v v - * ================================ - * ########################## - * ``` - */ - -int -sqsh__reader_init( - struct SqshReader *reader, const struct SqshIteratorImpl *impl, - void *iterator) { - int rv; - memset(reader, 0, sizeof(*reader)); - rv = sqsh__buffer_init(&reader->buffer); - if (rv < 0) { - return rv; - } - reader->impl = impl; - reader->iterator = iterator; - reader->iterator_offset = 0; - reader->data_offset = 0; - reader->data_size = 0; - reader->buffer_offset = 0; - reader->size = 0; - reader->data = NULL; - - return 0; -} - -static int -iterator_forward_to( - struct SqshReader *reader, sqsh_index_t offset, size_t desired_size) { - int rv; - const struct SqshIteratorImpl *impl = reader->impl; - void *iterator = reader->iterator; - const size_t block_size = impl->block_size(iterator); - const size_t iterator_size = impl->size(iterator); - const size_t current_end_offset = reader->iterator_offset + iterator_size; - if (offset < current_end_offset) { - return 0; - } - size_t amount = (offset - current_end_offset) / block_size; - reader->iterator_offset = current_end_offset + amount * block_size; - rv = impl->skip(iterator, amount + 1, desired_size); - if (rv < 0) { - return rv; - } else if (rv == 0) { - return -SQSH_ERROR_OUT_OF_BOUNDS; - } - - return 0; -} - -static int -map_buffered( - struct SqshReader *reader, sqsh_index_t new_offset, - size_t new_end_offset) { - int rv; - struct SqshBuffer new_buffer = {0}; - const sqsh_index_t buffer_offset = reader->buffer_offset; - const sqsh_index_t iterator_offset = reader->iterator_offset; - const size_t target_size = new_end_offset - new_offset; - const struct SqshIteratorImpl *impl = reader->impl; - void *iterator = reader->iterator; - - rv = sqsh__buffer_init(&new_buffer); - if (rv < 0) { - goto out; - } - if (new_offset < buffer_offset) { - /* Should never happen */ - abort(); - } - - /* - * 1. If the requested range is covered by the old buffer, copy - * the data starting from the old buffer to the new buffer. - */ - if (new_offset < iterator_offset && buffer_offset < iterator_offset) { - sqsh_index_t end_offset = SQSH_MIN(new_end_offset, iterator_offset); - - size_t size = end_offset - new_offset; - sqsh_index_t inner_offset = new_offset - buffer_offset; - const uint8_t *data = sqsh__buffer_data(&reader->buffer); - - rv = sqsh__buffer_append(&new_buffer, &data[inner_offset], size); - if (rv < 0) { - goto out; - } - } - - /* - * 2. The remainder of the requested range is read from the iterator - */ - sqsh_index_t inner_offset = 0; - if (new_offset > iterator_offset) { - inner_offset = new_offset - iterator_offset; - } - if (inner_offset >= impl->size(iterator)) { - rv = -SQSH_ERROR_OUT_OF_BOUNDS; - goto out; - } - /* We expect, that the iterator is already at the correct position. */ - while (true) { - const size_t size = SQSH_MIN( - impl->size(iterator) - inner_offset, - target_size - sqsh__buffer_size(&new_buffer)); - const uint8_t *data = impl->data(iterator); - - rv = sqsh__buffer_append(&new_buffer, &data[inner_offset], size); - if (rv < 0) { - goto out; - } - - inner_offset = 0; - if (sqsh__buffer_size(&new_buffer) < target_size) { - const size_t desired_size = - target_size - sqsh__buffer_size(&new_buffer); - reader->iterator_offset += impl->size(iterator); - rv = impl->next(iterator, desired_size); - if (rv < 0) { - goto out; - } else if (rv == 0) { - rv = -SQSH_ERROR_OUT_OF_BOUNDS; - goto out; - } - } else { - break; - } - } - - rv = sqsh__buffer_move(&reader->buffer, &new_buffer); - if (rv < 0) { - goto out; - } - reader->data_offset = new_offset; - reader->buffer_offset = new_offset; - reader->data = sqsh__buffer_data(&reader->buffer); - reader->data_size = sqsh__buffer_size(&reader->buffer); - -out: - sqsh__buffer_cleanup(&new_buffer); - return rv; -} - -int -sqsh__reader_advance( - struct SqshReader *reader, sqsh_index_t offset, size_t size) { - int rv = 0; - sqsh_index_t new_offset; - sqsh_index_t new_end_offset; - if (SQSH_ADD_OVERFLOW(offset, reader->data_offset, &new_offset)) { - return -SQSH_ERROR_INTEGER_OVERFLOW; - } - if (SQSH_ADD_OVERFLOW(new_offset, size, &new_end_offset)) { - return -SQSH_ERROR_INTEGER_OVERFLOW; - } - - /* Finding the start of the new range. */ - if (new_offset >= reader->iterator_offset) { - rv = iterator_forward_to(reader, new_offset, 1); - if (rv < 0) { - return rv; - } - reader->data = reader->impl->data(reader->iterator); - reader->data_size = reader->impl->size(reader->iterator); - reader->data_offset = reader->iterator_offset; - sqsh__buffer_cleanup(&reader->buffer); - } - - /* Forward the data pointer to the requested offset. */ - const sqsh_index_t inner_offset = new_offset - reader->data_offset; - reader->data += inner_offset; - reader->data_size -= inner_offset; - reader->data_offset = new_offset; - - reader->size = size; - - /* If the requested range is not covered by the iterator, */ - /* turn it into a buffer and extend it. */ - if (new_end_offset > reader->data_offset + reader->data_size) { - rv = map_buffered(reader, new_offset, new_end_offset); - if (rv < 0) { - return rv; - } - } - - return 0; -} - -const uint8_t * -sqsh__reader_data(const struct SqshReader *reader) { - return reader->data; -} - -size_t -sqsh__reader_size(const struct SqshReader *reader) { - return reader->size; -} - -int -sqsh__reader_cleanup(struct SqshReader *reader) { - sqsh__buffer_cleanup(&reader->buffer); - - return 0; -} diff --git a/test/meson.build b/test/meson.build index 6cef9f6bd..548c8cadc 100644 --- a/test/meson.build +++ b/test/meson.build @@ -33,7 +33,6 @@ sqsh_test = [ 'primitive/lru.c', 'primitive/rc_hash_map.c', 'primitive/rc_map.c', - 'primitive/reader.c', 'tree/walker.c', 'xattr/xattr_iterator.c', ] diff --git a/test/primitive/reader.c b/test/primitive/reader.c deleted file mode 100644 index 87a8daaa6..000000000 --- a/test/primitive/reader.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * BSD 2-Clause License - * - * Copyright (c) 2023, Enno Boland - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @author Enno Boland (mail@eboland.de) - * @file reader.c - */ - -#include "../common.h" -#include - -#include "../../include/sqsh_primitive_private.h" - -struct TestIterator { - char *data; - int remaining; - int block_size; - int size; -}; - -static const uint8_t * -test_iter_data(const void *data) { - struct TestIterator *iter = (struct TestIterator *)data; - return (uint8_t *)iter->data; -} - -static size_t -test_iter_size(const void *data) { - struct TestIterator *iter = (struct TestIterator *)data; - return iter->size; -} - -static size_t -test_iter_block_size(const void *data) { - struct TestIterator *iter = (struct TestIterator *)data; - if (iter->block_size == 0) { - iter->block_size = strlen(iter->data); - } - return iter->block_size; -} - -static int -test_iter_skip(void *data, size_t amount, size_t desired_size) { - struct TestIterator *iter = (struct TestIterator *)data; - (void)desired_size; - if (amount > 0) { - iter->remaining -= amount - 1; - } - if (iter->remaining == 0) { - iter->data = ""; - } - if (amount > (unsigned int)iter->remaining) { - return -1; - } - iter->remaining--; - iter->size = strlen(iter->data); - return iter->size; -} - -static int -test_iter_next(void *data, size_t desired_size) { - return test_iter_skip(data, 1, desired_size); -} - -static const struct SqshIteratorImpl impl = { - .next = test_iter_next, - .skip = test_iter_skip, - .data = test_iter_data, - .size = test_iter_size, - .block_size = test_iter_block_size}; - -static void -reader_init(void) { - int rv; - struct SqshReader reader = {0}; - struct TestIterator iter = {.data = ""}; - - rv = sqsh__reader_init(&reader, &impl, &iter); - assert(rv == 0); - - sqsh__reader_cleanup(&reader); -} - -static void -reader_advance_once(void) { - int rv; - struct SqshReader reader = {0}; - struct TestIterator iter = { - .data = "THIS IS A TEST STRING", .remaining = 1}; - - rv = sqsh__reader_init(&reader, &impl, &iter); - assert(rv == 0); - - rv = sqsh__reader_advance(&reader, 0, 6); - assert(rv == 0); - - const uint8_t *data = sqsh__reader_data(&reader); - assert(data == (void *)iter.data); - - sqsh__reader_cleanup(&reader); -} - -static void -reader_advance_once_with_offset(void) { - int rv; - struct SqshReader reader = {0}; - struct TestIterator iter = { - .data = "THIS IS A TEST STRING", .remaining = 1}; - rv = sqsh__reader_init(&reader, &impl, &iter); - assert(rv == 0); - - rv = sqsh__reader_advance(&reader, 4, 6); - assert(rv == 0); - - const uint8_t *data = sqsh__reader_data(&reader); - assert(data == (uint8_t *)&iter.data[4]); - - sqsh__reader_cleanup(&reader); -} - -static void -reader_advance_twice_with_offset(void) { - int rv; - struct SqshReader reader = {0}; - struct TestIterator iter = { - .data = "THIS IS A TEST STRING", .remaining = 1}; - - rv = sqsh__reader_init(&reader, &impl, &iter); - assert(rv == 0); - - rv = sqsh__reader_advance(&reader, 4, 6); - assert(rv == 0); - - const uint8_t *data = sqsh__reader_data(&reader); - assert(data == (uint8_t *)&iter.data[4]); - - rv = sqsh__reader_advance(&reader, 6, 2); - assert(rv == 0); - - const uint8_t *data2 = sqsh__reader_data(&reader); - assert(data2 == (uint8_t *)&iter.data[10]); - - sqsh__reader_cleanup(&reader); -} - -static void -reader_initial_advance(void) { - int rv; - struct SqshReader reader = {0}; - struct TestIterator iter = { - .data = "THIS IS A TEST STRING", .remaining = 1}; - rv = sqsh__reader_init(&reader, &impl, &iter); - assert(rv == 0); - - rv = sqsh__reader_advance(&reader, 5, 3); - assert(rv == 0); - const uint8_t *data = sqsh__reader_data(&reader); - assert(3 == sqsh__reader_size(&reader)); - assert(memcmp(data, "IS ", 3) == 0); - assert(data == (uint8_t *)&iter.data[5]); - - sqsh__reader_cleanup(&reader); -} - -static void -reader_advance_to_out_of_bounds(void) { - int rv; - struct SqshReader reader = {0}; - struct TestIterator iter = { - .data = "THIS IS A TEST STRING", .remaining = 1}; - - rv = sqsh__reader_init(&reader, &impl, &iter); - assert(rv == 0); - - rv = sqsh__reader_advance(&reader, strlen(iter.data), 1); - assert(rv < 0); - - sqsh__reader_cleanup(&reader); -} - -static void -reader_advance_over_boundary(void) { - int rv; - struct SqshReader reader = {0}; - struct TestIterator iter = {.data = "0123456789", .remaining = 2}; - - rv = sqsh__reader_init(&reader, &impl, &iter); - assert(rv == 0); - - rv = sqsh__reader_advance(&reader, 9, 2); - assert(rv == 0); - const uint8_t *data = sqsh__reader_data(&reader); - assert(2 == sqsh__reader_size(&reader)); - assert(memcmp(data, "90", 2) == 0); - - sqsh__reader_cleanup(&reader); -} - -static void -reader_initial_advance_2(void) { - int rv; - struct SqshReader reader = {0}; - struct TestIterator iter = {.data = "ABCD", .remaining = 10}; - - rv = sqsh__reader_init(&reader, &impl, &iter); - assert(rv == 0); - - rv = sqsh__reader_advance(&reader, 7, 5); - assert(rv == 0); - - const uint8_t *data = sqsh__reader_data(&reader); - assert(sqsh__reader_size(&reader) == 5); - assert(memcmp(data, "DABCD", 5) == 0); - - sqsh__reader_cleanup(&reader); -} - -static void -reader_error_1(void) { - int rv; - struct SqshReader reader = {0}; - struct TestIterator iter = {.data = "AB", .remaining = 10}; - - rv = sqsh__reader_init(&reader, &impl, &iter); - assert(rv == 0); - - rv = sqsh__reader_advance(&reader, 0, 4); - assert(rv == 0); - - const uint8_t *data = sqsh__reader_data(&reader); - assert(sqsh__reader_size(&reader) == 4); - assert(memcmp(data, "ABAB", 4) == 0); - - iter.data = "12"; - rv = sqsh__reader_advance(&reader, 4, 4); - assert(rv == 0); - - data = sqsh__reader_data(&reader); - assert(sqsh__reader_size(&reader) == 4); - assert(memcmp(data, "1212", 4) == 0); - - sqsh__reader_cleanup(&reader); -} - -static void -reader_map_into_buffer(void) { - int rv; - struct SqshReader reader = {0}; - struct TestIterator iter = {.data = "0123456789", .remaining = 2}; - - rv = sqsh__reader_init(&reader, &impl, &iter); - assert(rv == 0); - - rv = sqsh__reader_advance(&reader, 8, 4); - assert(rv == 0); - - const uint8_t *data = sqsh__reader_data(&reader); - assert(sqsh__reader_size(&reader) == 4); - assert(memcmp(data, "8901", 4) == 0); - - rv = sqsh__reader_advance(&reader, 1, 4); - assert(rv == 0); - - data = sqsh__reader_data(&reader); - assert(sqsh__reader_size(&reader) == 4); - assert(memcmp(data, "9012", 4) == 0); - - sqsh__reader_cleanup(&reader); -} - -static void -reader_map_into_buffer_twice(void) { - int rv; - struct SqshReader reader = {0}; - struct TestIterator iter = {.data = "0123456789", .remaining = 3}; - - rv = sqsh__reader_init(&reader, &impl, &iter); - assert(rv == 0); - - rv = sqsh__reader_advance(&reader, 8, 4); - assert(rv == 0); - - const uint8_t *data = sqsh__reader_data(&reader); - assert(sqsh__reader_size(&reader) == 4); - assert(memcmp(data, "8901", 4) == 0); - - rv = sqsh__reader_advance(&reader, 1, 14); - assert(rv == 0); - - data = sqsh__reader_data(&reader); - assert(sqsh__reader_size(&reader) == 14); - assert(memcmp(data, "90123456789012", 14) == 0); - - sqsh__reader_cleanup(&reader); -} - -DECLARE_TESTS -TEST(reader_init) -TEST(reader_advance_once) -TEST(reader_advance_once_with_offset) -TEST(reader_advance_twice_with_offset) -TEST(reader_initial_advance) -TEST(reader_advance_to_out_of_bounds) -TEST(reader_advance_over_boundary) -TEST(reader_initial_advance_2) -TEST(reader_error_1) -TEST(reader_map_into_buffer) -TEST(reader_map_into_buffer_twice) -END_TESTS From 1393fb03030b56b85d679d297a5327c6ee61fce0 Mon Sep 17 00:00:00 2001 From: Enno Boland Date: Thu, 17 Aug 2023 12:49:03 +0200 Subject: [PATCH 9/9] reader: rename reader2 to reader. --- include/sqsh_file_private.h | 2 +- include/sqsh_mapper_private.h | 2 +- include/sqsh_metablock_private.h | 2 +- include/sqsh_reader_private.h | 34 +- lib/file/file_reader.c | 12 +- lib/mapper/map_reader.c | 14 +- lib/meson.build | 2 +- lib/metablock/metablock_reader.c | 12 +- lib/reader/{reader2.c => reader.c} | 32 +- test/meson.build | 2 +- test/reader/reader.c | 579 +++++++++++++++++++++++++++++ test/reader/reader2.c | 579 ----------------------------- 12 files changed, 636 insertions(+), 636 deletions(-) rename lib/reader/{reader2.c => reader.c} (86%) create mode 100644 test/reader/reader.c delete mode 100644 test/reader/reader2.c diff --git a/include/sqsh_file_private.h b/include/sqsh_file_private.h index c596cb14f..f963f910b 100644 --- a/include/sqsh_file_private.h +++ b/include/sqsh_file_private.h @@ -174,7 +174,7 @@ struct SqshFileReader { * @privatesection */ struct SqshFileIterator iterator; - struct SqshReader2 reader; + struct SqshReader reader; }; /** diff --git a/include/sqsh_mapper_private.h b/include/sqsh_mapper_private.h index 6271225b3..04fd99155 100644 --- a/include/sqsh_mapper_private.h +++ b/include/sqsh_mapper_private.h @@ -481,7 +481,7 @@ struct SqshMapReader { uint64_t address; uint64_t upper_limit; struct SqshMapIterator iterator; - struct SqshReader2 reader; + struct SqshReader reader; }; /** diff --git a/include/sqsh_metablock_private.h b/include/sqsh_metablock_private.h index e61022d03..fa0d2823d 100644 --- a/include/sqsh_metablock_private.h +++ b/include/sqsh_metablock_private.h @@ -145,7 +145,7 @@ struct SqshMetablockReader { /** * @privatesection */ - struct SqshReader2 reader; + struct SqshReader reader; struct SqshMetablockIterator iterator; }; diff --git a/include/sqsh_reader_private.h b/include/sqsh_reader_private.h index 73070cad9..fa874446c 100644 --- a/include/sqsh_reader_private.h +++ b/include/sqsh_reader_private.h @@ -43,10 +43,10 @@ extern "C" { #endif /*************************************** - * reader/reader2.c + * reader/reader.c */ -struct SqshReader2IteratorImpl { +struct SqshReaderIteratorImpl { int (*next)(void *iterator, size_t desired_size); const uint8_t *(*data)(const void *iterator); size_t (*size)(const void *iterator); @@ -55,7 +55,7 @@ struct SqshReader2IteratorImpl { /** * @brief An iterator over extended attributes. */ -struct SqshReader2 { +struct SqshReader { /** * @privatesection */ @@ -68,7 +68,7 @@ struct SqshReader2 { /** * @brief interface to the iterator. */ - const struct SqshReader2IteratorImpl *iterator_impl; + const struct SqshReaderIteratorImpl *iterator_impl; /** * @brief The offset of the iterator. @@ -124,7 +124,7 @@ struct SqshReader2 { /** * @internal - * @memberof SqshReader2 + * @memberof SqshReader * @brief Initializes a reader. * * @param[out] reader Pointer to the metablock reader to be initialized. @@ -133,13 +133,13 @@ struct SqshReader2 { * * @return 0 on success, less than zero on error. */ -SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__reader2_init( - struct SqshReader2 *reader, - const struct SqshReader2IteratorImpl *iterator_impl, void *iterator); +SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__reader_init( + struct SqshReader *reader, + const struct SqshReaderIteratorImpl *iterator_impl, void *iterator); /** * @internal - * @memberof SqshReader2 + * @memberof SqshReader * @brief Advances the reader by the given offset and size. * * @param[in,out] reader Pointer to the metablock reader to be advanced. @@ -148,12 +148,12 @@ SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__reader2_init( * * @return 0 on success, less than zero on error. */ -SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__reader2_advance( - struct SqshReader2 *reader, sqsh_index_t offset, size_t size); +SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__reader_advance( + struct SqshReader *reader, sqsh_index_t offset, size_t size); /** * @internal - * @memberof SqshReader2 + * @memberof SqshReader * @brief Returns a pointer to the data at the current position of the metablock * reader. * @@ -162,11 +162,11 @@ SQSH_NO_EXPORT SQSH_NO_UNUSED int sqsh__reader2_advance( * @return Pointer to the data at the current position of the metablock reader. */ SQSH_NO_EXPORT const uint8_t * -sqsh__reader2_data(const struct SqshReader2 *reader); +sqsh__reader_data(const struct SqshReader *reader); /** * @internal - * @memberof SqshReader2 + * @memberof SqshReader * @brief Returns the size of the data at the current position of the metablock * reader. * @@ -174,18 +174,18 @@ sqsh__reader2_data(const struct SqshReader2 *reader); * * @return Size of the data at the current position of the metablock reader. */ -SQSH_NO_EXPORT size_t sqsh__reader2_size(const struct SqshReader2 *reader); +SQSH_NO_EXPORT size_t sqsh__reader_size(const struct SqshReader *reader); /** * @internal - * @memberof SqshReader2 + * @memberof SqshReader * @brief Cleans up and frees the resources used by the metablock reader. * * @param[in,out] reader Pointer to the metablock reader to be cleaned up. * * @return 0 on success, less than zero on error. */ -SQSH_NO_EXPORT int sqsh__reader2_cleanup(struct SqshReader2 *reader); +SQSH_NO_EXPORT int sqsh__reader_cleanup(struct SqshReader *reader); #ifdef __cplusplus } diff --git a/lib/file/file_reader.c b/lib/file/file_reader.c index c26e2f697..8d5ce86b2 100644 --- a/lib/file/file_reader.c +++ b/lib/file/file_reader.c @@ -52,7 +52,7 @@ file_iterator_size(const void *iterator) { return sqsh_file_iterator_size(iterator); } -static const struct SqshReader2IteratorImpl file_reader_impl = { +static const struct SqshReaderIteratorImpl file_reader_impl = { .next = file_iterator_next, .data = file_iterator_data, .size = file_iterator_size, @@ -66,7 +66,7 @@ sqsh__file_reader_init( if (rv < 0) { goto out; } - rv = sqsh__reader2_init( + rv = sqsh__reader_init( &reader->reader, &file_reader_impl, &reader->iterator); out: return rv; @@ -95,22 +95,22 @@ sqsh_file_reader_new(const struct SqshFile *file, int *err) { int sqsh_file_reader_advance( struct SqshFileReader *reader, sqsh_index_t offset, size_t size) { - return sqsh__reader2_advance(&reader->reader, offset, size); + return sqsh__reader_advance(&reader->reader, offset, size); } const uint8_t * sqsh_file_reader_data(const struct SqshFileReader *reader) { - return sqsh__reader2_data(&reader->reader); + return sqsh__reader_data(&reader->reader); } size_t sqsh_file_reader_size(const struct SqshFileReader *reader) { - return sqsh__reader2_size(&reader->reader); + return sqsh__reader_size(&reader->reader); } int sqsh__file_reader_cleanup(struct SqshFileReader *reader) { - sqsh__reader2_cleanup(&reader->reader); + sqsh__reader_cleanup(&reader->reader); sqsh__file_iterator_cleanup(&reader->iterator); return 0; diff --git a/lib/mapper/map_reader.c b/lib/mapper/map_reader.c index 2f9669790..26c52036f 100644 --- a/lib/mapper/map_reader.c +++ b/lib/mapper/map_reader.c @@ -50,7 +50,7 @@ map_iterator_size(const void *iterator) { return sqsh__map_iterator_size(iterator); } -static const struct SqshReader2IteratorImpl map_reader_impl = { +static const struct SqshReaderIteratorImpl map_reader_impl = { .next = map_iterator_next, .data = map_iterator_data, .size = map_iterator_size, @@ -74,7 +74,7 @@ sqsh__map_reader_init( if (rv < 0) { goto out; } - rv = sqsh__reader2_init( + rv = sqsh__reader_init( &reader->reader, &map_reader_impl, &reader->iterator); if (rv < 0) { goto out; @@ -82,7 +82,7 @@ sqsh__map_reader_init( reader->upper_limit = upper_limit; reader->address = start_address; - rv = sqsh__reader2_advance(&reader->reader, offset, 0); + rv = sqsh__reader_advance(&reader->reader, offset, 0); out: if (rv < 0) { sqsh__map_reader_cleanup(reader); @@ -106,7 +106,7 @@ int sqsh__map_reader_advance( struct SqshMapReader *reader, sqsh_index_t offset, size_t size) { reader->address += offset; - return sqsh__reader2_advance(&reader->reader, offset, size); + return sqsh__reader_advance(&reader->reader, offset, size); } int @@ -117,17 +117,17 @@ sqsh__map_reader_all(struct SqshMapReader *reader) { const uint8_t * sqsh__map_reader_data(const struct SqshMapReader *reader) { - return sqsh__reader2_data(&reader->reader); + return sqsh__reader_data(&reader->reader); } size_t sqsh__map_reader_size(const struct SqshMapReader *reader) { - return sqsh__reader2_size(&reader->reader); + return sqsh__reader_size(&reader->reader); } int sqsh__map_reader_cleanup(struct SqshMapReader *reader) { - sqsh__reader2_cleanup(&reader->reader); + sqsh__reader_cleanup(&reader->reader); sqsh__map_iterator_cleanup(&reader->iterator); return 0; diff --git a/lib/meson.build b/lib/meson.build index 95a3ec158..c515b64a8 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -1,5 +1,5 @@ libsqsh_sources = files( - 'reader/reader2.c', + 'reader/reader.c', 'archive/archive.c', 'archive/compression_options.c', 'archive/inode_map.c', diff --git a/lib/metablock/metablock_reader.c b/lib/metablock/metablock_reader.c index a1fe1250b..8f31b5428 100644 --- a/lib/metablock/metablock_reader.c +++ b/lib/metablock/metablock_reader.c @@ -54,7 +54,7 @@ metablock_iterator_size(const void *iterator) { return sqsh__metablock_iterator_size(iterator); } -static const struct SqshReader2IteratorImpl metablock_reader_impl = { +static const struct SqshReaderIteratorImpl metablock_reader_impl = { .next = metablock_iterator_next, .data = metablock_iterator_data, .size = metablock_iterator_size, @@ -70,7 +70,7 @@ sqsh__metablock_reader_init( if (rv < 0) { goto out; } - rv = sqsh__reader2_init( + rv = sqsh__reader_init( &reader->reader, &metablock_reader_impl, &reader->iterator); out: return rv; @@ -79,22 +79,22 @@ sqsh__metablock_reader_init( int sqsh__metablock_reader_advance( struct SqshMetablockReader *reader, sqsh_index_t offset, size_t size) { - return sqsh__reader2_advance(&reader->reader, offset, size); + return sqsh__reader_advance(&reader->reader, offset, size); } const uint8_t * sqsh__metablock_reader_data(const struct SqshMetablockReader *reader) { - return sqsh__reader2_data(&reader->reader); + return sqsh__reader_data(&reader->reader); } size_t sqsh__metablock_reader_size(const struct SqshMetablockReader *reader) { - return sqsh__reader2_size(&reader->reader); + return sqsh__reader_size(&reader->reader); } int sqsh__metablock_reader_cleanup(struct SqshMetablockReader *reader) { - sqsh__reader2_cleanup(&reader->reader); + sqsh__reader_cleanup(&reader->reader); sqsh__metablock_iterator_cleanup(&reader->iterator); return 0; diff --git a/lib/reader/reader2.c b/lib/reader/reader.c similarity index 86% rename from lib/reader/reader2.c rename to lib/reader/reader.c index c1b61ec41..3d719957f 100644 --- a/lib/reader/reader2.c +++ b/lib/reader/reader.c @@ -39,7 +39,7 @@ #include static int -reader_iterator_next(struct SqshReader2 *reader, size_t desired_size) { +reader_iterator_next(struct SqshReader *reader, size_t desired_size) { int rv = reader->iterator_impl->next(reader->iterator, desired_size); if (rv == 0) { rv = -SQSH_ERROR_OUT_OF_BOUNDS; @@ -63,10 +63,10 @@ reader_iterator_next(struct SqshReader2 *reader, size_t desired_size) { */ static int reader_iterator_skip( - struct SqshReader2 *reader, sqsh_index_t *offset, size_t desired_size) { + struct SqshReader *reader, sqsh_index_t *offset, size_t desired_size) { int rv = 0; void *iterator = reader->iterator; - const struct SqshReader2IteratorImpl *impl = reader->iterator_impl; + const struct SqshReaderIteratorImpl *impl = reader->iterator_impl; size_t current_size = impl->size(iterator); @@ -85,9 +85,9 @@ reader_iterator_skip( } int -sqsh__reader2_init( - struct SqshReader2 *reader, - const struct SqshReader2IteratorImpl *iterator_impl, void *iterator) { +sqsh__reader_init( + struct SqshReader *reader, + const struct SqshReaderIteratorImpl *iterator_impl, void *iterator) { reader->data = NULL; reader->size = 0; reader->offset = 0; @@ -108,10 +108,10 @@ sqsh__reader2_init( * @return 0 on success, negative on error. */ static int -reader_fill_buffer(struct SqshReader2 *reader, size_t size) { +reader_fill_buffer(struct SqshReader *reader, size_t size) { int rv = 0; void *iterator = reader->iterator; - const struct SqshReader2IteratorImpl *impl = reader->iterator_impl; + const struct SqshReaderIteratorImpl *impl = reader->iterator_impl; struct SqshBuffer *buffer = &reader->buffer; sqsh_index_t offset = reader->offset; @@ -149,7 +149,7 @@ reader_fill_buffer(struct SqshReader2 *reader, size_t size) { } static int -handle_buffered(struct SqshReader2 *reader, sqsh_index_t offset, size_t size) { +handle_buffered(struct SqshReader *reader, sqsh_index_t offset, size_t size) { int rv = 0; struct SqshBuffer new_buffer = {0}; sqsh_index_t iterator_offset = reader->iterator_offset; @@ -179,10 +179,10 @@ handle_buffered(struct SqshReader2 *reader, sqsh_index_t offset, size_t size) { } static int -handle_mapped(struct SqshReader2 *reader, sqsh_index_t offset, size_t size) { +handle_mapped(struct SqshReader *reader, sqsh_index_t offset, size_t size) { int rv = 0; void *iterator = reader->iterator; - const struct SqshReader2IteratorImpl *impl = reader->iterator_impl; + const struct SqshReaderIteratorImpl *impl = reader->iterator_impl; if (SQSH_ADD_OVERFLOW(offset, reader->offset, &offset)) { rv = -SQSH_ERROR_INTEGER_OVERFLOW; @@ -215,8 +215,8 @@ handle_mapped(struct SqshReader2 *reader, sqsh_index_t offset, size_t size) { } int -sqsh__reader2_advance( - struct SqshReader2 *reader, sqsh_index_t offset, size_t size) { +sqsh__reader_advance( + struct SqshReader *reader, sqsh_index_t offset, size_t size) { if (offset >= reader->iterator_offset) { offset -= reader->iterator_offset; reader->iterator_offset = 0; @@ -227,16 +227,16 @@ sqsh__reader2_advance( } const uint8_t * -sqsh__reader2_data(const struct SqshReader2 *reader) { +sqsh__reader_data(const struct SqshReader *reader) { return reader->data; } size_t -sqsh__reader2_size(const struct SqshReader2 *reader) { +sqsh__reader_size(const struct SqshReader *reader) { return reader->size; } int -sqsh__reader2_cleanup(struct SqshReader2 *reader) { +sqsh__reader_cleanup(struct SqshReader *reader) { return sqsh__buffer_cleanup(&reader->buffer); } diff --git a/test/meson.build b/test/meson.build index 548c8cadc..a7829c4cf 100644 --- a/test/meson.build +++ b/test/meson.build @@ -28,7 +28,7 @@ sqsh_test = [ 'metablock/metablock_iterator.c', 'metablock/metablock_reader.c', 'nasty.c', - 'reader/reader2.c', + 'reader/reader.c', 'primitive/buffer.c', 'primitive/lru.c', 'primitive/rc_hash_map.c', diff --git a/test/reader/reader.c b/test/reader/reader.c new file mode 100644 index 000000000..b78375fb4 --- /dev/null +++ b/test/reader/reader.c @@ -0,0 +1,579 @@ +/****************************************************************************** + * * + * Copyright (c) 2023, Enno Boland * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are * + * met: * + * * + * * Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + ******************************************************************************/ + +/** + * @author Enno Boland (mail@eboland.de) + * @file integration.c + */ + +#include "../include/sqsh_error.h" +#include "../include/sqsh_reader_private.h" +#include "common.h" +#include +#include + +struct TestIterator { + char *data; + char *current_data; + int remaining; +}; + +static const uint8_t * +test_iter_data(const void *data) { + struct TestIterator *iter = (struct TestIterator *)data; + return (uint8_t *)iter->current_data; +} + +static size_t +test_iter_size(const void *data) { + struct TestIterator *iter = (struct TestIterator *)data; + if (iter->current_data == NULL) { + return 0; + } else { + return strlen(iter->current_data); + } +} + +static int +test_iter_next(void *data, size_t desired_size) { + struct TestIterator *iter = (struct TestIterator *)data; + (void)desired_size; + if (iter->remaining == 0) { + iter->current_data = ""; + return 0; + } + iter->current_data = iter->data; + iter->remaining--; + return strlen(iter->current_data); +} + +static const struct SqshReaderIteratorImpl test_iter = { + .next = test_iter_next, + .data = test_iter_data, + .size = test_iter_size, +}; + +static void +test_reader_init(void) { + struct SqshReader reader = {0}; + struct TestIterator iter = { + .data = "test", + .remaining = 4, + }; + + int rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + sqsh__reader_cleanup(&reader); +} + +static void +test_reader_advance_with_offset(void) { + struct SqshReader reader = {0}; + struct TestIterator iter = { + .data = "test", + .remaining = 1, + }; + + int rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader_advance(&reader, 1, 2); + assert(rv == 0); + + const uint8_t *data = sqsh__reader_data(&reader); + size_t size = sqsh__reader_size(&reader); + assert(size == 2); + assert(memcmp(data, "es", 2) == 0); + + sqsh__reader_cleanup(&reader); +} + +static void +test_reader_advance_to_block(void) { + struct SqshReader reader = {0}; + struct TestIterator iter = { + .data = "test", + .remaining = 1, + }; + + int rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader_advance(&reader, 0, 4); + assert(rv == 0); + + const uint8_t *data = sqsh__reader_data(&reader); + size_t size = sqsh__reader_size(&reader); + assert(size == 4); + assert(memcmp(data, "test", 4) == 0); + + sqsh__reader_cleanup(&reader); +} + +static void +test_reader_advance_to_two_blocks() { + struct SqshReader reader = {0}; + struct TestIterator iter = { + .data = "test", + .remaining = 4, + }; + + int rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader_advance(&reader, 0, 8); + assert(rv == 0); + + const uint8_t *data = sqsh__reader_data(&reader); + size_t size = sqsh__reader_size(&reader); + assert(size == 8); + assert(memcmp(data, "testtest", 8) == 0); + + sqsh__reader_cleanup(&reader); +} + +static void +test_reader_advance_to_two_blocks_with_offset() { + struct SqshReader reader = {0}; + struct TestIterator iter = { + .data = "test", + .remaining = 4, + }; + + int rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader_advance(&reader, 1, 6); + assert(rv == 0); + + const uint8_t *data = sqsh__reader_data(&reader); + size_t size = sqsh__reader_size(&reader); + assert(size == 6); + assert(memcmp(data, "esttes", 6) == 0); + + sqsh__reader_cleanup(&reader); +} + +static void +test_reader_from_buffered_to_mapped() { + struct SqshReader reader = {0}; + struct TestIterator iter = { + .data = "test", + .remaining = 4, + }; + + int rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + // Trigger a buffered result + rv = sqsh__reader_advance(&reader, 1, 6); + assert(rv == 0); + + const uint8_t *data = sqsh__reader_data(&reader); + size_t size = sqsh__reader_size(&reader); + assert(size == 6); + assert(memcmp(data, "esttes", 6) == 0); + + // Trigger back to a mapped result + rv = sqsh__reader_advance(&reader, 4, 3); + assert(rv == 0); + + data = sqsh__reader_data(&reader); + size = sqsh__reader_size(&reader); + assert(size == 3); + assert(memcmp(data, "est", 3) == 0); + + sqsh__reader_cleanup(&reader); +} + +static void +test_reader_from_buffered_to_buffered() { + struct SqshReader reader = {0}; + struct TestIterator iter = { + .data = "test", + .remaining = 4, + }; + + int rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + // Trigger a buffered result + rv = sqsh__reader_advance(&reader, 1, 6); + assert(rv == 0); + + const uint8_t *data = sqsh__reader_data(&reader); + size_t size = sqsh__reader_size(&reader); + assert(size == 6); + assert(memcmp(data, "esttes", 6) == 0); + + // Trigger back to a mapped result + rv = sqsh__reader_advance(&reader, 8, 6); + assert(rv == 0); + + data = sqsh__reader_data(&reader); + size = sqsh__reader_size(&reader); + assert(size == 6); + assert(memcmp(data, "esttes", 6) == 0); + + sqsh__reader_cleanup(&reader); +} + +static void +test_reader_advance_inside_buffered() { + struct SqshReader reader = {0}; + struct TestIterator iter = { + .data = "test", + .remaining = 4, + }; + + int rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + // Trigger a buffered result + rv = sqsh__reader_advance(&reader, 1, 6); + assert(rv == 0); + + const uint8_t *data = sqsh__reader_data(&reader); + size_t size = sqsh__reader_size(&reader); + assert(size == 6); + assert(memcmp(data, "esttes", 6) == 0); + + // Trigger back to a mapped result + rv = sqsh__reader_advance(&reader, 1, 6); + assert(rv == 0); + + data = sqsh__reader_data(&reader); + size = sqsh__reader_size(&reader); + assert(size == 6); + assert(memcmp(data, "sttest", 6) == 0); + + sqsh__reader_cleanup(&reader); +} + +static void +test_reader_advance_with_zero_size() { + struct SqshReader reader = {0}; + struct TestIterator iter = { + .data = "test", + .remaining = 4, + }; + + int rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader_advance(&reader, 3, 0); + assert(rv == 0); + + size_t size = sqsh__reader_size(&reader); + assert(size == 0); + + // Trigger back to a mapped result + rv = sqsh__reader_advance(&reader, 0, 4); + assert(rv == 0); + + const uint8_t *data = sqsh__reader_data(&reader); + size = sqsh__reader_size(&reader); + assert(size == 4); + assert(memcmp(data, "ttes", 4) == 0); + + sqsh__reader_cleanup(&reader); +} + +static void +test_reader_advance_once(void) { + int rv; + struct SqshReader reader = {0}; + struct TestIterator iter = { + .data = "THIS IS A TEST STRING", .remaining = 1}; + + rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader_advance(&reader, 0, 6); + assert(rv == 0); + + const uint8_t *data = sqsh__reader_data(&reader); + assert(data == (void *)iter.data); + + sqsh__reader_cleanup(&reader); +} + +static void +test_reader_advance_once_with_offset(void) { + int rv; + struct SqshReader reader = {0}; + struct TestIterator iter = { + .data = "THIS IS A TEST STRING", .remaining = 1}; + rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader_advance(&reader, 4, 6); + assert(rv == 0); + + const uint8_t *data = sqsh__reader_data(&reader); + assert(data == (uint8_t *)&iter.data[4]); + + sqsh__reader_cleanup(&reader); +} + +static void +test_reader_advance_twice_with_offset(void) { + int rv; + struct SqshReader reader = {0}; + struct TestIterator iter = { + .data = "THIS IS A TEST STRING", .remaining = 1}; + + rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader_advance(&reader, 4, 6); + assert(rv == 0); + + const uint8_t *data = sqsh__reader_data(&reader); + assert(data == (uint8_t *)&iter.data[4]); + + rv = sqsh__reader_advance(&reader, 6, 2); + assert(rv == 0); + + const uint8_t *data2 = sqsh__reader_data(&reader); + assert(data2 == (uint8_t *)&iter.data[10]); + + sqsh__reader_cleanup(&reader); +} + +static void +test_reader_initial_advance(void) { + int rv; + struct SqshReader reader = {0}; + struct TestIterator iter = { + .data = "THIS IS A TEST STRING", .remaining = 1}; + rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader_advance(&reader, 5, 3); + assert(rv == 0); + const uint8_t *data = sqsh__reader_data(&reader); + assert(3 == sqsh__reader_size(&reader)); + assert(memcmp(data, "IS ", 3) == 0); + assert(data == (uint8_t *)&iter.data[5]); + + sqsh__reader_cleanup(&reader); +} + +static void +test_reader_advance_to_out_of_bounds(void) { + int rv; + struct SqshReader reader = {0}; + struct TestIterator iter = { + .data = "THIS IS A TEST STRING", .remaining = 1}; + + rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader_advance(&reader, strlen(iter.data), 1); + assert(rv < 0); + + sqsh__reader_cleanup(&reader); +} + +static void +test_reader_advance_over_boundary(void) { + int rv; + struct SqshReader reader = {0}; + struct TestIterator iter = {.data = "0123456789", .remaining = 2}; + + rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader_advance(&reader, 9, 2); + assert(rv == 0); + const uint8_t *data = sqsh__reader_data(&reader); + assert(2 == sqsh__reader_size(&reader)); + assert(memcmp(data, "90", 2) == 0); + + sqsh__reader_cleanup(&reader); +} + +static void +test_reader_initial_advance_2(void) { + int rv; + struct SqshReader reader = {0}; + struct TestIterator iter = {.data = "ABCD", .remaining = 10}; + + rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader_advance(&reader, 7, 5); + assert(rv == 0); + + const uint8_t *data = sqsh__reader_data(&reader); + assert(sqsh__reader_size(&reader) == 5); + assert(memcmp(data, "DABCD", 5) == 0); + + sqsh__reader_cleanup(&reader); +} + +static void +test_reader_error_1(void) { + int rv; + struct SqshReader reader = {0}; + struct TestIterator iter = {.data = "AB", .remaining = 10}; + + rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader_advance(&reader, 0, 4); + assert(rv == 0); + + const uint8_t *data = sqsh__reader_data(&reader); + assert(sqsh__reader_size(&reader) == 4); + assert(memcmp(data, "ABAB", 4) == 0); + + iter.data = "12"; + rv = sqsh__reader_advance(&reader, 4, 4); + assert(rv == 0); + + data = sqsh__reader_data(&reader); + assert(sqsh__reader_size(&reader) == 4); + assert(memcmp(data, "1212", 4) == 0); + + sqsh__reader_cleanup(&reader); +} + +static void +test_reader_map_into_buffer(void) { + int rv; + struct SqshReader reader = {0}; + struct TestIterator iter = {.data = "0123456789", .remaining = 2}; + + rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader_advance(&reader, 8, 4); + assert(rv == 0); + + const uint8_t *data = sqsh__reader_data(&reader); + assert(sqsh__reader_size(&reader) == 4); + assert(memcmp(data, "8901", 4) == 0); + + rv = sqsh__reader_advance(&reader, 1, 4); + assert(rv == 0); + + data = sqsh__reader_data(&reader); + assert(sqsh__reader_size(&reader) == 4); + assert(memcmp(data, "9012", 4) == 0); + + sqsh__reader_cleanup(&reader); +} + +static void +test_reader_map_into_buffer_twice(void) { + int rv; + struct SqshReader reader = {0}; + struct TestIterator iter = {.data = "0123456789", .remaining = 3}; + + rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader_advance(&reader, 8, 4); + assert(rv == 0); + + const uint8_t *data = sqsh__reader_data(&reader); + assert(sqsh__reader_size(&reader) == 4); + assert(memcmp(data, "8901", 4) == 0); + + rv = sqsh__reader_advance(&reader, 1, 14); + assert(rv == 0); + + data = sqsh__reader_data(&reader); + assert(sqsh__reader_size(&reader) == 14); + assert(memcmp(data, "90123456789012", 14) == 0); + + sqsh__reader_cleanup(&reader); +} + +static void +test_reader_extend_size_till_end(void) { + int rv; + struct SqshReader reader = {0}; + struct TestIterator iter = {.data = "0123456789", .remaining = 2}; + + rv = sqsh__reader_init(&reader, &test_iter, &iter); + assert(rv == 0); + + rv = sqsh__reader_advance(&reader, 4, 4); + assert(rv == 0); + + const uint8_t *data = sqsh__reader_data(&reader); + assert(sqsh__reader_size(&reader) == 4); + assert(memcmp(data, "4567", 4) == 0); + + rv = sqsh__reader_advance(&reader, 0, 6); + assert(rv == 0); + + data = sqsh__reader_data(&reader); + assert(sqsh__reader_size(&reader) == 6); + assert(memcmp(data, "456789", 6) == 0); + + iter.data = "ABCDEF"; + + rv = sqsh__reader_advance(&reader, 0, 12); + data = sqsh__reader_data(&reader); + assert(sqsh__reader_size(&reader) == 12); + assert(memcmp(data, "456789ABCDEF", 12) == 0); + + // rv = sqsh__reader_advance(&reader, 0, 13); + // assert(rv == -SQSH_ERROR_OUT_OF_BOUNDS); + + sqsh__reader_cleanup(&reader); +} + +DECLARE_TESTS +TEST(test_reader_init) +TEST(test_reader_advance_to_block) +TEST(test_reader_advance_with_offset) +TEST(test_reader_advance_to_two_blocks) +TEST(test_reader_advance_to_two_blocks_with_offset) +TEST(test_reader_from_buffered_to_mapped) +TEST(test_reader_from_buffered_to_buffered) +TEST(test_reader_from_buffered_to_buffered) +TEST(test_reader_advance_inside_buffered) +TEST(test_reader_advance_with_zero_size) +TEST(test_reader_advance_once) +TEST(test_reader_advance_once_with_offset) +TEST(test_reader_advance_twice_with_offset) +TEST(test_reader_initial_advance) +TEST(test_reader_advance_to_out_of_bounds) +TEST(test_reader_advance_over_boundary) +TEST(test_reader_initial_advance_2) +TEST(test_reader_error_1) +TEST(test_reader_map_into_buffer) +TEST(test_reader_map_into_buffer_twice) +TEST(test_reader_extend_size_till_end) +END_TESTS diff --git a/test/reader/reader2.c b/test/reader/reader2.c deleted file mode 100644 index 0862fece5..000000000 --- a/test/reader/reader2.c +++ /dev/null @@ -1,579 +0,0 @@ -/****************************************************************************** - * * - * Copyright (c) 2023, Enno Boland * - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions are * - * met: * - * * - * * Redistributions of source code must retain the above copyright notice, * - * this list of conditions and the following disclaimer. * - * * Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * * - ******************************************************************************/ - -/** - * @author Enno Boland (mail@eboland.de) - * @file integration.c - */ - -#include "../include/sqsh_error.h" -#include "../include/sqsh_reader_private.h" -#include "common.h" -#include -#include - -struct TestIterator { - char *data; - char *current_data; - int remaining; -}; - -static const uint8_t * -test_iter_data(const void *data) { - struct TestIterator *iter = (struct TestIterator *)data; - return (uint8_t *)iter->current_data; -} - -static size_t -test_iter_size(const void *data) { - struct TestIterator *iter = (struct TestIterator *)data; - if (iter->current_data == NULL) { - return 0; - } else { - return strlen(iter->current_data); - } -} - -static int -test_iter_next(void *data, size_t desired_size) { - struct TestIterator *iter = (struct TestIterator *)data; - (void)desired_size; - if (iter->remaining == 0) { - iter->current_data = ""; - return 0; - } - iter->current_data = iter->data; - iter->remaining--; - return strlen(iter->current_data); -} - -static const struct SqshReader2IteratorImpl test_iter = { - .next = test_iter_next, - .data = test_iter_data, - .size = test_iter_size, -}; - -static void -test_reader2_init(void) { - struct SqshReader2 reader = {0}; - struct TestIterator iter = { - .data = "test", - .remaining = 4, - }; - - int rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - sqsh__reader2_cleanup(&reader); -} - -static void -test_reader2_advance_with_offset(void) { - struct SqshReader2 reader = {0}; - struct TestIterator iter = { - .data = "test", - .remaining = 1, - }; - - int rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - rv = sqsh__reader2_advance(&reader, 1, 2); - assert(rv == 0); - - const uint8_t *data = sqsh__reader2_data(&reader); - size_t size = sqsh__reader2_size(&reader); - assert(size == 2); - assert(memcmp(data, "es", 2) == 0); - - sqsh__reader2_cleanup(&reader); -} - -static void -test_reader2_advance_to_block(void) { - struct SqshReader2 reader = {0}; - struct TestIterator iter = { - .data = "test", - .remaining = 1, - }; - - int rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - rv = sqsh__reader2_advance(&reader, 0, 4); - assert(rv == 0); - - const uint8_t *data = sqsh__reader2_data(&reader); - size_t size = sqsh__reader2_size(&reader); - assert(size == 4); - assert(memcmp(data, "test", 4) == 0); - - sqsh__reader2_cleanup(&reader); -} - -static void -test_reader2_advance_to_two_blocks() { - struct SqshReader2 reader = {0}; - struct TestIterator iter = { - .data = "test", - .remaining = 4, - }; - - int rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - rv = sqsh__reader2_advance(&reader, 0, 8); - assert(rv == 0); - - const uint8_t *data = sqsh__reader2_data(&reader); - size_t size = sqsh__reader2_size(&reader); - assert(size == 8); - assert(memcmp(data, "testtest", 8) == 0); - - sqsh__reader2_cleanup(&reader); -} - -static void -test_reader2_advance_to_two_blocks_with_offset() { - struct SqshReader2 reader = {0}; - struct TestIterator iter = { - .data = "test", - .remaining = 4, - }; - - int rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - rv = sqsh__reader2_advance(&reader, 1, 6); - assert(rv == 0); - - const uint8_t *data = sqsh__reader2_data(&reader); - size_t size = sqsh__reader2_size(&reader); - assert(size == 6); - assert(memcmp(data, "esttes", 6) == 0); - - sqsh__reader2_cleanup(&reader); -} - -static void -test_reader2_from_buffered_to_mapped() { - struct SqshReader2 reader = {0}; - struct TestIterator iter = { - .data = "test", - .remaining = 4, - }; - - int rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - // Trigger a buffered result - rv = sqsh__reader2_advance(&reader, 1, 6); - assert(rv == 0); - - const uint8_t *data = sqsh__reader2_data(&reader); - size_t size = sqsh__reader2_size(&reader); - assert(size == 6); - assert(memcmp(data, "esttes", 6) == 0); - - // Trigger back to a mapped result - rv = sqsh__reader2_advance(&reader, 4, 3); - assert(rv == 0); - - data = sqsh__reader2_data(&reader); - size = sqsh__reader2_size(&reader); - assert(size == 3); - assert(memcmp(data, "est", 3) == 0); - - sqsh__reader2_cleanup(&reader); -} - -static void -test_reader2_from_buffered_to_buffered() { - struct SqshReader2 reader = {0}; - struct TestIterator iter = { - .data = "test", - .remaining = 4, - }; - - int rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - // Trigger a buffered result - rv = sqsh__reader2_advance(&reader, 1, 6); - assert(rv == 0); - - const uint8_t *data = sqsh__reader2_data(&reader); - size_t size = sqsh__reader2_size(&reader); - assert(size == 6); - assert(memcmp(data, "esttes", 6) == 0); - - // Trigger back to a mapped result - rv = sqsh__reader2_advance(&reader, 8, 6); - assert(rv == 0); - - data = sqsh__reader2_data(&reader); - size = sqsh__reader2_size(&reader); - assert(size == 6); - assert(memcmp(data, "esttes", 6) == 0); - - sqsh__reader2_cleanup(&reader); -} - -static void -test_reader2_advance_inside_buffered() { - struct SqshReader2 reader = {0}; - struct TestIterator iter = { - .data = "test", - .remaining = 4, - }; - - int rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - // Trigger a buffered result - rv = sqsh__reader2_advance(&reader, 1, 6); - assert(rv == 0); - - const uint8_t *data = sqsh__reader2_data(&reader); - size_t size = sqsh__reader2_size(&reader); - assert(size == 6); - assert(memcmp(data, "esttes", 6) == 0); - - // Trigger back to a mapped result - rv = sqsh__reader2_advance(&reader, 1, 6); - assert(rv == 0); - - data = sqsh__reader2_data(&reader); - size = sqsh__reader2_size(&reader); - assert(size == 6); - assert(memcmp(data, "sttest", 6) == 0); - - sqsh__reader2_cleanup(&reader); -} - -static void -test_reader2_advance_with_zero_size() { - struct SqshReader2 reader = {0}; - struct TestIterator iter = { - .data = "test", - .remaining = 4, - }; - - int rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - rv = sqsh__reader2_advance(&reader, 3, 0); - assert(rv == 0); - - size_t size = sqsh__reader2_size(&reader); - assert(size == 0); - - // Trigger back to a mapped result - rv = sqsh__reader2_advance(&reader, 0, 4); - assert(rv == 0); - - const uint8_t *data = sqsh__reader2_data(&reader); - size = sqsh__reader2_size(&reader); - assert(size == 4); - assert(memcmp(data, "ttes", 4) == 0); - - sqsh__reader2_cleanup(&reader); -} - -static void -test_reader2_advance_once(void) { - int rv; - struct SqshReader2 reader = {0}; - struct TestIterator iter = { - .data = "THIS IS A TEST STRING", .remaining = 1}; - - rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - rv = sqsh__reader2_advance(&reader, 0, 6); - assert(rv == 0); - - const uint8_t *data = sqsh__reader2_data(&reader); - assert(data == (void *)iter.data); - - sqsh__reader2_cleanup(&reader); -} - -static void -test_reader2_advance_once_with_offset(void) { - int rv; - struct SqshReader2 reader = {0}; - struct TestIterator iter = { - .data = "THIS IS A TEST STRING", .remaining = 1}; - rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - rv = sqsh__reader2_advance(&reader, 4, 6); - assert(rv == 0); - - const uint8_t *data = sqsh__reader2_data(&reader); - assert(data == (uint8_t *)&iter.data[4]); - - sqsh__reader2_cleanup(&reader); -} - -static void -test_reader2_advance_twice_with_offset(void) { - int rv; - struct SqshReader2 reader = {0}; - struct TestIterator iter = { - .data = "THIS IS A TEST STRING", .remaining = 1}; - - rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - rv = sqsh__reader2_advance(&reader, 4, 6); - assert(rv == 0); - - const uint8_t *data = sqsh__reader2_data(&reader); - assert(data == (uint8_t *)&iter.data[4]); - - rv = sqsh__reader2_advance(&reader, 6, 2); - assert(rv == 0); - - const uint8_t *data2 = sqsh__reader2_data(&reader); - assert(data2 == (uint8_t *)&iter.data[10]); - - sqsh__reader2_cleanup(&reader); -} - -static void -test_reader2_initial_advance(void) { - int rv; - struct SqshReader2 reader = {0}; - struct TestIterator iter = { - .data = "THIS IS A TEST STRING", .remaining = 1}; - rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - rv = sqsh__reader2_advance(&reader, 5, 3); - assert(rv == 0); - const uint8_t *data = sqsh__reader2_data(&reader); - assert(3 == sqsh__reader2_size(&reader)); - assert(memcmp(data, "IS ", 3) == 0); - assert(data == (uint8_t *)&iter.data[5]); - - sqsh__reader2_cleanup(&reader); -} - -static void -test_reader2_advance_to_out_of_bounds(void) { - int rv; - struct SqshReader2 reader = {0}; - struct TestIterator iter = { - .data = "THIS IS A TEST STRING", .remaining = 1}; - - rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - rv = sqsh__reader2_advance(&reader, strlen(iter.data), 1); - assert(rv < 0); - - sqsh__reader2_cleanup(&reader); -} - -static void -test_reader2_advance_over_boundary(void) { - int rv; - struct SqshReader2 reader = {0}; - struct TestIterator iter = {.data = "0123456789", .remaining = 2}; - - rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - rv = sqsh__reader2_advance(&reader, 9, 2); - assert(rv == 0); - const uint8_t *data = sqsh__reader2_data(&reader); - assert(2 == sqsh__reader2_size(&reader)); - assert(memcmp(data, "90", 2) == 0); - - sqsh__reader2_cleanup(&reader); -} - -static void -test_reader2_initial_advance_2(void) { - int rv; - struct SqshReader2 reader = {0}; - struct TestIterator iter = {.data = "ABCD", .remaining = 10}; - - rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - rv = sqsh__reader2_advance(&reader, 7, 5); - assert(rv == 0); - - const uint8_t *data = sqsh__reader2_data(&reader); - assert(sqsh__reader2_size(&reader) == 5); - assert(memcmp(data, "DABCD", 5) == 0); - - sqsh__reader2_cleanup(&reader); -} - -static void -test_reader2_error_1(void) { - int rv; - struct SqshReader2 reader = {0}; - struct TestIterator iter = {.data = "AB", .remaining = 10}; - - rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - rv = sqsh__reader2_advance(&reader, 0, 4); - assert(rv == 0); - - const uint8_t *data = sqsh__reader2_data(&reader); - assert(sqsh__reader2_size(&reader) == 4); - assert(memcmp(data, "ABAB", 4) == 0); - - iter.data = "12"; - rv = sqsh__reader2_advance(&reader, 4, 4); - assert(rv == 0); - - data = sqsh__reader2_data(&reader); - assert(sqsh__reader2_size(&reader) == 4); - assert(memcmp(data, "1212", 4) == 0); - - sqsh__reader2_cleanup(&reader); -} - -static void -test_reader2_map_into_buffer(void) { - int rv; - struct SqshReader2 reader = {0}; - struct TestIterator iter = {.data = "0123456789", .remaining = 2}; - - rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - rv = sqsh__reader2_advance(&reader, 8, 4); - assert(rv == 0); - - const uint8_t *data = sqsh__reader2_data(&reader); - assert(sqsh__reader2_size(&reader) == 4); - assert(memcmp(data, "8901", 4) == 0); - - rv = sqsh__reader2_advance(&reader, 1, 4); - assert(rv == 0); - - data = sqsh__reader2_data(&reader); - assert(sqsh__reader2_size(&reader) == 4); - assert(memcmp(data, "9012", 4) == 0); - - sqsh__reader2_cleanup(&reader); -} - -static void -test_reader2_map_into_buffer_twice(void) { - int rv; - struct SqshReader2 reader = {0}; - struct TestIterator iter = {.data = "0123456789", .remaining = 3}; - - rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - rv = sqsh__reader2_advance(&reader, 8, 4); - assert(rv == 0); - - const uint8_t *data = sqsh__reader2_data(&reader); - assert(sqsh__reader2_size(&reader) == 4); - assert(memcmp(data, "8901", 4) == 0); - - rv = sqsh__reader2_advance(&reader, 1, 14); - assert(rv == 0); - - data = sqsh__reader2_data(&reader); - assert(sqsh__reader2_size(&reader) == 14); - assert(memcmp(data, "90123456789012", 14) == 0); - - sqsh__reader2_cleanup(&reader); -} - -static void -test_reader2_extend_size_till_end(void) { - int rv; - struct SqshReader2 reader = {0}; - struct TestIterator iter = {.data = "0123456789", .remaining = 2}; - - rv = sqsh__reader2_init(&reader, &test_iter, &iter); - assert(rv == 0); - - rv = sqsh__reader2_advance(&reader, 4, 4); - assert(rv == 0); - - const uint8_t *data = sqsh__reader2_data(&reader); - assert(sqsh__reader2_size(&reader) == 4); - assert(memcmp(data, "4567", 4) == 0); - - rv = sqsh__reader2_advance(&reader, 0, 6); - assert(rv == 0); - - data = sqsh__reader2_data(&reader); - assert(sqsh__reader2_size(&reader) == 6); - assert(memcmp(data, "456789", 6) == 0); - - iter.data = "ABCDEF"; - - rv = sqsh__reader2_advance(&reader, 0, 12); - data = sqsh__reader2_data(&reader); - assert(sqsh__reader2_size(&reader) == 12); - assert(memcmp(data, "456789ABCDEF", 12) == 0); - - // rv = sqsh__reader2_advance(&reader, 0, 13); - // assert(rv == -SQSH_ERROR_OUT_OF_BOUNDS); - - sqsh__reader2_cleanup(&reader); -} - -DECLARE_TESTS -TEST(test_reader2_init) -TEST(test_reader2_advance_to_block) -TEST(test_reader2_advance_with_offset) -TEST(test_reader2_advance_to_two_blocks) -TEST(test_reader2_advance_to_two_blocks_with_offset) -TEST(test_reader2_from_buffered_to_mapped) -TEST(test_reader2_from_buffered_to_buffered) -TEST(test_reader2_from_buffered_to_buffered) -TEST(test_reader2_advance_inside_buffered) -TEST(test_reader2_advance_with_zero_size) -TEST(test_reader2_advance_once) -TEST(test_reader2_advance_once_with_offset) -TEST(test_reader2_advance_twice_with_offset) -TEST(test_reader2_initial_advance) -TEST(test_reader2_advance_to_out_of_bounds) -TEST(test_reader2_advance_over_boundary) -TEST(test_reader2_initial_advance_2) -TEST(test_reader2_error_1) -TEST(test_reader2_map_into_buffer) -TEST(test_reader2_map_into_buffer_twice) -TEST(test_reader2_extend_size_till_end) -END_TESTS