Skip to content

Commit

Permalink
Implement and test util::file_seek
Browse files Browse the repository at this point in the history
  • Loading branch information
BenWiederhake committed Nov 27, 2023
1 parent bd2745f commit 0442a74
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 0 deletions.
16 changes: 16 additions & 0 deletions include/osmium/util/file.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,22 @@ namespace osmium {
return static_cast<std::size_t>(offset);
}

/**
* Set current offset into file.
*
* @param fd Open file descriptor.
* @param offset Desired absolute offset into the file
*/
inline void file_seek(int fd, size_t offset) noexcept {
#ifdef _MSC_VER
osmium::detail::disable_invalid_parameter_handler diph;
// https://msdn.microsoft.com/en-us/library/1yee101t.aspx
_lseeki64(fd, offset, SEEK_SET);
#else
::lseek(fd, offset, SEEK_SET);
#endif
}

/**
* Check whether the file descriptor refers to a TTY.
*
Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ add_unit_test(io test_compression_factory)
add_unit_test(io test_file_formats)
add_unit_test(io test_nocompression)
add_unit_test(io test_output_utils)
add_unit_test(io test_file_seek)
add_unit_test(io test_string_table)

add_unit_test(io test_bzip2 ENABLE_IF ${BZIP2_FOUND} LIBS ${BZIP2_LIBRARIES})
Expand Down
62 changes: 62 additions & 0 deletions test/t/io/test_file_seek.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include "catch.hpp"

#include "utils.hpp"

#include <osmium/io/detail/read_write.hpp>
#include <osmium/util/file.hpp>

/**
* Can read and seek around in files.
*/
TEST_CASE("Seek and read in files") {
/* gzipped data contains very few repetitions in the binary file format,
* which makes it easy to identify any problems. */
int fd = osmium::io::detail::open_for_reading(with_data_dir("t/io/data.osm.gz"));
struct seek_expectation {
size_t offset;
unsigned char eight_bytes[8];
};
const seek_expectation expectations[] = {
{ 0x00, {0x1f, 0x8b, 0x08, 0x08, 0x19, 0x4a, 0x18, 0x54} },
{ 0x00, {0x1f, 0x8b, 0x08, 0x08, 0x19, 0x4a, 0x18, 0x54} }, /* repeat / jump back */
{ 0x21, {0x56, 0xc6, 0x18, 0xc3, 0xea, 0x6d, 0x4f, 0xe0} }, /* unaligned */
{ 0xb3, {0xcd, 0x0a, 0xe7, 0x8f, 0xde, 0x00, 0x00, 0x00} }, /* close to end */
{ 0x21, {0x56, 0xc6, 0x18, 0xc3, 0xea, 0x6d, 0x4f, 0xe0} }, /* "long" backward jump */
};
for (const auto& expect : expectations) {
printf("Trying to seek to %lu\n", expect.offset);
char actual_eight_bytes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
osmium::util::file_seek(fd, expect.offset);
bool did_actually_read = osmium::io::detail::read_exactly(fd, &actual_eight_bytes[0], 8);
REQUIRE(did_actually_read);
for (int i = 0; i < 8; ++i) {
REQUIRE(expect.eight_bytes[i] == static_cast<unsigned char>(actual_eight_bytes[i]));
}
}
}

TEST_CASE("Seek close to end of file") {
/* gzipped data contains very few repetitions in the binary file format,
* which makes it easy to identify any problems. */
int fd = osmium::io::detail::open_for_reading(with_data_dir("t/io/data.osm.gz"));
REQUIRE(osmium::util::file_size(with_data_dir("t/io/data.osm.gz")) == 187);
char actual_eight_bytes[8] = {1, 1, 1, 1, 1, 1, 1, 1};
osmium::util::file_seek(fd, 186);
auto actually_read = osmium::io::detail::reliable_read(fd, &actual_eight_bytes[0], 8);
REQUIRE(actually_read == 1);
REQUIRE(actual_eight_bytes[0] == 0);
REQUIRE(actual_eight_bytes[1] == 1);
}

TEST_CASE("Seek to exact end of file") {
/* gzipped data contains very few repetitions in the binary file format,
* which makes it easy to identify any problems. */
int fd = osmium::io::detail::open_for_reading(with_data_dir("t/io/data.osm.gz"));
REQUIRE(osmium::util::file_size(with_data_dir("t/io/data.osm.gz")) == 187);
char actual_eight_bytes[8] = {1, 1, 1, 1, 1, 1, 1, 1};
osmium::util::file_seek(fd, 187);
auto actually_read = osmium::io::detail::reliable_read(fd, &actual_eight_bytes[0], 8);
REQUIRE(actually_read == 0);
REQUIRE(actual_eight_bytes[0] == 1);
REQUIRE(actual_eight_bytes[1] == 1);
}

0 comments on commit 0442a74

Please sign in to comment.