char **dictionary_path,\r
int *force,\r
int *quality,\r
+ int *gapmem,\r
int *decompress,\r
int *repeat,\r
int *verbose,\r
}\r
++k;\r
continue;\r
+ } else if (!strcmp("--gap", argv[k]) ||\r
+ !strcmp("-g", argv[k])) {\r
+ if (!ParseQuality(argv[k + 1], gapmem)) {\r
+ goto error;\r
+ }\r
+ ++k;\r
+ continue;\r
}\r
}\r
goto error;\r
return;\r
error:\r
fprintf(stderr,\r
- "Usage: %s [--force] [--quality n] [--decompress]"\r
+ "Usage: %s [--force] [--quality n] [--gap n] [--decompress]"\r
" [--input filename] [--output filename] [--repeat iters]"\r
" [--verbose] [--window n] [--custom-dictionary filename]\n",\r
argv[0]);\r
return retval;\r
}\r
\r
+/* Brotli specified memory allocate function */\r
+static void *BrAlloc (void *memsize, size_t size) {\r
+ *(int64_t *)memsize += size;\r
+ return malloc(size);\r
+}\r
+\r
+/* Brotli specified memory free function */\r
+static void BrFree (void *memsize, void *ptr) {\r
+ free(ptr);\r
+}\r
+\r
/* Result ownersip is passed to caller.\r
|*dictionary_size| is set to resulting buffer size. */\r
-static uint8_t* ReadDictionary(const char* path, size_t* dictionary_size) {\r
+static uint8_t* ReadDictionary(const char* path, size_t* dictionary_size, void *memsize) {\r
static const int kMaxDictionarySize = (1 << 24) - 16;\r
FILE *f = fopen(path, "rb");\r
int64_t file_size_64;\r
}\r
*dictionary_size = (size_t)file_size_64;\r
\r
- buffer = (uint8_t*)malloc(*dictionary_size);\r
+ buffer = (uint8_t *)BrAlloc(memsize, *dictionary_size);\r
if (!buffer) {\r
fprintf(stderr, "could not read dictionary: out of memory\n");\r
exit(1);\r
\r
static const size_t kFileBufferSize = 65536;\r
\r
-static int Decompress(FILE* fin, FILE* fout, const char* dictionary_path) {\r
+static int Decompress(FILE* fin, FILE* fout, const char* dictionary_path, void *memsize) {\r
/* Dictionary should be kept during first rounds of decompression. */\r
uint8_t* dictionary = NULL;\r
uint8_t* input;\r
size_t available_out = kFileBufferSize;\r
uint8_t* next_out;\r
BrotliResult result = BROTLI_RESULT_ERROR;\r
- BrotliState* s = BrotliCreateState(NULL, NULL, NULL);\r
+ BrotliState* s = BrotliCreateState(BrAlloc, BrFree, memsize);\r
if (!s) {\r
fprintf(stderr, "out of memory\n");\r
return 0;\r
}\r
if (dictionary_path != NULL) {\r
size_t dictionary_size = 0;\r
- dictionary = ReadDictionary(dictionary_path, &dictionary_size);\r
+ dictionary = ReadDictionary(dictionary_path, &dictionary_size, memsize);\r
BrotliSetCustomDictionary(dictionary_size, dictionary, s);\r
}\r
- input = (uint8_t*)malloc(kFileBufferSize);\r
- output = (uint8_t*)malloc(kFileBufferSize);\r
+ input = (uint8_t*)BrAlloc(memsize, kFileBufferSize);\r
+ output = (uint8_t*)BrAlloc(memsize, kFileBufferSize);\r
if (!input || !output) {\r
fprintf(stderr, "out of memory\n");\r
goto end;\r
}\r
\r
end:\r
- free(dictionary);\r
- free(input);\r
- free(output);\r
+ BrFree(memsize, dictionary);\r
+ BrFree(memsize, input);\r
+ BrFree(memsize, output);\r
BrotliDestroyState(s);\r
return (result == BROTLI_RESULT_SUCCESS) ? 1 : 0;\r
}\r
\r
static int Compress(int quality, int lgwin, FILE* fin, FILE* fout,\r
- const char *dictionary_path) {\r
- BrotliEncoderState* s = BrotliEncoderCreateInstance(0, 0, 0);\r
- uint8_t* buffer = (uint8_t*)malloc(kFileBufferSize << 1);\r
+ const char *dictionary_path, void *memsize) {\r
+ BrotliEncoderState* s = BrotliEncoderCreateInstance(BrAlloc, BrFree, memsize);\r
+ uint8_t* buffer = (uint8_t*)BrAlloc(memsize, kFileBufferSize << 1);\r
uint8_t* input = buffer;\r
uint8_t* output = buffer + kFileBufferSize;\r
size_t available_in = 0;\r
BrotliEncoderSetParameter(s, BROTLI_PARAM_LGWIN, (uint32_t)lgwin);\r
if (dictionary_path != NULL) {\r
size_t dictionary_size = 0;\r
- uint8_t* dictionary = ReadDictionary(dictionary_path, &dictionary_size);\r
+ uint8_t* dictionary = ReadDictionary(dictionary_path, &dictionary_size, memsize);\r
BrotliEncoderSetCustomDictionary(s, dictionary_size, dictionary);\r
- free(dictionary);\r
+ BrFree(memsize, dictionary);\r
}\r
\r
while (1) {\r
}\r
\r
finish:\r
- free(buffer);\r
+ BrFree(memsize, buffer);\r
BrotliEncoderDestroyInstance(s);\r
\r
if (!is_ok) {\r
return 1;\r
}\r
\r
+#define GAP_MEM_BLOCK 4096\r
+\r
int main(int argc, char** argv) {\r
char *input_path = 0;\r
char *output_path = 0;\r
char *dictionary_path = 0;\r
int force = 0;\r
int quality = 11;\r
+ int gmem = 1;\r
int decompress = 0;\r
int repeat = 1;\r
int verbose = 0;\r
int lgwin = 0;\r
clock_t clock_start;\r
int i;\r
+ int64_t originsize = 0;\r
+ int64_t msize = 0;\r
ParseArgv(argc, argv, &input_path, &output_path, &dictionary_path, &force,\r
- &quality, &decompress, &repeat, &verbose, &lgwin);\r
+ &quality, &gmem, &decompress, &repeat, &verbose, &lgwin);\r
clock_start = clock();\r
for (i = 0; i < repeat; ++i) {\r
FILE* fin = OpenInputFile(input_path);\r
FILE* fout = OpenOutputFile(output_path, force || repeat);\r
int is_ok = 0;\r
if (decompress) {\r
- is_ok = Decompress(fin, fout, dictionary_path);\r
+ if (fseek(fin, 16, SEEK_SET) != 0) {\r
+ fclose(fin);\r
+ return -1;\r
+ }\r
+ is_ok = Decompress(fin, fout, dictionary_path, (void *)&msize);\r
} else {\r
- is_ok = Compress(quality, lgwin, fin, fout, dictionary_path);\r
+ originsize = FileSize(input_path); /* get original file size */\r
+ fwrite(&originsize, 1, sizeof(int64_t), fout); /* add in original binary file size */\r
+ fwrite(&msize, 1, sizeof(int64_t), fout); /* add in dummy decompression required memory size */\r
+ is_ok = Compress(quality, lgwin, fin, fout, dictionary_path, (void *)&msize);\r
}\r
if (!is_ok) {\r
unlink(output_path);\r
perror("fclose");\r
exit(1);\r
}\r
+ /* after compression operation then execute decompression operation\r
+ to get decompression required memory size. */\r
+ if (decompress == 0) {\r
+ fin = OpenInputFile(output_path);\r
+ fout = tmpfile ();\r
+ msize = 0;\r
+ if (fseek(fin, 16, SEEK_SET) != 0) {\r
+ fclose(fin);\r
+ return -1;\r
+ }\r
+ is_ok = Decompress(fin, fout, dictionary_path, (void *)&msize);\r
+ if (!is_ok) {\r
+ exit(1);\r
+ }\r
+ if (fclose(fin) != 0) {\r
+ perror("fclose");\r
+ exit(1);\r
+ }\r
+ if (fclose(fout) != 0) {\r
+ perror("fclose");\r
+ exit(1);\r
+ }\r
+ fout = fopen(output_path, "rb+"); /* open output_path file and add in head info */\r
+ /* seek to the offset of decompression required memory size */\r
+ if (fseek(fout, 8, SEEK_SET) != 0) {\r
+ fclose(fout);\r
+ return -1;\r
+ }\r
+ msize += gmem * GAP_MEM_BLOCK; /* there is a memory gap between IA32 and X64 environment*/\r
+ fwrite(&msize, 1, sizeof(int64_t), fout); /* update final decompression required memory size */\r
+ if (fclose(fout) != 0) {\r
+ perror("fclose");\r
+ exit(1);\r
+ }\r
+ }\r
}\r
if (verbose) {\r
clock_t clock_end = clock();\r