BaseTools: Add Brotli algorithm tool
[mirror_edk2.git] / BaseTools / Source / C / BrotliCompress / tools / bro.c
index 57e053aa298b0442078fdecaafb6a5241488d7bc..2fa9f05e7f21f68d73ea9dc4a1ac376fbede8b02 100644 (file)
@@ -73,6 +73,7 @@ static void ParseArgv(int argc, char **argv,
                       char **dictionary_path,\r
                       int *force,\r
                       int *quality,\r
+                      int *gapmem,\r
                       int *decompress,\r
                       int *repeat,\r
                       int *verbose,\r
@@ -160,6 +161,13 @@ static void ParseArgv(int argc, char **argv,
         }\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
@@ -167,7 +175,7 @@ static void ParseArgv(int argc, char **argv,
   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
@@ -225,9 +233,20 @@ static int64_t FileSize(const char *path) {
   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
@@ -252,7 +271,7 @@ static uint8_t* ReadDictionary(const char* path, size_t* dictionary_size) {
   }\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
@@ -268,7 +287,7 @@ static uint8_t* ReadDictionary(const char* path, size_t* dictionary_size) {
 \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
@@ -279,18 +298,18 @@ static int Decompress(FILE* fin, FILE* fout, const char* dictionary_path) {
   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
@@ -331,17 +350,17 @@ static int Decompress(FILE* fin, FILE* fout, const char* dictionary_path) {
   }\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
@@ -360,9 +379,9 @@ static int Compress(int quality, int lgwin, FILE* fin, FILE* fout,
   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
@@ -392,7 +411,7 @@ static int Compress(int quality, int lgwin, FILE* fin, FILE* fout,
   }\r
 \r
 finish:\r
-  free(buffer);\r
+  BrFree(memsize, buffer);\r
   BrotliEncoderDestroyInstance(s);\r
 \r
   if (!is_ok) {\r
@@ -409,29 +428,41 @@ finish:
   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
@@ -445,6 +476,41 @@ int main(int argc, char** argv) {
       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