Skip to content

Commit

Permalink
Add io operation callbacks (#112)
Browse files Browse the repository at this point in the history
* Add io operation callbacks

Add `unshield_open2` and `unshield_open2_force_version` to allows
overriding `fopen`, `fseek`, `ftell`, `fread`, `fwrite`, `fclose`,
`opendir`, `closedir`, `readdir` which lets the user pipe data from a
program without doing a round trip to the hard drive

* Add `unshield_*` calls to reduce repetition

* Add validation test for open2 callbacks
  • Loading branch information
bwrsandman authored Dec 4, 2023
1 parent 51e55ba commit 0fbc94c
Show file tree
Hide file tree
Showing 10 changed files with 638 additions and 54 deletions.
5 changes: 2 additions & 3 deletions .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,10 @@ jobs:
${{matrix.platform.msys-env}}-zlib
- name: Configure CMake
run: cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -DBUILD_STATIC=${{matrix.build-static}}
run: cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -DBUILD_STATIC=${{matrix.build-static}} -DBUILD_TESTING=ON

- name: Build
run: cmake --build build

- name: Test
working-directory: build
run: ctest --output-on-failure
run: ctest --test-dir build --output-on-failure
5 changes: 4 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ endif()
message(STATUS "OPENSSL_FOUND: ${OPENSSL_FOUND}")
message(STATUS "USE_OUR_OWN_MD5: ${USE_OUR_OWN_MD5}")
message(STATUS "BUILD_STATIC: ${BUILD_STATIC}")
message(STATUS "BUILD_TESTING: ${BUILD_TESTING}")

add_definitions(-DHAVE_CONFIG_H)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/lib/unshield_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/lib/unshield_config.h)
Expand Down Expand Up @@ -84,4 +85,6 @@ add_subdirectory(src)
install(FILES man/unshield.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libunshield.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)

add_subdirectory(test)
if (BUILD_TESTING)
add_subdirectory(test)
endif ()
61 changes: 30 additions & 31 deletions lib/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,8 @@ static bool unshield_reader_open_volume(UnshieldReader* reader, int volume)/*{{{
#if VERBOSE >= 2
unshield_trace("Open volume %i", volume);
#endif
FCLOSE(reader->volume_file);

FCLOSE(reader->unshield, reader->volume_file);

reader->volume_file = unshield_fopen_for_reading(reader->unshield, volume, CABINET_SUFFIX);
if (!reader->volume_file)
Expand All @@ -328,8 +328,7 @@ static bool unshield_reader_open_volume(UnshieldReader* reader, int volume)/*{{{
uint8_t tmp[COMMON_HEADER_SIZE];
uint8_t* p = tmp;

if (COMMON_HEADER_SIZE !=
fread(&tmp, 1, COMMON_HEADER_SIZE, reader->volume_file))
if (COMMON_HEADER_SIZE != unshield_fread(reader->unshield, &tmp, 1, COMMON_HEADER_SIZE, reader->volume_file))
goto exit;

if (!unshield_read_common_header(&p, &common_header))
Expand All @@ -346,8 +345,8 @@ static bool unshield_reader_open_volume(UnshieldReader* reader, int volume)/*{{{
uint8_t five_header[VOLUME_HEADER_SIZE_V5];
uint8_t* p = five_header;

if (VOLUME_HEADER_SIZE_V5 !=
fread(&five_header, 1, VOLUME_HEADER_SIZE_V5, reader->volume_file))
if (VOLUME_HEADER_SIZE_V5 !=
unshield_fread(reader->unshield, &five_header, 1, VOLUME_HEADER_SIZE_V5, reader->volume_file))
goto exit;

reader->volume_header.data_offset = READ_UINT32(p); p += 4;
Expand Down Expand Up @@ -383,8 +382,8 @@ static bool unshield_reader_open_volume(UnshieldReader* reader, int volume)/*{{{
uint8_t six_header[VOLUME_HEADER_SIZE_V6];
uint8_t* p = six_header;

if (VOLUME_HEADER_SIZE_V6 !=
fread(&six_header, 1, VOLUME_HEADER_SIZE_V6, reader->volume_file))
if (VOLUME_HEADER_SIZE_V6 !=
unshield_fread(reader->unshield, &six_header, 1, VOLUME_HEADER_SIZE_V6, reader->volume_file))
goto exit;

reader->volume_header.data_offset = READ_UINT32(p); p += 4;
Expand Down Expand Up @@ -486,7 +485,7 @@ static bool unshield_reader_open_volume(UnshieldReader* reader, int volume)/*{{{
else
reader->volume_bytes_left = volume_bytes_left_expanded;

fseek(reader->volume_file, data_offset, SEEK_SET);
unshield_fseek(reader->unshield, reader->volume_file, data_offset, SEEK_SET);

reader->volume = volume;
success = true;
Expand Down Expand Up @@ -532,20 +531,20 @@ static bool unshield_reader_read(UnshieldReader* reader, void* buffer, size_t si

#if VERBOSE >= 3
unshield_trace("Trying to read 0x%x bytes from offset %08x in volume %i",
bytes_to_read, ftell(reader->volume_file), reader->volume);
bytes_to_read, unshield_ftell(reader->unshield, reader->volume_file), reader->volume);
#endif
if (bytes_to_read == 0)
{
unshield_error("bytes_to_read can't be zero");
goto exit;
}

if (bytes_to_read != fread(p, 1, bytes_to_read, reader->volume_file))
if (bytes_to_read != unshield_fread(reader->unshield, p, 1, bytes_to_read, reader->volume_file))
{
unshield_error("Failed to read 0x%08x bytes of file %i (%s) from volume %i. Current offset = 0x%08x",
bytes_to_read, reader->index,
unshield_file_name(reader->unshield, reader->index), reader->volume,
ftell(reader->volume_file));
unshield_ftell(reader->unshield, reader->volume_file));
goto exit;
}

Expand Down Expand Up @@ -583,14 +582,14 @@ static bool unshield_reader_read(UnshieldReader* reader, void* buffer, size_t si
return success;
}/*}}}*/

int copy_file(FILE* infile, FILE* outfile) {
int copy_file(Unshield* unshield, FILE* infile, FILE* outfile) {
#define SIZE (1024*1024)

char buffer[SIZE];
size_t bytes;

while (0 < (bytes = fread(buffer, 1, sizeof(buffer), infile)))
fwrite(buffer, 1, bytes, outfile);
while (0 < (bytes = unshield_fread(unshield, buffer, 1, sizeof(buffer), infile)))
unshield_fwrite(unshield, buffer, 1, bytes, outfile);

return 0;
}
Expand Down Expand Up @@ -626,7 +625,7 @@ static UnshieldReader* unshield_reader_create_external(/*{{{*/
}

if (file_descriptor->flags & FILE_COMPRESSED) {
long file_size = FSIZE(reader->volume_file);
long file_size = FSIZE(unshield, reader->volume_file);
FILE *temporary_file = NULL;

/*
Expand All @@ -639,7 +638,7 @@ static UnshieldReader* unshield_reader_create_external(/*{{{*/
if (diff > 0) {
diff = MIN(sizeof(END_OF_CHUNK), diff);
temporary_file = tmpfile();
copy_file(reader->volume_file, temporary_file);
copy_file(reader->unshield, reader->volume_file, temporary_file);
fwrite(END_OF_CHUNK + sizeof(END_OF_CHUNK) - diff, 1, diff, temporary_file);
fseek(temporary_file, 0, SEEK_SET);

Expand Down Expand Up @@ -719,7 +718,7 @@ static void unshield_reader_destroy(UnshieldReader* reader)/*{{{*/
{
if (reader)
{
FCLOSE(reader->volume_file);
FCLOSE(reader->unshield, reader->volume_file);
free(reader);
}
}/*}}}*/
Expand Down Expand Up @@ -777,15 +776,15 @@ bool unshield_file_save (Unshield* unshield, int index, const char* filename)/*{
goto exit;
}

if (unshield_fsize(reader->volume_file) == (long)file_descriptor->data_offset)
if (unshield_fsize(unshield, reader->volume_file) == (long)file_descriptor->data_offset)
{
unshield_error("File %i is not inside the cabinet.", index);
goto exit;
}

if (filename)
{
output = fopen(filename, "wb");
output = unshield_fopen(unshield, filename, "wb");
if (!output)
{
unshield_error("Failed to open output file '%s'", filename);
Expand Down Expand Up @@ -883,7 +882,7 @@ bool unshield_file_save (Unshield* unshield, int index, const char* filename)/*{

if (output)
{
if (bytes_to_write != fwrite(output_buffer, 1, bytes_to_write, output))
if (bytes_to_write != unshield_fwrite(unshield, output_buffer, 1, bytes_to_write, output))
{
unshield_error("Failed to write %i bytes to file '%s'", bytes_to_write, filename);
goto exit;
Expand Down Expand Up @@ -925,7 +924,7 @@ bool unshield_file_save (Unshield* unshield, int index, const char* filename)/*{
md5 = NULL;
#endif
unshield_reader_destroy(reader);
FCLOSE(output);
FCLOSE(unshield, output);
FREE(input_buffer);
FREE(output_buffer);
return success;
Expand Down Expand Up @@ -992,15 +991,15 @@ bool unshield_file_save_raw(Unshield* unshield, int index, const char* filename)
goto exit;
}

if (unshield_fsize(reader->volume_file) == (long)file_descriptor->data_offset)
if (unshield_fsize(unshield, reader->volume_file) == (long)file_descriptor->data_offset)
{
unshield_error("File %i is not inside the cabinet.", index);
goto exit;
}

if (filename)
{
output = fopen(filename, "wb");
output = unshield_fopen(unshield, filename, "wb");
if (!output)
{
unshield_error("Failed to open output file '%s'", filename);
Expand Down Expand Up @@ -1031,7 +1030,7 @@ bool unshield_file_save_raw(Unshield* unshield, int index, const char* filename)
bytes_left -= bytes_to_write;

if (output) {
if (bytes_to_write != fwrite(output_buffer, 1, bytes_to_write, output)) {
if (bytes_to_write != unshield_fwrite(unshield, output_buffer, 1, bytes_to_write, output)) {
unshield_error("Failed to write %i bytes to file '%s'", bytes_to_write, filename);
goto exit;
}
Expand All @@ -1042,7 +1041,7 @@ bool unshield_file_save_raw(Unshield* unshield, int index, const char* filename)

exit:
unshield_reader_destroy(reader);
FCLOSE(output);
FCLOSE(unshield, output);
FREE(input_buffer);
FREE(output_buffer);
return success;
Expand Down Expand Up @@ -1110,7 +1109,7 @@ bool unshield_file_save_old(Unshield* unshield, int index, const char* filename)
goto exit;
}

if (unshield_fsize(reader->volume_file) == (long)file_descriptor->data_offset)
if (unshield_fsize(unshield, reader->volume_file) == (long)file_descriptor->data_offset)
{
unshield_error("File %i is not inside the cabinet. Trying external file!", index);
unshield_reader_destroy(reader);
Expand All @@ -1124,7 +1123,7 @@ bool unshield_file_save_old(Unshield* unshield, int index, const char* filename)

if (filename)
{
output = fopen(filename, "wb");
output = unshield_fopen(unshield, filename, "wb");
if (!output)
{
unshield_error("Failed to open output file '%s'", filename);
Expand Down Expand Up @@ -1247,7 +1246,7 @@ bool unshield_file_save_old(Unshield* unshield, int index, const char* filename)
bytes_left -= bytes_to_write;

if (output) {
if (bytes_to_write != fwrite(output_buffer, 1, bytes_to_write, output)) {
if (bytes_to_write != unshield_fwrite(unshield, output_buffer, 1, bytes_to_write, output)) {
unshield_error("Failed to write %i bytes to file '%s'", bytes_to_write, filename);
goto exit;
}
Expand All @@ -1272,7 +1271,7 @@ bool unshield_file_save_old(Unshield* unshield, int index, const char* filename)
bytes_left -= bytes_to_write;

if (output) {
if (bytes_to_write != fwrite(output_buffer, 1, bytes_to_write, output))
if (bytes_to_write != unshield_fwrite(unshield, output_buffer, 1, bytes_to_write, output))
{
unshield_error("Failed to write %i bytes to file '%s'", bytes_to_write, filename);
goto exit;
Expand All @@ -1295,7 +1294,7 @@ bool unshield_file_save_old(Unshield* unshield, int index, const char* filename)

exit:
unshield_reader_destroy(reader);
FCLOSE(output);
FCLOSE(unshield, output);
FREE(input_buffer);
FREE(output_buffer);
return success;
Expand Down
21 changes: 10 additions & 11 deletions lib/helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
#include <unistd.h>

#ifdef _WIN32
#define fseek _fseeki64
#define ftell _ftelli64
#define realpath(N,R) _fullpath((R),(N),_MAX_PATH)
#include <direct.h>
#ifndef PATH_MAX
Expand Down Expand Up @@ -103,11 +101,12 @@ FILE* unshield_fopen_for_reading(Unshield* unshield, int index, const char* suff
else
q=filename;

sourcedir = opendir(dirname);
sourcedir = unshield_opendir(unshield, dirname);
/* Search for the File case independent */
if (sourcedir)
{
for (dent=readdir(sourcedir);dent;dent=readdir(sourcedir))
for (dent=unshield_readdir(unshield, sourcedir);dent;
dent=unshield_readdir(unshield, sourcedir))
{
if (!(strcasecmp(q, dent->d_name)))
{
Expand All @@ -134,11 +133,11 @@ FILE* unshield_fopen_for_reading(Unshield* unshield, int index, const char* suff
#if VERBOSE
unshield_trace("Opening file '%s'", filename);
#endif
result = fopen(filename, "rb");
result = unshield_fopen(unshield, filename, "rb");

exit:
if (sourcedir)
closedir(sourcedir);
unshield_closedir(unshield, sourcedir);
free(filename);
free(dirname);
return result;
Expand All @@ -147,13 +146,13 @@ FILE* unshield_fopen_for_reading(Unshield* unshield, int index, const char* suff
return NULL;
}

long long unshield_fsize(FILE* file)
long long unshield_fsize(Unshield* unshield, FILE* file)
{
long long result;
long long previous = ftell(file);
fseek(file, 0L, SEEK_END);
result = ftell(file);
fseek(file, previous, SEEK_SET);
long long previous = unshield_ftell(unshield, file);
unshield_fseek(unshield, file, 0L, SEEK_END);
result = unshield_ftell(unshield, file);
unshield_fseek(unshield, file, previous, SEEK_SET);
return result;
}

Expand Down
Loading

0 comments on commit 0fbc94c

Please sign in to comment.