diff --git a/CMakeLists.txt b/CMakeLists.txt index 5dd141b..72386ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,14 +10,12 @@ if (${isBigEndian}) add_definitions(-DWORDS_BIGENDIAN) endif() -add_link_options("-lc") - IF(CMAKE_SIZEOF_VOID_P EQUAL 8) - add_library(base16384 SHARED base1464.c) - add_library(base16384_s STATIC base1464.c) + add_library(base16384 SHARED file.c base1464.c) + add_library(base16384_s STATIC file.c base1464.c) ELSE() - add_library(base16384 SHARED base1432.c) - add_library(base16384_s STATIC base1432.c) + add_library(base16384 SHARED file.c base1432.c) + add_library(base16384_s STATIC file.c base1432.c) ENDIF() set_target_properties(base16384_b PROPERTIES OUTPUT_NAME base16384) diff --git a/base1432.c b/base1432.c index 44bed16..020f72e 100644 --- a/base1432.c +++ b/base1432.c @@ -61,7 +61,7 @@ // #define DEBUG -int encode(const char* data, int dlen, char* buf, int blen) { +int base16384_encode(const char* data, int dlen, char* buf, int blen) { int outlen = dlen / 7 * 8; int offset = dlen % 7; switch(offset) { // 算上偏移标志字符占用的2字节 @@ -139,7 +139,7 @@ int encode(const char* data, int dlen, char* buf, int blen) { return outlen; } -int decode(const char* data, int dlen, char* buf, int blen) { +int base16384_decode(const char* data, int dlen, char* buf, int blen) { int outlen = dlen; int offset = 0; if(data[dlen-2] == '=') { diff --git a/base1464.c b/base1464.c index d96fbf8..517fc1b 100644 --- a/base1464.c +++ b/base1464.c @@ -61,7 +61,7 @@ // #define DEBUG -int encode(const char* data, int dlen, char* buf, int blen) { +int base16384_encode(const char* data, int dlen, char* buf, int blen) { int outlen = dlen / 7 * 8; int offset = dlen % 7; switch(offset) { // 算上偏移标志字符占用的2字节 @@ -135,7 +135,7 @@ int encode(const char* data, int dlen, char* buf, int blen) { return outlen; } -int decode(const char* data, int dlen, char* buf, int blen) { +int base16384_decode(const char* data, int dlen, char* buf, int blen) { int outlen = dlen; int offset = 0; if(data[dlen-2] == '=') { diff --git a/base16384.c b/base16384.c index c811527..72e24bd 100644 --- a/base16384.c +++ b/base16384.c @@ -18,190 +18,13 @@ #ifndef __cosmopolitan #include #include -#include -#include -#include +#include #include -#ifdef _WIN32 - #include -#else - #include -#endif #endif #include "base16384.h" -#ifdef __cosmopolitan -#define get_file_size(filepath) ((off_t)GetFileSize(filepath)) -#else -static off_t get_file_size(const char* filepath) { - struct stat statbuf; - return stat(filepath, &statbuf)?-1:statbuf.st_size; -} -#endif - -char encbuf[BUFSIZ*1024/7*7]; -char decbuf[BUFSIZ*1024/8*8+2]; - -static int encode_file(const char* input, const char* output) { - off_t inputsize; - FILE* fp = NULL; - FILE* fpo; - if(*(uint16_t*)input == *(uint16_t*)"-") { // read from stdin - inputsize = 0; - fp = stdin; - } else inputsize = get_file_size(input); - if(inputsize < 0) { - perror("Get file size error"); - return 1; - } - fpo = (*(uint16_t*)output == *(uint16_t*)"-")?stdout:fopen(output, "wb"); - if(!fpo) { - perror("Fopen output file error"); - return 2; - } - if(!inputsize || inputsize > BUFSIZ*1024) { // stdin or big file, use encbuf & fread - inputsize = BUFSIZ*1024/7*7; - #ifdef _WIN32 - } - #endif - if(!fp) fp = fopen(input, "rb"); - if(!fp) { - perror("Fopen input file error"); - return 3; - } - - int outputsize = encode_len(inputsize)+16; - size_t cnt = 0; - fputc(0xFE, fpo); - fputc(0xFF, fpo); - while((cnt = fread(encbuf, sizeof(char), inputsize, fp))) { - int n = encode(encbuf, cnt, decbuf, outputsize); - if(fwrite(decbuf, n, 1, fpo) <= 0) { - perror("Write file error"); - return 4; - } - } - /* 由操作系统负责释放资源 - fclose(fpo); - fclose(fp); - 以缩短程序运行时间 */ - #ifndef _WIN32 - } else { // small file, use mmap & fwrite - int fd = open(input, O_RDONLY); - if(fd <= 0) { - perror("Open input file error"); - return 5; - } - char *input_file = mmap(NULL, (size_t)inputsize, PROT_READ, MAP_PRIVATE, fd, 0); - if(input_file == MAP_FAILED) { - perror("Map input file error"); - return 6; - } - int outputsize = encode_len(inputsize)+16; - fputc(0xFE, fpo); - fputc(0xFF, fpo); - int n = encode(input_file, (int)inputsize, decbuf, outputsize); - if(fwrite(decbuf, n, 1, fpo) <= 0) { - perror("Write file error"); - return 7; - } - munmap(input_file, (size_t)inputsize); - /* 由操作系统负责释放资源 - fclose(fpo); - close(fd); - 以缩短程序运行时间 */ - } - #endif - return 0; -} - -#define rm_head(fp) {\ - int ch = fgetc(fp);\ - if(ch == 0xFE) fgetc(fp);\ - else rewind(fp);\ -} - -#define skip_offset(input_file) ((input_file[0]==(char)0xFE)?2:0) - -static int is_next_end(FILE* fp) { - int ch = fgetc(fp); - if(ch == '=') return fgetc(fp); - ungetc(ch, fp); - return 0; -} - -static int decode_file(const char* input, const char* output) { - off_t inputsize; - FILE* fp = NULL; - FILE* fpo; - if(*(uint16_t*)input == *(uint16_t*)"-") { // read from stdin - inputsize = 0; - fp = stdin; - } else inputsize = get_file_size(input); - if(inputsize < 0) { - perror("Get file size error"); - return 1; - } - fpo = (*(uint16_t*)output == *(uint16_t*)"-")?stdout:fopen(output, "wb"); - if(!fpo) { - perror("Fopen output file error"); - return 2; - } - if(!inputsize || inputsize > BUFSIZ*1024) { // stdin or big file, use decbuf & fread - inputsize = BUFSIZ*1024/8*8; - #ifdef _WIN32 - } - #endif - if(!fp) fp = fopen(input, "rb"); - if(!fp) { - perror("Fopen input file error"); - return 3; - } - int outputsize = decode_len(inputsize, 0)+16; - int cnt = 0; - int end = 0; - rm_head(fp); - while((cnt = fread(decbuf, sizeof(char), inputsize, fp))) { - if((end = is_next_end(fp))) { - decbuf[cnt++] = '='; - decbuf[cnt++] = end; - } - if(fwrite(encbuf, decode(decbuf, cnt, encbuf, outputsize), 1, fpo) <= 0) { - perror("Write file error"); - return 4; - } - } - /* 由操作系统负责释放资源 - fclose(fpo); - fclose(fp); - 以缩短程序运行时间 */ - #ifndef _WIN32 - } else { // small file, use mmap & fwrite - int fd = open(input, O_RDONLY); - if(fd <= 0) { - perror("Open input file error"); - return 5; - } - char *input_file = mmap(NULL, (size_t)inputsize, PROT_READ, MAP_PRIVATE, fd, 0); - if(input_file == MAP_FAILED) { - perror("Map input file error"); - return 6; - } - int outputsize = decode_len(inputsize, 0)+16; - int off = skip_offset(input_file); - if(fwrite(encbuf, decode(input_file+off, inputsize-off, encbuf, outputsize), 1, fpo) <= 0) { - perror("Write file error"); - return 7; - } - munmap(input_file, (size_t)inputsize); - /* 由操作系统负责释放资源 - fclose(fpo); - close(fd); - 以缩短程序运行时间 */ - } - #endif - return 0; -} +char encbuf[BASE16384_ENCBUFSZ]; +char decbuf[BASE16384_DECBUFSZ]; #ifndef _WIN32 unsigned long get_start_ms() { @@ -211,32 +34,73 @@ unsigned long get_start_ms() { } #endif +static void print_usage() { + puts("Copyright (c) 2022 Fumiama Minamoto.\nBase16384 2.2.0 (Oct 16th 2022). Usage:"); + puts("base16384 [-edt] [inputfile] [outputfile]"); + puts(" -e\t\tencode"); + puts(" -d\t\tdecode"); + puts(" -t\t\tshow spend time"); + puts(" inputfile\tpass - to read from stdin"); + puts(" outputfile\tpass - to write to stdout"); +} + int main(int argc, char** argv) { - if(argc != 4) { - puts("Usage: -[e|d] "); - puts("\t-e encode"); - puts("\t-d decode"); - puts("\t pass - to read from stdin"); - puts("\t pass - to write to stdout"); - exit(EXIT_SUCCESS); + if(argc != 4 || argv[1][0] != '-') { + print_usage(); + return -1; } - #ifdef _WIN32 - clock_t t = clock(); - #else - unsigned long t = get_start_ms(); - #endif - int exitstat = 0; - switch(argv[1][1]) { - case 'e': exitstat = encode_file(argv[2], argv[3]); break; - case 'd': exitstat = decode_file(argv[2], argv[3]); break; - default: break; + int flaglen = strlen(argv[1]); + if(flaglen <= 1 || flaglen > 3) { + print_usage(); + return -2; } - if(!exitstat && *(uint16_t*)(argv[3]) != *(uint16_t*)"-") { + #ifdef _WIN32 + clock_t t = 0; + #else + unsigned long t = 0; + #endif + base16384_err_t exitstat = base16384_err_ok; + char cmd = argv[1][1]; + if(cmd == 't') { + if(flaglen == 2) { + print_usage(); return -3; + } + #ifdef _WIN32 + t = clock(); + #else + t = get_start_ms(); + #endif + cmd = argv[1][2]; + } else if(flaglen == 3) { + if(argv[1][2] != 't') { + print_usage(); return -4; + } + #ifdef _WIN32 + t = clock(); + #else + t = get_start_ms(); + #endif + } + switch(cmd) { + case 'e': exitstat = base16384_encode_file(argv[2], argv[3], encbuf, decbuf); break; + case 'd': exitstat = base16384_decode_file(argv[2], argv[3], encbuf, decbuf); break; + default: print_usage(); return -5; + } + if(t && !exitstat && *(uint16_t*)(argv[3]) != *(uint16_t*)"-") { #ifdef _WIN32 printf("spend time: %lums\n", clock() - t); #else printf("spend time: %lums\n", get_start_ms() - t); #endif } + if(exitstat) switch(exitstat) { + case base16384_err_get_file_size: perror("base16384_err_get_file_size"); break; + case base16384_err_fopen_output_file: perror("base16384_err_fopen_output_file"); break; + case base16384_err_fopen_input_file: perror("base16384_err_fopen_input_file"); break; + case base16384_err_write_file: perror("base16384_err_write_file"); break; + case base16384_err_open_input_file: perror("base16384_err_open_input_file"); break; + case base16384_err_map_input_file: perror("base16384_err_map_input_file"); break; + default: perror("base16384"); break; + } return exitstat; } diff --git a/base16384.h b/base16384.h index 2a4469c..5aa686b 100644 --- a/base16384.h +++ b/base16384.h @@ -1,5 +1,5 @@ -#ifndef _BASE14_H_ -#define _BASE14_H_ +#ifndef _BASE16384_H_ +#define _BASE16384_H_ /* base16384.h * This file is part of the base16384 distribution (https://github.com/fumiama/base16384). @@ -18,8 +18,26 @@ * along with this program. If not, see . */ -// encode_len calc min buf size to fill encode result -int encode_len(int dlen) { +#include + +// base16384_err_t is the return value of base16384_en/decode_file +enum base16384_err_t { + base16384_err_ok, + base16384_err_get_file_size, + base16384_err_fopen_output_file, + base16384_err_fopen_input_file, + base16384_err_write_file, + base16384_err_open_input_file, + base16384_err_map_input_file, +}; +// base16384_err_t is the return value of base16384_en/decode_file +typedef enum base16384_err_t base16384_err_t; + +#define BASE16384_ENCBUFSZ (BUFSIZ*1024/7*7) +#define BASE16384_DECBUFSZ (BUFSIZ*1024/8*8+2) + +// base16384_encode_len calc min buf size to fill encode result +static inline int base16384_encode_len(int dlen) { int outlen = dlen / 7 * 8; int offset = dlen % 7; switch(offset) { // 算上偏移标志字符占用的2字节 @@ -35,8 +53,8 @@ int encode_len(int dlen) { return outlen + 8; // 冗余的8B用于可能的结尾的覆盖 } -// decode_len calc min buf size to fill decode result -int decode_len(int dlen, int offset) { +// base16384_decode_len calc min buf size to fill decode result +static inline int base16384_decode_len(int dlen, int offset) { int outlen = dlen; switch(offset) { // 算上偏移标志字符占用的2字节 case 0: break; @@ -51,9 +69,20 @@ int decode_len(int dlen, int offset) { return outlen / 8 * 7 + offset + 1; // 多出1字节用于循环覆盖 } -// encode data and write result into buf -int encode(const char* data, int dlen, char* buf, int blen); -// decode data and write result into buf -int decode(const char* data, int dlen, char* buf, int blen); +// base16384_encode encodes data and write result into buf +int base16384_encode(const char* data, int dlen, char* buf, int blen); -#endif \ No newline at end of file +// base16384_decode decodes data and write result into buf +int base16384_decode(const char* data, int dlen, char* buf, int blen); + +// base16384_encode_file encodes input file to output file. +// use `-` to specify stdin/stdout +// encbuf & decbuf must be no less than BASE16384_ENCBUFSZ & BASE16384_DECBUFSZ +base16384_err_t base16384_encode_file(const char* input, const char* output, char* encbuf, char* decbuf); + +// base16384_decode_file decodes input file to output file. +// use `-` to specify stdin/stdout +// encbuf & decbuf must be no less than BASE16384_ENCBUFSZ & BASE16384_DECBUFSZ +base16384_err_t base16384_decode_file(const char* input, const char* output, char* encbuf, char* decbuf); + +#endif diff --git a/file.c b/file.c new file mode 100644 index 0000000..2d6fc4c --- /dev/null +++ b/file.c @@ -0,0 +1,186 @@ +/* file.c + * This file is part of the base16384 distribution (https://github.com/fumiama/base16384). + * Copyright (c) 2022 Fumiama Minamoto. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __cosmopolitan +#include +#include +#include +#include +#include +#ifdef _WIN32 + #include +#else + #include +#endif +#endif +#include "base16384.h" + +#ifdef __cosmopolitan +#define get_file_size(filepath) ((off_t)GetFileSize(filepath)) +#else +static off_t get_file_size(const char* filepath) { + struct stat statbuf; + return stat(filepath, &statbuf)?-1:statbuf.st_size; +} +#endif + +base16384_err_t base16384_encode_file(const char* input, const char* output, char* encbuf, char* decbuf) { + off_t inputsize; + FILE* fp = NULL; + FILE* fpo; + if(*(uint16_t*)input == *(uint16_t*)"-") { // read from stdin + inputsize = 0; + fp = stdin; + } else inputsize = get_file_size(input); + if(inputsize < 0) { + return base16384_err_get_file_size; + } + fpo = (*(uint16_t*)output == *(uint16_t*)"-")?stdout:fopen(output, "wb"); + if(!fpo) { + return base16384_err_fopen_output_file; + } + if(!inputsize || inputsize > BUFSIZ*1024) { // stdin or big file, use encbuf & fread + inputsize = BUFSIZ*1024/7*7; + #ifdef _WIN32 + } + #endif + if(!fp) fp = fopen(input, "rb"); + if(!fp) { + return base16384_err_fopen_input_file; + } + + int outputsize = base16384_encode_len(inputsize)+16; + size_t cnt = 0; + fputc(0xFE, fpo); + fputc(0xFF, fpo); + while((cnt = fread(encbuf, sizeof(char), inputsize, fp))) { + int n = base16384_encode(encbuf, cnt, decbuf, outputsize); + if(fwrite(decbuf, n, 1, fpo) <= 0) { + return base16384_err_write_file; + } + } + /* 由操作系统负责释放资源 + fclose(fpo); + fclose(fp); + 以缩短程序运行时间 */ + #ifndef _WIN32 + } else { // small file, use mmap & fwrite + int fd = open(input, O_RDONLY); + if(fd <= 0) { + return base16384_err_open_input_file; + } + char *input_file = mmap(NULL, (size_t)inputsize, PROT_READ, MAP_PRIVATE, fd, 0); + if(input_file == MAP_FAILED) { + return base16384_err_map_input_file; + } + int outputsize = base16384_encode_len(inputsize)+16; + fputc(0xFE, fpo); + fputc(0xFF, fpo); + int n = base16384_encode(input_file, (int)inputsize, decbuf, outputsize); + if(fwrite(decbuf, n, 1, fpo) <= 0) { + return base16384_err_write_file; + } + munmap(input_file, (size_t)inputsize); + /* 由操作系统负责释放资源 + fclose(fpo); + close(fd); + 以缩短程序运行时间 */ + } + #endif + return base16384_err_ok; +} + +#define rm_head(fp) {\ + int ch = fgetc(fp);\ + if(ch == 0xFE) fgetc(fp);\ + else rewind(fp);\ +} + +#define skip_offset(input_file) ((input_file[0]==(char)0xFE)?2:0) + +static int is_next_end(FILE* fp) { + int ch = fgetc(fp); + if(ch == '=') return fgetc(fp); + ungetc(ch, fp); + return 0; +} + +base16384_err_t base16384_decode_file(const char* input, const char* output, char* encbuf, char* decbuf) { + off_t inputsize; + FILE* fp = NULL; + FILE* fpo; + if(*(uint16_t*)input == *(uint16_t*)"-") { // read from stdin + inputsize = 0; + fp = stdin; + } else inputsize = get_file_size(input); + if(inputsize < 0) { + return base16384_err_get_file_size; + } + fpo = (*(uint16_t*)output == *(uint16_t*)"-")?stdout:fopen(output, "wb"); + if(!fpo) { + return base16384_err_fopen_output_file; + } + if(!inputsize || inputsize > BUFSIZ*1024) { // stdin or big file, use decbuf & fread + inputsize = BUFSIZ*1024/8*8; + #ifdef _WIN32 + } + #endif + if(!fp) fp = fopen(input, "rb"); + if(!fp) { + return base16384_err_fopen_input_file; + } + int outputsize = base16384_decode_len(inputsize, 0)+16; + int cnt = 0; + int end = 0; + rm_head(fp); + while((cnt = fread(decbuf, sizeof(char), inputsize, fp))) { + if((end = is_next_end(fp))) { + decbuf[cnt++] = '='; + decbuf[cnt++] = end; + } + if(fwrite(encbuf, base16384_decode(decbuf, cnt, encbuf, outputsize), 1, fpo) <= 0) { + return base16384_err_write_file; + } + } + /* 由操作系统负责释放资源 + fclose(fpo); + fclose(fp); + 以缩短程序运行时间 */ + #ifndef _WIN32 + } else { // small file, use mmap & fwrite + int fd = open(input, O_RDONLY); + if(fd <= 0) { + return base16384_err_open_input_file; + } + char *input_file = mmap(NULL, (size_t)inputsize, PROT_READ, MAP_PRIVATE, fd, 0); + if(input_file == MAP_FAILED) { + return base16384_err_map_input_file; + } + int outputsize = base16384_decode_len(inputsize, 0)+16; + int off = skip_offset(input_file); + if(fwrite(encbuf, base16384_decode(input_file+off, inputsize-off, encbuf, outputsize), 1, fpo) <= 0) { + return base16384_err_write_file; + } + munmap(input_file, (size_t)inputsize); + /* 由操作系统负责释放资源 + fclose(fpo); + close(fd); + 以缩短程序运行时间 */ + } + #endif + return base16384_err_ok; +}