BaseTools: Add Brotli algorithm tool
authorSong, BinX <binx.song@intel.com>
Thu, 23 Mar 2017 02:16:16 +0000 (10:16 +0800)
committerLiming Gao <liming.gao@intel.com>
Wed, 29 Mar 2017 04:14:43 +0000 (12:14 +0800)
- Add Brotli algorithm tool support

Cc: Liming Gao <liming.gao@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Bell Song <binx.song@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
BaseTools/BinWrappers/PosixLike/Brotli [new file with mode: 0644]
BaseTools/BinWrappers/PosixLike/BrotliCompress [new file with mode: 0644]
BaseTools/Conf/tools_def.template
BaseTools/Source/C/BrotliCompress/BrotliCompress.bat [new file with mode: 0644]
BaseTools/Source/C/BrotliCompress/GNUmakefile [new file with mode: 0644]
BaseTools/Source/C/BrotliCompress/Makefile [new file with mode: 0644]
BaseTools/Source/C/BrotliCompress/ReadMe.txt [new file with mode: 0644]
BaseTools/Source/C/BrotliCompress/tools/bro.c
BaseTools/Source/C/GNUmakefile
BaseTools/Source/C/Makefile

diff --git a/BaseTools/BinWrappers/PosixLike/Brotli b/BaseTools/BinWrappers/PosixLike/Brotli
new file mode 100644 (file)
index 0000000..a244ecc
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash\r
+\r
+full_cmd=${BASH_SOURCE:-$0} # see http://mywiki.wooledge.org/BashFAQ/028 for a discussion of why $0 is not a good choice here\r
+dir=$(dirname "$full_cmd")\r
+cmd=${full_cmd##*/}\r
+\r
+if [ -n "$WORKSPACE" ] && [ -e "$WORKSPACE/Conf/BaseToolsCBinaries" ]\r
+then\r
+  exec "$WORKSPACE/Conf/BaseToolsCBinaries/$cmd"\r
+elif [ -n "$WORKSPACE" ] && [ -e "$EDK_TOOLS_PATH/Source/C" ]\r
+then\r
+  if [ ! -e "$EDK_TOOLS_PATH/Source/C/bin/$cmd" ]\r
+  then\r
+    echo "BaseTools C Tool binary was not found ($cmd)"\r
+    echo "You may need to run:"\r
+    echo "  make -C $EDK_TOOLS_PATH/Source/C"\r
+  else\r
+    exec "$EDK_TOOLS_PATH/Source/C/bin/$cmd" "$@"\r
+  fi\r
+elif [ -e "$dir/../../Source/C/bin/$cmd" ]\r
+then\r
+  exec "$dir/../../Source/C/bin/$cmd" "$@"\r
+else\r
+  echo "Unable to find the real '$cmd' to run"\r
+  echo "This message was printed by"\r
+  echo "  $0"\r
+  exit 127\r
+fi\r
+\r
diff --git a/BaseTools/BinWrappers/PosixLike/BrotliCompress b/BaseTools/BinWrappers/PosixLike/BrotliCompress
new file mode 100644 (file)
index 0000000..a571ff6
--- /dev/null
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash\r
+#\r
+# This script will exec Brotli tool.\r
+#\r
+# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution.  The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+LVL="--quality 9"\r
+\r
+while [ $# != 0 ];do\r
+  case $1 in\r
+    -d)\r
+      ARGS+="--decompress "\r
+    ;;\r
+    -e)\r
+    ;;\r
+    -g)\r
+      ARGS+="--gap $2 "\r
+      shift\r
+    ;;\r
+    -l)\r
+      LVL="--quality $2 "\r
+      shift\r
+    ;;\r
+    -o)\r
+      ARGS+="--output $2 "\r
+      shift\r
+    ;;\r
+    *)\r
+      ARGS+="--input $1 "\r
+  esac\r
+\r
+shift\r
+done\r
+\r
+exec Brotli $ARGS $LVL\r
index ab4f936..0aabdeb 100755 (executable)
@@ -7706,6 +7706,12 @@ RELEASE_RVCTCYGWIN_ARM_CC_FLAGS  = "$(CCPATH_FLAG)" $(ARCHCC_FLAGS) $(PLATFORM_F
 *_*_*_RSA2048SHA256SIGN_PATH = Rsa2048Sha256Sign\r
 *_*_*_RSA2048SHA256SIGN_GUID = A7717414-C616-4977-9420-844712A735BF\r
 \r
+##################\r
+# BrotliCompress tool definitions\r
+##################\r
+*_*_*_BROTLI_PATH        = BrotliCompress\r
+*_*_*_BROTLI_GUID        = 3D532050-5CDA-4FD0-879E-0F7F630D5AFB\r
+\r
 ##################\r
 # LzmaCompress tool definitions\r
 ##################\r
diff --git a/BaseTools/Source/C/BrotliCompress/BrotliCompress.bat b/BaseTools/Source/C/BrotliCompress/BrotliCompress.bat
new file mode 100644 (file)
index 0000000..1bca076
--- /dev/null
@@ -0,0 +1,48 @@
+@echo off\r
+@setlocal\r
+\r
+set LVL=--quality 9\r
+\r
+:Begin\r
+if "%1"=="" goto End\r
+\r
+if "%1"=="-d" (\r
+  set ARGS=%ARGS% --decompress\r
+  shift\r
+  goto Begin\r
+)\r
+\r
+if "%1"=="-e" (\r
+  shift\r
+  goto Begin\r
+)\r
+\r
+if "%1"=="-g" (\r
+  set ARGS=%ARGS% --gap %2\r
+  shift\r
+  shift\r
+  goto Begin\r
+)\r
+\r
+if "%1"=="-l" (\r
+  set LVL=--quality %2\r
+  shift\r
+  shift\r
+  goto Begin\r
+)\r
+\r
+if "%1"=="-o" (\r
+  set ARGS=%ARGS% --output %2\r
+  set INTMP=%2\r
+  shift\r
+  shift\r
+  goto Begin\r
+)\r
+\r
+set ARGS=%ARGS% --input %1\r
+shift\r
+goto Begin\r
+\r
+:End\r
+Brotli %ARGS% %LVL%\r
+@echo on\r
\ No newline at end of file
diff --git a/BaseTools/Source/C/BrotliCompress/GNUmakefile b/BaseTools/Source/C/BrotliCompress/GNUmakefile
new file mode 100644 (file)
index 0000000..368edbd
--- /dev/null
@@ -0,0 +1,43 @@
+## @file\r
+# GNU/Linux makefile for 'Brotli' module build.\r
+#\r
+# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution.  The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+ARCH ?= IA32\r
+MAKEROOT ?= ..\r
+\r
+APPNAME = Brotli\r
+\r
+OBJECTS = \\r
+  tools/bro.o \\r
+  common/dictionary.o \\r
+  dec/bit_reader.o \\r
+  dec/decode.o \\r
+  dec/huffman.o \\r
+  dec/state.o \\r
+  enc/backward_references.o \\r
+  enc/bit_cost.o \\r
+  enc/block_splitter.o \\r
+  enc/brotli_bit_stream.o \\r
+  enc/cluster.o \\r
+  enc/compress_fragment.o \\r
+  enc/compress_fragment_two_pass.o \\r
+  enc/encode.o \\r
+  enc/entropy_encode.o \\r
+  enc/histogram.o \\r
+  enc/literal_cost.o \\r
+  enc/memory.o \\r
+  enc/metablock.o \\r
+  enc/static_dict.o \\r
+  enc/utf8_util.o\r
+\r
+include $(MAKEROOT)/Makefiles/app.makefile\r
+\r
+LIBS += -lm\r
diff --git a/BaseTools/Source/C/BrotliCompress/Makefile b/BaseTools/Source/C/BrotliCompress/Makefile
new file mode 100644 (file)
index 0000000..9d45ea5
--- /dev/null
@@ -0,0 +1,60 @@
+## @file\r
+# Windows makefile for 'Brotli' module build.\r
+#\r
+# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution.  The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+!INCLUDE ..\Makefiles\ms.common\r
+\r
+CFLAGS = $(CFLAGS) /W2\r
+\r
+APPNAME = Brotli\r
+\r
+#LIBS = $(LIB_PATH)\Common.lib\r
+\r
+COMMON_OBJ = common\dictionary.obj\r
+DEC_OBJ = \\r
+  dec\bit_reader.obj \\r
+  dec\decode.obj \\r
+  dec\huffman.obj \\r
+  dec\state.obj\r
+ENC_OBJ = \\r
+  enc\backward_references.obj \\r
+  enc\bit_cost.obj \\r
+  enc\block_splitter.obj \\r
+  enc\brotli_bit_stream.obj \\r
+  enc\cluster.obj \\r
+  enc\compress_fragment.obj \\r
+  enc\compress_fragment_two_pass.obj \\r
+  enc\encode.obj \\r
+  enc\entropy_encode.obj \\r
+  enc\histogram.obj \\r
+  enc\literal_cost.obj \\r
+  enc\memory.obj \\r
+  enc\metablock.obj \\r
+  enc\static_dict.obj \\r
+  enc\utf8_util.obj\r
+\r
+OBJECTS = \\r
+  tools\bro.obj \\r
+  $(COMMON_OBJ) \\r
+  $(DEC_OBJ) \\r
+  $(ENC_OBJ)\r
+\r
+!INCLUDE ..\Makefiles\ms.app\r
+\r
+all: $(BIN_PATH)\BrotliCompress.bat\r
+\r
+$(BIN_PATH)\BrotliCompress.bat: BrotliCompress.bat\r
+  copy BrotliCompress.bat $(BIN_PATH)\BrotliCompress.bat /Y\r
+\r
+cleanall: localCleanall\r
+\r
+localCleanall:\r
+  del /f /q $(BIN_PATH)\BrotliCompress.bat > nul\r
diff --git a/BaseTools/Source/C/BrotliCompress/ReadMe.txt b/BaseTools/Source/C/BrotliCompress/ReadMe.txt
new file mode 100644 (file)
index 0000000..c19c0a1
--- /dev/null
@@ -0,0 +1,2 @@
+It is based on the Brotli v0.5.2.\r
+Brotli was released on the website https://github.com/google/brotli.\r
index 57e053a..2fa9f05 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
index 66baabb..83e188c 100644 (file)
@@ -52,6 +52,7 @@ LIBRARIES = Common
 APPLICATIONS = \\r
   GnuGenBootSector \\r
   BootSectImage \\r
+  BrotliCompress \\r
   EfiLdrImage \\r
   EfiRom \\r
   GenFfs \\r
index 3005a17..77d3b97 100644 (file)
@@ -17,6 +17,7 @@ ARCH = IA32
 LIBRARIES = Common\r
 APPLICATIONS = \\r
   BootSectImage \\r
+  BrotliCompress \\r
   EfiLdrImage \\r
   EfiRom \\r
   GenBootSector \\r