diff --git a/base16384.c b/base16384.c index b5e9e24..f860f40 100644 --- a/base16384.c +++ b/base16384.c @@ -123,22 +123,6 @@ int main(int argc, char** argv) { #endif } - #define base16384_perror_case(n) case base16384_err_##n: perror("base16384_err_"#n) - if(exitstat) switch(exitstat) { - base16384_perror_case(get_file_size); break; - base16384_perror_case(fopen_output_file); break; - base16384_perror_case(fopen_input_file); break; - base16384_perror_case(write_file); break; - base16384_perror_case(open_input_file); break; - base16384_perror_case(map_input_file); break; - base16384_perror_case(read_file); break; - base16384_perror_case(invalid_file_name); break; - base16384_perror_case(invalid_commandline_parameter); break; - base16384_perror_case(invalid_decoding_checksum); break; - default: perror("base16384"); break; - } - #undef base16384_perror_case - - return exitstat; + return base16384_perror(exitstat); } diff --git a/base16384.h b/base16384.h index 609503a..7ea5d88 100644 --- a/base16384.h +++ b/base16384.h @@ -221,22 +221,46 @@ base16384_err_t base16384_decode_fp_detailed(base16384_typed_flag_params(FILE*)) */ base16384_err_t base16384_decode_fd_detailed(base16384_typed_flag_params(int)); -#define BASE16384_DEFINE_DEATILED_WRAP(method, name, type) \ - static inline base16384_err_t base16384_##method##_##name##(base16384_typed_params(type)) { \ +#define BASE16384_WRAP_DECL(method, name, type) \ + static inline base16384_err_t base16384_##method##_##name(base16384_typed_params(type)) { \ return base16384_##method##_##name##_detailed(input, output, encbuf, decbuf, 0); \ } - BASE16384_DEFINE_DEATILED_WRAP(encode, file, const char*); - BASE16384_DEFINE_DEATILED_WRAP(encode, fp, FILE*); - BASE16384_DEFINE_DEATILED_WRAP(encode, fd, int); + BASE16384_WRAP_DECL(encode, file, const char*); + BASE16384_WRAP_DECL(encode, fp, FILE*); + BASE16384_WRAP_DECL(encode, fd, int); - BASE16384_DEFINE_DEATILED_WRAP(decode, file, const char*); - BASE16384_DEFINE_DEATILED_WRAP(decode, fp, FILE*); - BASE16384_DEFINE_DEATILED_WRAP(decode, fd, int); + BASE16384_WRAP_DECL(decode, file, const char*); + BASE16384_WRAP_DECL(decode, fp, FILE*); + BASE16384_WRAP_DECL(decode, fd, int); -#undef BASE16384_DEFINE_DEATILED_WRAP +#undef BASE16384_WRAP_DECL #undef base16384_typed_flag_params #undef base16384_typed_params +/** + * @brief call perror on error + * @param err the error + * @return the input parameter `err` +*/ +static inline base16384_err_t base16384_perror(base16384_err_t err) { + #define base16384_perror_case(n) case base16384_err_##n: perror("base16384_err_"#n) + if(err) switch(err) { + base16384_perror_case(get_file_size); break; + base16384_perror_case(fopen_output_file); break; + base16384_perror_case(fopen_input_file); break; + base16384_perror_case(write_file); break; + base16384_perror_case(open_input_file); break; + base16384_perror_case(map_input_file); break; + base16384_perror_case(read_file); break; + base16384_perror_case(invalid_file_name); break; + base16384_perror_case(invalid_commandline_parameter); break; + base16384_perror_case(invalid_decoding_checksum); break; + default: perror("base16384"); break; + } + #undef base16384_perror_case + return err; +} + #endif diff --git a/file.c b/file.c index 80bdd09..62f3f34 100644 --- a/file.c +++ b/file.c @@ -119,17 +119,18 @@ base16384_err_t base16384_encode_file_detailed(const char* input, const char* ou return base16384_err_invalid_file_name; } if(is_standard_io(input)) { // read from stdin - inputsize = 0; + inputsize = _BASE16384_ENCBUFSZ; fp = stdin; } else inputsize = get_file_size(input); - if(inputsize < 0) { + if(inputsize <= 0) { + if(!inputsize) errno = EINVAL; return base16384_err_get_file_size; } fpo = is_standard_io(output)?stdout:fopen(output, "wb"); if(!fpo) { return base16384_err_fopen_output_file; } - if(!inputsize || inputsize > _BASE16384_ENCBUFSZ) { // stdin or big file, use encbuf & fread + if(inputsize >= _BASE16384_ENCBUFSZ) { // stdin or big file, use encbuf & fread inputsize = _BASE16384_ENCBUFSZ; #if defined _WIN32 || defined __cosmopolitan } @@ -151,7 +152,7 @@ base16384_err_t base16384_encode_file_detailed(const char* input, const char* ou while((cnt = fread(encbuf, sizeof(char), inputsize, fp)) > 0) { if(flag&BASE16384_FLAG_SUM_CHECK_ON_REMAIN) sum = calc_and_embed_sum(sum, cnt, encbuf); int n = base16384_encode_unsafe(encbuf, cnt, decbuf); - if(fwrite(decbuf, n, 1, fpo) <= 0) { + if(n && fwrite(decbuf, n, 1, fpo) <= 0) { goto_base16384_file_detailed_cleanup(encode, base16384_err_write_file, {}); } } @@ -170,7 +171,7 @@ base16384_err_t base16384_encode_file_detailed(const char* input, const char* ou fputc(0xFF, fpo); } int n = base16384_encode(input_file, (int)inputsize, decbuf); - if(fwrite(decbuf, n, 1, fpo) <= 0) { + if(n && fwrite(decbuf, n, 1, fpo) <= 0) { goto_base16384_file_detailed_cleanup(encode, base16384_err_write_file, { munmap(input_file, (size_t)inputsize); close(fd); @@ -204,7 +205,7 @@ base16384_err_t base16384_encode_fp_detailed(FILE* input, FILE* output, char* en while((cnt = fread(encbuf, sizeof(char), inputsize, input)) > 0) { if(flag&BASE16384_FLAG_SUM_CHECK_ON_REMAIN) sum = calc_and_embed_sum(sum, cnt, encbuf); int n = base16384_encode_unsafe(encbuf, cnt, decbuf); - if(fwrite(decbuf, n, 1, output) <= 0) { + if(n && fwrite(decbuf, n, 1, output) <= 0) { return base16384_err_write_file; } } @@ -225,7 +226,7 @@ base16384_err_t base16384_encode_fd_detailed(int input, int output, char* encbuf while((cnt = read(input, encbuf, inputsize)) > 0) { if(flag&BASE16384_FLAG_SUM_CHECK_ON_REMAIN) sum = calc_and_embed_sum(sum, cnt, encbuf); int n = base16384_encode_unsafe(encbuf, cnt, decbuf); - if(write(output, decbuf, n) < n) { + if(n && write(output, decbuf, n) < n) { return base16384_err_write_file; } } @@ -260,17 +261,18 @@ base16384_err_t base16384_decode_file_detailed(const char* input, const char* ou return base16384_err_invalid_file_name; } if(is_standard_io(input)) { // read from stdin - inputsize = 0; + inputsize = _BASE16384_DECBUFSZ; fp = stdin; } else inputsize = get_file_size(input); - if(inputsize < 0) { + if(inputsize <= 0) { + if(!inputsize) errno = EINVAL; return base16384_err_get_file_size; } fpo = is_standard_io(output)?stdout:fopen(output, "wb"); if(!fpo) { return base16384_err_fopen_output_file; } - if(!inputsize || inputsize > _BASE16384_DECBUFSZ) { // stdin or big file, use decbuf & fread + if(inputsize >= _BASE16384_DECBUFSZ) { // stdin or big file, use decbuf & fread inputsize = _BASE16384_DECBUFSZ; #if defined _WIN32 || defined __cosmopolitan } @@ -295,7 +297,7 @@ base16384_err_t base16384_decode_file_detailed(const char* input, const char* ou } if(errno) goto_base16384_file_detailed_cleanup(decode, base16384_err_read_file, {}); cnt = base16384_decode_unsafe(decbuf, cnt, encbuf); - if(fwrite(encbuf, cnt, 1, fpo) <= 0) { + if(cnt && fwrite(encbuf, cnt, 1, fpo) <= 0) { goto_base16384_file_detailed_cleanup(decode, base16384_err_write_file, {}); } if(flag&BASE16384_FLAG_SUM_CHECK_ON_REMAIN) { @@ -316,7 +318,8 @@ base16384_err_t base16384_decode_file_detailed(const char* input, const char* ou goto_base16384_file_detailed_cleanup(decode, base16384_err_map_input_file, close(fd)); } int off = skip_offset(input_file); - if(fwrite(encbuf, base16384_decode(input_file+off, inputsize-off, encbuf), 1, fpo) <= 0) { + int n = base16384_decode(input_file+off, inputsize-off, encbuf); + if(n && fwrite(encbuf, n, 1, fpo) <= 0) { goto_base16384_file_detailed_cleanup(decode, base16384_err_write_file, { munmap(input_file, (size_t)inputsize); close(fd); @@ -356,7 +359,7 @@ base16384_err_t base16384_decode_fp_detailed(FILE* input, FILE* output, char* en decbuf[cnt++] = end; } cnt = base16384_decode_unsafe(decbuf, cnt, encbuf); - if(fwrite(encbuf, cnt, 1, output) <= 0) { + if(cnt && fwrite(encbuf, cnt, 1, output) <= 0) { return base16384_err_write_file; } if(flag&BASE16384_FLAG_SUM_CHECK_ON_REMAIN) { @@ -371,10 +374,10 @@ base16384_err_t base16384_decode_fp_detailed(FILE* input, FILE* output, char* en static inline uint16_t is_next_end_fd(int fd) { uint8_t ch = 0; - read(fd, &ch, 1); + if(read(fd, &ch, 1) != 1) return (uint16_t)EOF; uint16_t ret = (uint16_t)ch & 0x00ff; if(ch == '=') { - read(fd, &ch, 1); + if(read(fd, &ch, 1) != 1) return (uint16_t)EOF; ret <<= 8; ret |= (uint16_t)ch & 0x00ff; } @@ -390,29 +393,32 @@ base16384_err_t base16384_decode_fd_detailed(int input, int output, char* encbuf errno = EINVAL; return base16384_err_fopen_output_file; } - off_t inputsize = _BASE16384_DECBUFSZ; + off_t inputsize = _BASE16384_DECBUFSZ-1; int cnt = 0; - int end = 0; uint32_t sum = BASE16384_SIMPLE_SUM_INIT_VALUE; decbuf[0] = 0; - if(read(input, decbuf, 2) < 2) { + if(read(input, decbuf, 2) != 2) { return base16384_err_read_file; } - if(decbuf[0] != (char)(0xfe)) cnt = 2; - while((end = read(input, decbuf+cnt, inputsize-cnt)) > 0 || cnt > 0) { - if(end > 0) { - cnt += end; - uint16_t next = is_next_end_fd(input); - if(errno) { - return base16384_err_read_file; - } - if(next&0xff00) { - decbuf[cnt++] = '='; - } + if(decbuf[0] != (char)(0xfe)) { + cnt = read(input, decbuf+2, inputsize-2)+2; + } else { + cnt = read(input, decbuf, inputsize); + } + if(cnt > 0) do { + uint16_t next = is_next_end_fd(input); + if(errno) { + return base16384_err_read_file; + } + if((uint16_t)(~next)) { + if(next&0xff00) decbuf[cnt++] = '='; decbuf[cnt++] = (char)(next&0x00ff); } - end = base16384_decode_unsafe(decbuf, cnt, encbuf); - if(write(output, encbuf, end) < end) { + #ifdef DEBUG + fprintf(stderr, "decode chunk: %d, last2: %c %02x\n", cnt, decbuf[cnt-2], (uint8_t)decbuf[cnt-1]); + #endif + cnt = base16384_decode_unsafe(decbuf, cnt, encbuf); + if(cnt && write(output, encbuf, cnt) != cnt) { return base16384_err_write_file; } if(flag&BASE16384_FLAG_SUM_CHECK_ON_REMAIN) { @@ -421,7 +427,6 @@ base16384_err_t base16384_decode_fd_detailed(int input, int output, char* encbuf return base16384_err_invalid_decoding_checksum; } } - cnt = 0; - } + } while((cnt = read(input, decbuf, inputsize)) > 0); return base16384_err_ok; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 48a9ab2..bb82a5e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 2.8.12) if (POLICY CMP0048) - cmake_policy(SET CMP0048 NEW) + cmake_policy(SET CMP0048 NEW) endif (POLICY CMP0048) project(base16384_test VERSION 1.0.0) @@ -9,6 +9,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) file (GLOB_RECURSE C_FILES "*.c") foreach (C_FILE ${C_FILES}) get_filename_component(FILE_NAME ${C_FILE} NAME_WE) + message(STATUS "Add test ${FILE_NAME}") add_executable(${FILE_NAME} ${C_FILE}) target_link_libraries(${FILE_NAME} base16384_s) add_test(NAME do_${FILE_NAME} COMMAND ${FILE_NAME}) diff --git a/test/coder_test.c b/test/coder_test.c index fb5f06f..fe391f6 100644 --- a/test/coder_test.c +++ b/test/coder_test.c @@ -6,9 +6,11 @@ #include "base16384.h" -char encbuf[4096+16]; -char decbuf[4096/7*8+16]; -char tstbuf[4096+16]; +#define TEST_SIZE (4096) + +char encbuf[TEST_SIZE+16]; +char decbuf[TEST_SIZE/7*8+16]; +char tstbuf[TEST_SIZE+16]; #define loop_diff(target) \ for(i = start; i < end; i++) { \ @@ -44,18 +46,18 @@ char tstbuf[4096+16]; int main() { srand(time(NULL)); int i, n; - for(i = 0; i < 4096; i += sizeof(int)) { + for(i = 0; i <= TEST_SIZE; i += sizeof(int)) { *(int*)(&encbuf[i]) = rand(); } - fputs("testing base16384_encode/base16384_decode...\n", stderr); - for(i = 0; i < 4096; i++) { + fputs("testing base16384_en/decode...\n", stderr); + for(i = 0; i <= TEST_SIZE; i++) { n = base16384_encode(encbuf, i, decbuf); n = base16384_decode(decbuf, n, tstbuf); int decn = n; if (memcmp(encbuf, tstbuf, n)) return_error(i, n); } - fputs("testing base16384_encode_unsafe/base16384_decode_unsafe...\n", stderr); - for(i = 0; i < 4096; i++) { + fputs("testing base16384_en/ecode_unsafe...\n", stderr); + for(i = 0; i <= TEST_SIZE; i++) { n = base16384_encode_unsafe(encbuf, i, decbuf); n = base16384_decode_unsafe(decbuf, n, tstbuf); if ((n = memcmp(encbuf, tstbuf, n))) return_error(i, n); diff --git a/test/wrap_test.c b/test/wrap_test.c new file mode 100644 index 0000000..467914c --- /dev/null +++ b/test/wrap_test.c @@ -0,0 +1,173 @@ + +#ifdef _WIN32 + #include + #define ftruncate _chsize_s +#else + #define _POSIX1_SOURCE 2 + #include +#endif +#include +#include +#include +#include +#include +#include + +#include "base16384.h" +#include "binary.h" + +#define TEST_SIZE (4096) +#define TEST_INPUT_FILENAME "wrap_test_input.bin" +#define TEST_OUTPUT_FILENAME "wrap_test_output.bin" +#define TEST_VALIDATE_FILENAME "wrap_test_validate.bin" + +char encbuf[BASE16384_ENCBUFSZ]; +char decbuf[BASE16384_DECBUFSZ]; +char tstbuf[BASE16384_ENCBUFSZ]; + +#define ok(has_failed, reason) \ + if (has_failed) { \ + perror(reason); \ + return 1; \ + } + +#define loop_ok(has_failed, i, reason) \ + if (has_failed) { \ + fprintf(stderr, "loop @%d: ", i); \ + perror(reason); \ + return 1; \ + } + +#define reset_and_truncate(fd, i) { \ + fd = open(TEST_INPUT_FILENAME, O_RDWR); \ + ok(!fd, "open"); \ + loop_ok(lseek(fd, 0, SEEK_SET), i, "lseek"); \ + loop_ok(ftruncate(fd, i), i, "ftruncate"); \ +} + +#define base16384_loop_ok(err) \ + if (err) { \ + fprintf(stderr, "loop @%d: ", i); \ + base16384_perror(err); \ + return 1; \ + } + +#define validate_result() \ + uint64_t buf, sum_input = 0, sum_validate = 0; \ + fp = fopen(TEST_INPUT_FILENAME, "rb"); { \ + loop_ok(!fp, i, "fopen"); \ + while (fread(&buf, sizeof(sum_input), 1, fp) == 1) sum_input += buf; \ + buf = 0; \ + while (fread(&buf, 1, 1, fp) == 1) { \ + sum_input += buf; \ + sum_input = LEFTROTATE(sum_input, 4); \ + } \ + } fclose(fp); \ + fp = fopen(TEST_VALIDATE_FILENAME, "rb"); { \ + loop_ok(!fp, i, "fopen"); \ + while (fread(&buf, sizeof(sum_validate), 1, fp) == 1) sum_validate += buf; \ + buf = 0; \ + while (fread(&buf, 1, 1, fp) == 1) { \ + sum_validate += buf; \ + sum_validate = LEFTROTATE(sum_validate, 4); \ + } \ + } fclose(fp); \ + if (sum_input != sum_validate) { \ + fprintf(stderr, "loop @%d, expect: %016llx, got: %016llx: ", i, sum_input, sum_validate); \ + fputs(TEST_INPUT_FILENAME " and " TEST_VALIDATE_FILENAME " mismatch.", stderr); \ + return 1; \ + } + +#define init_input_file() \ + for(i = 0; i < TEST_SIZE; i += sizeof(int)) { \ + *(int*)(&encbuf[i]) = rand(); \ + } \ + fp = fopen(TEST_INPUT_FILENAME, "wb"); \ + ok(!fp, "fopen"); \ + ok(fwrite(encbuf, TEST_SIZE, 1, fp) != 1, "fwrite"); \ + ok(fclose(fp), "fclose"); + +int main() { + srand(time(NULL)); + + FILE* fp; + int fd, i; + base16384_err_t err; + + fputs("testing base16384_en/decode_file...\n", stderr); + init_input_file(); + for(i = TEST_SIZE; i > 0; i--) { + reset_and_truncate(fd, i); + loop_ok(close(fd), i, "close"); + + err = base16384_encode_file(TEST_INPUT_FILENAME, TEST_OUTPUT_FILENAME, encbuf, decbuf); + base16384_loop_ok(err); + err = base16384_decode_file(TEST_OUTPUT_FILENAME, TEST_VALIDATE_FILENAME, encbuf, decbuf); + base16384_loop_ok(err); + + validate_result(); + } + + fputs("testing base16384_en/decode_fp...\n", stderr); + init_input_file(); + for(i = TEST_SIZE; i > 0; i--) { + reset_and_truncate(fd, i); + loop_ok(close(fd), i, "close"); + + FILE* fpin = fopen(TEST_INPUT_FILENAME, "rb"); + loop_ok(!fpin, i, "fopen"); + + FILE* fpout = fopen(TEST_OUTPUT_FILENAME, "wb+"); + loop_ok(!fpout, i, "fopen"); + + err = base16384_encode_fp(fpin, fpout, encbuf, decbuf); + base16384_loop_ok(err); + + loop_ok(fclose(fpin), i, "fclose"); + + FILE* fpval = fopen(TEST_VALIDATE_FILENAME, "wb"); + loop_ok(!fpval, i, "fopen"); + + rewind(fpout); + + err = base16384_decode_fp(fpout, fpval, encbuf, decbuf); + base16384_loop_ok(err); + + loop_ok(fclose(fpout), i, "fclose"); + loop_ok(fclose(fpval), i, "fclose"); + + validate_result(); + } + + fputs("testing base16384_en/decode_fd...\n", stderr); + init_input_file(); + for(i = TEST_SIZE; i > 0; i--) { + reset_and_truncate(fd, i); + + int fdout = open(TEST_OUTPUT_FILENAME, O_RDWR|O_TRUNC|O_CREAT|O_APPEND); + loop_ok(!fdout, i, "open"); + + err = base16384_encode_fd(fd, fdout, encbuf, decbuf); + base16384_loop_ok(err); + loop_ok(close(fd), i, "close"); + + int fdval = open(TEST_VALIDATE_FILENAME, O_WRONLY|O_TRUNC|O_CREAT); + loop_ok(!fdval, i, "open"); + + loop_ok(lseek(fdout, 0, SEEK_SET), i, "lseek"); + + err = base16384_decode_fd(fdout, fdval, encbuf, decbuf); + base16384_loop_ok(err); + + loop_ok(close(fdout), i, "close"); + loop_ok(close(fdval), i, "close"); + + validate_result(); + } + + remove(TEST_INPUT_FILENAME); + remove(TEST_OUTPUT_FILENAME); + remove(TEST_VALIDATE_FILENAME); + + return 0; +}