mirror of
https://github.com/google/brotli.git
synced 2025-01-13 09:50:08 +00:00
Update bro tool:
* use new decoder API * copy permissions and modification time to output file
This commit is contained in:
parent
f20b3eeb2f
commit
9223fd4d8d
82
tools/bro.c
82
tools/bro.c
@ -19,9 +19,11 @@
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#include <unistd.h>
|
||||
#include <utime.h>
|
||||
#else
|
||||
#include <io.h>
|
||||
#include <share.h>
|
||||
#include <sys/utime.h>
|
||||
|
||||
#define MAKE_BINARY(FILENO) (_setmode((FILENO), _O_BINARY), (FILENO))
|
||||
|
||||
@ -31,12 +33,18 @@
|
||||
#define S_IRUSR S_IREAD
|
||||
#define S_IWUSR S_IWRITE
|
||||
#endif
|
||||
|
||||
#define fdopen _fdopen
|
||||
#define unlink _unlink
|
||||
#define utimbuf _utimbuf
|
||||
#define utime _utime
|
||||
|
||||
#define fopen ms_fopen
|
||||
#define open ms_open
|
||||
|
||||
#define chmod(F, P)
|
||||
#define chown(F, O, G)
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||
#define fseek _fseeki64
|
||||
#define ftell _ftelli64
|
||||
@ -76,7 +84,8 @@ static void ParseArgv(int argc, char **argv,
|
||||
int *decompress,
|
||||
int *repeat,
|
||||
int *verbose,
|
||||
int *lgwin) {
|
||||
int *lgwin,
|
||||
int *copy_stat) {
|
||||
int k;
|
||||
*force = 0;
|
||||
*input_path = 0;
|
||||
@ -84,6 +93,7 @@ static void ParseArgv(int argc, char **argv,
|
||||
*repeat = 1;
|
||||
*verbose = 0;
|
||||
*lgwin = 22;
|
||||
*copy_stat = 1;
|
||||
{
|
||||
size_t argv0_len = strlen(argv[0]);
|
||||
*decompress =
|
||||
@ -109,6 +119,12 @@ static void ParseArgv(int argc, char **argv,
|
||||
}
|
||||
*verbose = 1;
|
||||
continue;
|
||||
} else if (!strcmp("--no-copy-stat", argv[k])) {
|
||||
if (*copy_stat == 0) {
|
||||
goto error;
|
||||
}
|
||||
*copy_stat = 0;
|
||||
continue;
|
||||
}
|
||||
if (k < argc - 1) {
|
||||
if (!strcmp("--input", argv[k]) ||
|
||||
@ -150,7 +166,7 @@ static void ParseArgv(int argc, char **argv,
|
||||
}
|
||||
++k;
|
||||
continue;
|
||||
} else if (!strcmp("--window", argv[k]) ||
|
||||
} else if (!strcmp("--window", argv[k]) ||
|
||||
!strcmp("-w", argv[k])) {
|
||||
if (!ParseQuality(argv[k + 1], lgwin)) {
|
||||
goto error;
|
||||
@ -169,7 +185,8 @@ error:
|
||||
fprintf(stderr,
|
||||
"Usage: %s [--force] [--quality n] [--decompress]"
|
||||
" [--input filename] [--output filename] [--repeat iters]"
|
||||
" [--verbose] [--window n] [--custom-dictionary filename]\n",
|
||||
" [--verbose] [--window n] [--custom-dictionary filename]"
|
||||
" [--no-copy-stat]\n",
|
||||
argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
@ -225,6 +242,26 @@ static int64_t FileSize(const char *path) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Copy file times and permissions.
|
||||
TODO: this is a "best effort" implementation; honest cross-platform
|
||||
fully featured implementation is way too hacky; add more hacks by request. */
|
||||
static void CopyStat(const char* input_path, const char* output_path) {
|
||||
struct stat statbuf;
|
||||
struct utimbuf times;
|
||||
if (input_path == 0 || output_path == 0) {
|
||||
return;
|
||||
}
|
||||
if (stat(input_path, &statbuf) != 0) {
|
||||
return;
|
||||
}
|
||||
times.actime = statbuf.st_atime;
|
||||
times.modtime = statbuf.st_mtime;
|
||||
utime(output_path, ×);
|
||||
chmod(output_path, statbuf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
|
||||
chown(output_path, (__uid_t)-1, statbuf.st_gid);
|
||||
chown(output_path, statbuf.st_uid, (__gid_t)-1);
|
||||
}
|
||||
|
||||
/* Result ownersip is passed to caller.
|
||||
|*dictionary_size| is set to resulting buffer size. */
|
||||
static uint8_t* ReadDictionary(const char* path, size_t* dictionary_size) {
|
||||
@ -273,13 +310,12 @@ static int Decompress(FILE* fin, FILE* fout, const char* dictionary_path) {
|
||||
uint8_t* dictionary = NULL;
|
||||
uint8_t* input;
|
||||
uint8_t* output;
|
||||
size_t total_out;
|
||||
size_t available_in;
|
||||
const uint8_t* next_in;
|
||||
size_t available_out = kFileBufferSize;
|
||||
uint8_t* next_out;
|
||||
BrotliResult result = BROTLI_RESULT_ERROR;
|
||||
BrotliState* s = BrotliCreateState(NULL, NULL, NULL);
|
||||
BrotliDecoderResult result = BROTLI_DECODER_RESULT_ERROR;
|
||||
BrotliDecoderState* s = BrotliDecoderCreateInstance(NULL, NULL, NULL);
|
||||
if (!s) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
return 0;
|
||||
@ -287,7 +323,7 @@ static int Decompress(FILE* fin, FILE* fout, const char* dictionary_path) {
|
||||
if (dictionary_path != NULL) {
|
||||
size_t dictionary_size = 0;
|
||||
dictionary = ReadDictionary(dictionary_path, &dictionary_size);
|
||||
BrotliSetCustomDictionary(dictionary_size, dictionary, s);
|
||||
BrotliDecoderSetCustomDictionary(s, dictionary_size, dictionary);
|
||||
}
|
||||
input = (uint8_t*)malloc(kFileBufferSize);
|
||||
output = (uint8_t*)malloc(kFileBufferSize);
|
||||
@ -296,9 +332,9 @@ static int Decompress(FILE* fin, FILE* fout, const char* dictionary_path) {
|
||||
goto end;
|
||||
}
|
||||
next_out = output;
|
||||
result = BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
result = BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
|
||||
while (1) {
|
||||
if (result == BROTLI_RESULT_NEEDS_MORE_INPUT) {
|
||||
if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
|
||||
if (feof(fin)) {
|
||||
break;
|
||||
}
|
||||
@ -307,7 +343,7 @@ static int Decompress(FILE* fin, FILE* fout, const char* dictionary_path) {
|
||||
if (ferror(fin)) {
|
||||
break;
|
||||
}
|
||||
} else if (result == BROTLI_RESULT_NEEDS_MORE_OUTPUT) {
|
||||
} else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
|
||||
fwrite(output, 1, kFileBufferSize, fout);
|
||||
if (ferror(fout)) {
|
||||
break;
|
||||
@ -317,16 +353,17 @@ static int Decompress(FILE* fin, FILE* fout, const char* dictionary_path) {
|
||||
} else {
|
||||
break; /* Error or success. */
|
||||
}
|
||||
result = BrotliDecompressStream(&available_in, &next_in,
|
||||
&available_out, &next_out, &total_out, s);
|
||||
result = BrotliDecoderDecompressStream(
|
||||
s, &available_in, &next_in, &available_out, &next_out, 0);
|
||||
}
|
||||
if (next_out != output) {
|
||||
fwrite(output, 1, (size_t)(next_out - output), fout);
|
||||
}
|
||||
|
||||
if ((result == BROTLI_RESULT_NEEDS_MORE_OUTPUT) || ferror(fout)) {
|
||||
if ((result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) || ferror(fout)) {
|
||||
fprintf(stderr, "failed to write output\n");
|
||||
} else if (result != BROTLI_RESULT_SUCCESS) { /* Error or needs more input. */
|
||||
} else if (result != BROTLI_DECODER_RESULT_SUCCESS) {
|
||||
/* Error or needs more input. */
|
||||
fprintf(stderr, "corrupt input\n");
|
||||
}
|
||||
|
||||
@ -334,8 +371,8 @@ end:
|
||||
free(dictionary);
|
||||
free(input);
|
||||
free(output);
|
||||
BrotliDestroyState(s);
|
||||
return (result == BROTLI_RESULT_SUCCESS) ? 1 : 0;
|
||||
BrotliDecoderDestroyInstance(s);
|
||||
return (result == BROTLI_DECODER_RESULT_SUCCESS) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int Compress(int quality, int lgwin, FILE* fin, FILE* fout,
|
||||
@ -419,14 +456,15 @@ int main(int argc, char** argv) {
|
||||
int repeat = 1;
|
||||
int verbose = 0;
|
||||
int lgwin = 0;
|
||||
int copy_stat = 1;
|
||||
clock_t clock_start;
|
||||
int i;
|
||||
ParseArgv(argc, argv, &input_path, &output_path, &dictionary_path, &force,
|
||||
&quality, &decompress, &repeat, &verbose, &lgwin);
|
||||
&quality, &decompress, &repeat, &verbose, &lgwin, ©_stat);
|
||||
clock_start = clock();
|
||||
for (i = 0; i < repeat; ++i) {
|
||||
FILE* fin = OpenInputFile(input_path);
|
||||
FILE* fout = OpenOutputFile(output_path, force || repeat);
|
||||
FILE* fout = OpenOutputFile(output_path, force || (repeat > 1));
|
||||
int is_ok = 0;
|
||||
if (decompress) {
|
||||
is_ok = Decompress(fin, fout, dictionary_path);
|
||||
@ -437,11 +475,15 @@ int main(int argc, char** argv) {
|
||||
unlink(output_path);
|
||||
exit(1);
|
||||
}
|
||||
if (fclose(fin) != 0) {
|
||||
if (fclose(fout) != 0) {
|
||||
perror("fclose");
|
||||
exit(1);
|
||||
}
|
||||
if (fclose(fout) != 0) {
|
||||
/* TOCTOU violation, but otherwise it is impossible to set file times. */
|
||||
if (copy_stat && (i + 1 == repeat)) {
|
||||
CopyStat(input_path, output_path);
|
||||
}
|
||||
if (fclose(fin) != 0) {
|
||||
perror("fclose");
|
||||
exit(1);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user