]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/C/BrotliCompress/BrotliCompress.c
BaseTools: Fix BrotliCompress tool issue
[mirror_edk2.git] / BaseTools / Source / C / BrotliCompress / BrotliCompress.c
diff --git a/BaseTools/Source/C/BrotliCompress/BrotliCompress.c b/BaseTools/Source/C/BrotliCompress/BrotliCompress.c
new file mode 100644 (file)
index 0000000..5a1400f
--- /dev/null
@@ -0,0 +1,572 @@
+/** @file\r
+  BrotliCompress Compress/Decompress tool (BrotliCompress)\r
+\r
+  Copyright (c) 2020, ByoSoft Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+/* Command line interface for Brotli library. */\r
+\r
+#include <errno.h>\r
+#include <fcntl.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <sys/stat.h>\r
+#include <sys/types.h>\r
+#include <time.h>\r
+\r
+#include "./brotli/c/common/constants.h"\r
+#include "./brotli/c/common/version.h"\r
+#include <brotli/decode.h>\r
+#include <brotli/encode.h>\r
+\r
+#if !defined(_WIN32)\r
+#include <unistd.h>\r
+#include <utime.h>\r
+#else\r
+#include <io.h>\r
+#include <share.h>\r
+#include <sys/utime.h>\r
+\r
+#if !defined(__MINGW32__)\r
+#define STDIN_FILENO _fileno(stdin)\r
+#define STDOUT_FILENO _fileno(stdout)\r
+#define S_IRUSR S_IREAD\r
+#define S_IWUSR S_IWRITE\r
+#endif\r
+\r
+#define fopen ms_fopen\r
+#define open ms_open\r
+\r
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)\r
+#define fseek _fseeki64\r
+#define ftell _ftelli64\r
+#endif\r
+\r
+static FILE* ms_fopen(const char* FileName, const char* Mode) {\r
+  FILE* Result;\r
+  Result = NULL;\r
+  fopen_s(&Result, FileName, Mode);\r
+  return Result;\r
+}\r
+\r
+static int ms_open(const char* FileName, int Oflag, int Pmode) {\r
+  int Result;\r
+  Result = -1;\r
+  _sopen_s(&Result, FileName, Oflag | O_BINARY, _SH_DENYNO, Pmode);\r
+  return Result;\r
+}\r
+#endif  /* WIN32 */\r
+\r
+\r
+#ifndef _MAX_PATH\r
+#define _MAX_PATH 500\r
+#endif\r
+\r
+#define DEFAULT_LGWIN 22\r
+#define DECODE_HEADER_SIZE 0x10\r
+#define GAP_MEM_BLOCK 0x1000\r
+size_t ScratchBufferSize = 0;\r
+static const size_t kFileBufferSize  = 1 << 19;\r
+\r
+static void Version(void) {\r
+  int Major;\r
+  int Minor;\r
+  int Patch;\r
+  Major = BROTLI_VERSION >> 24;\r
+  Minor = (BROTLI_VERSION >> 12) & 0xFFF;\r
+  Patch = BROTLI_VERSION & 0xFFF;\r
+  printf("BrotliCompress %d.%d.%d\n", Major, Minor, Patch);\r
+}\r
+\r
+static void Usage() {\r
+  printf("Usage: %s [OPTION]... [FILE]...\n", __FILE__);\r
+  printf(\r
+"Options:\n"\r
+"  -e, --compress              compress\n"\r
+"  -d, --decompress            decompress\n"\r
+"  -h, --help                  display this help and exit\n");\r
+  printf(\r
+"  -o FILE, --output=FILE      output file (only if 1 input file)\n");\r
+ printf(\r
+"  -g NUM, --gap=NUM           scratch memory gap level (1-16)\n");\r
+  printf(\r
+"  -q NUM, --quality=NUM       compression level (%d-%d)\n",\r
+          BROTLI_MIN_QUALITY, BROTLI_MAX_QUALITY);\r
+  printf(\r
+"  -v, --version               display version and exit\n");\r
+}\r
+\r
+static int64_t FileSize(const char* Path) {\r
+  FILE *FileHandle;\r
+  int64_t RetVal;\r
+  FileHandle = fopen(Path, "rb");\r
+\r
+  if (FileHandle == NULL) {\r
+    printf ("Failed to open file [%s]\n", Path);\r
+    return -1;\r
+  }\r
+  if (fseek(FileHandle, 0L, SEEK_END) != 0) {\r
+    printf ("Failed to seek file [%s]\n", Path);\r
+    fclose(FileHandle);\r
+    return -1;\r
+  }\r
+  RetVal = ftell(FileHandle);\r
+  if (fclose(FileHandle) != 0) {\r
+    printf ("Failed to close file [%s]\n", Path);\r
+    return -1;\r
+  }\r
+  return RetVal;\r
+}\r
+\r
+static BROTLI_BOOL HasMoreInput(FILE *FileHandle) {\r
+  return feof(FileHandle) ? BROTLI_FALSE : BROTLI_TRUE;\r
+}\r
+\r
+int OpenFiles(char *InputFile, FILE **InHandle, char *OutputFile, FILE **OutHandle) {\r
+  *InHandle = NULL;\r
+  *OutHandle = NULL;\r
+  *InHandle = fopen(InputFile, "rb");\r
+  if (*InHandle == NULL) {\r
+    printf("Failed to open input file [%s]\n", InputFile);\r
+    return BROTLI_FALSE;\r
+  }\r
+\r
+  *OutHandle = fopen(OutputFile, "wb+");\r
+  if (*OutHandle == NULL) {\r
+    printf("Failed to open output file [%s]\n", OutputFile);\r
+    fclose(*InHandle);\r
+    return BROTLI_FALSE;\r
+  }\r
+  return BROTLI_TRUE;\r
+}\r
+\r
+int CompressFile(char *InputFile, uint8_t *InputBuffer, char *OutputFile, uint8_t *OutputBuffer, int Quality, int Gap) {\r
+  int64_t InputFileSize;\r
+  FILE *InputFileHandle;\r
+  FILE *OutputFileHandle;\r
+  BrotliEncoderState *EncodeState;\r
+  uint32_t LgWin;\r
+  BROTLI_BOOL IsEof;\r
+  size_t AvailableIn;\r
+  const uint8_t *NextIn;\r
+  size_t AvailableOut;\r
+  uint8_t *NextOut;\r
+  uint8_t *Input;\r
+  uint8_t *Output;\r
+  size_t OutSize;\r
+  uint32_t SizeHint;\r
+  BROTLI_BOOL IsOk;\r
+  AvailableIn = 0;\r
+  IsEof = BROTLI_FALSE;\r
+  Input = InputBuffer;\r
+  Output = OutputBuffer;\r
+  IsOk = BROTLI_TRUE;\r
+  LgWin = DEFAULT_LGWIN;\r
+\r
+  InputFileSize = FileSize(InputFile);\r
+\r
+  IsOk = OpenFiles(InputFile, &InputFileHandle, OutputFile, &OutputFileHandle);\r
+  if (!IsOk) {\r
+    return IsOk;\r
+  }\r
+\r
+  fseek (OutputFileHandle, DECODE_HEADER_SIZE, SEEK_SET);\r
+\r
+  EncodeState = BrotliEncoderCreateInstance(NULL, NULL, NULL);\r
+  if (!EncodeState) {\r
+    printf("Out of memory\n");\r
+    IsOk = BROTLI_FALSE;\r
+    goto Finish;\r
+  }\r
+  BrotliEncoderSetParameter(EncodeState, BROTLI_PARAM_QUALITY, (uint32_t)Quality);\r
+\r
+  if (InputFileSize >= 0) {\r
+    LgWin = BROTLI_MIN_WINDOW_BITS;\r
+    while (BROTLI_MAX_BACKWARD_LIMIT(LgWin) < InputFileSize) {\r
+      LgWin++;\r
+      if (LgWin == BROTLI_MAX_WINDOW_BITS) {\r
+        break;\r
+      }\r
+    }\r
+  }\r
+  BrotliEncoderSetParameter(EncodeState, BROTLI_PARAM_LGWIN, LgWin);\r
+  if (InputFileSize > 0) {\r
+    SizeHint = InputFileSize < (1 << 30)? (uint32_t)InputFileSize : (1u << 30);\r
+    BrotliEncoderSetParameter(EncodeState, BROTLI_PARAM_SIZE_HINT, SizeHint);\r
+  }\r
+\r
+  AvailableIn = 0;\r
+  NextIn = NULL;\r
+  AvailableOut = kFileBufferSize;\r
+  NextOut = Output;\r
+  for (;;) {\r
+    if (AvailableIn == 0 && !IsEof) {\r
+      AvailableIn = fread(Input, 1, kFileBufferSize, InputFileHandle);\r
+      NextIn = Input;\r
+      if (ferror(InputFileHandle)) {\r
+        printf("Failed to read input [%s]\n", InputFile);\r
+        IsOk = BROTLI_FALSE;\r
+        goto Finish;\r
+      }\r
+      IsEof = !HasMoreInput(InputFileHandle);\r
+    }\r
+\r
+    if (!BrotliEncoderCompressStream(EncodeState,\r
+      IsEof ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS,\r
+      &AvailableIn, &NextIn, &AvailableOut, &NextOut, NULL)) {\r
+        printf("Failed to compress data [%s]\n", InputFile);\r
+        IsOk = BROTLI_FALSE;\r
+        goto Finish;\r
+    }\r
+    if (AvailableOut == 0) {\r
+      OutSize = (size_t)(NextOut - Output);\r
+      if (OutSize > 0) {\r
+        fwrite(Output, 1, OutSize, OutputFileHandle);\r
+        if (ferror(OutputFileHandle)) {\r
+          printf("Failed to write output [%s]\n", OutputFile);\r
+          IsOk = BROTLI_FALSE;\r
+          goto Finish;\r
+        }\r
+      }\r
+      AvailableOut = kFileBufferSize;\r
+      NextOut = Output;\r
+    }\r
+    if (BrotliEncoderIsFinished(EncodeState)) {\r
+      OutSize = (size_t)(NextOut - Output);\r
+      if (OutSize > 0) {\r
+        fwrite(Output, 1, OutSize, OutputFileHandle);\r
+        if (ferror(OutputFileHandle)) {\r
+          printf("Failed to write output [%s]\n", OutputFile);\r
+          IsOk = BROTLI_FALSE;\r
+          goto Finish;\r
+        }\r
+        AvailableOut = 0;\r
+      }\r
+    }\r
+    if (IsEof) {\r
+      break;\r
+    }\r
+  }\r
+\r
+Finish:\r
+  if (EncodeState) {\r
+    BrotliEncoderDestroyInstance(EncodeState);\r
+  }\r
+  if (InputFileHandle) {\r
+    fclose(InputFileHandle);\r
+  }\r
+  if (OutputFileHandle) {\r
+    fclose(OutputFileHandle);\r
+  }\r
+  return IsOk;\r
+}\r
+\r
+/* Default BrotliAllocFunc */\r
+void* BrotliAllocFunc(void* Opaque, size_t Size) {\r
+  *(size_t *)Opaque = *(size_t *) Opaque + Size;\r
+  return malloc(Size);\r
+}\r
+\r
+/* Default BrotliFreeFunc */\r
+void BrotliFreeFunc(void* Opaque, void* Address) {\r
+  free(Address);\r
+}\r
+\r
+int DecompressFile(char *InputFile, uint8_t *InputBuffer, char *OutputFile, uint8_t *OutputBuffer, int Quality, int Gap) {\r
+  FILE *InputFileHandle;\r
+  FILE *OutputFileHandle;\r
+  BrotliDecoderState *DecoderState;\r
+  BrotliDecoderResult Result;\r
+  size_t AvailableIn;\r
+  const uint8_t *NextIn;\r
+  size_t AvailableOut;\r
+  uint8_t *NextOut;\r
+  uint8_t *Input;\r
+  uint8_t *Output;\r
+  size_t OutSize;\r
+  BROTLI_BOOL IsOk;\r
+  AvailableIn = 0;\r
+  Input = InputBuffer;\r
+  Output = OutputBuffer;\r
+  IsOk = BROTLI_TRUE;\r
+\r
+  IsOk = OpenFiles(InputFile, &InputFileHandle, OutputFile, &OutputFileHandle);\r
+  if (!IsOk) {\r
+        return IsOk;\r
+  }\r
+  fseek(InputFileHandle, DECODE_HEADER_SIZE, SEEK_SET);\r
+\r
+  DecoderState = BrotliDecoderCreateInstance(BrotliAllocFunc, BrotliFreeFunc, &ScratchBufferSize);\r
+  if (!DecoderState) {\r
+    printf("Out of memory\n");\r
+    IsOk = BROTLI_FALSE;\r
+    goto Finish;\r
+  }\r
+  /* This allows decoding "large-window" streams. Though it creates\r
+       fragmentation (new builds decode streams that old builds don't),\r
+       it is better from used experience perspective. */\r
+  BrotliDecoderSetParameter(DecoderState, BROTLI_DECODER_PARAM_LARGE_WINDOW, 1u);\r
+\r
+  AvailableIn = 0;\r
+  NextIn = NULL;\r
+  AvailableOut = kFileBufferSize;\r
+  NextOut = Output;\r
+  Result = BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;\r
+  for (;;) {\r
+    if (Result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {\r
+      if (!HasMoreInput(InputFileHandle)) {\r
+        printf("Corrupt input [%s]\n", InputFile);\r
+        IsOk = BROTLI_FALSE;\r
+        goto Finish;\r
+      }\r
+      AvailableIn = fread(Input, 1, kFileBufferSize, InputFileHandle);\r
+      NextIn = Input;\r
+      if (ferror(InputFileHandle)) {\r
+        printf("Failed to read input [%s]\n", InputFile);\r
+        IsOk = BROTLI_FALSE;\r
+        goto Finish;\r
+      }\r
+    } else if (Result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {\r
+      OutSize = (size_t) (NextOut - Output);\r
+      if (OutSize > 0) {\r
+        fwrite(Output, 1, OutSize, OutputFileHandle);\r
+        if (ferror(OutputFileHandle)) {\r
+          printf("Failed to write output [%s]\n", OutputFile);\r
+          IsOk = BROTLI_FALSE;\r
+          goto Finish;\r
+        }\r
+      }\r
+      AvailableOut = kFileBufferSize;\r
+      NextOut = Output;\r
+    } else if (Result == BROTLI_DECODER_RESULT_SUCCESS) {\r
+      OutSize = (size_t) (NextOut - Output);\r
+      if (OutSize > 0) {\r
+        fwrite(Output, 1, OutSize, OutputFileHandle);\r
+        if (ferror(OutputFileHandle)) {\r
+          printf("Failed to write output [%s]\n", OutputFile);\r
+          IsOk = BROTLI_FALSE;\r
+          goto Finish;\r
+        }\r
+      }\r
+      AvailableOut = 0;\r
+      if (AvailableIn != 0 || HasMoreInput(InputFileHandle)) {\r
+        printf("Corrupt input [%s]\n", InputFile);\r
+        IsOk = BROTLI_FALSE;\r
+        goto Finish;\r
+      }\r
+    } else {\r
+      printf("Corrupt input [%s]\n", InputFile);\r
+      IsOk = BROTLI_FALSE;\r
+      goto Finish;\r
+    }\r
+    if (!HasMoreInput(InputFileHandle) && Result == BROTLI_DECODER_RESULT_SUCCESS ) {\r
+      break;\r
+    }\r
+    Result = BrotliDecoderDecompressStream(DecoderState, &AvailableIn, &NextIn, &AvailableOut, &NextOut, 0);\r
+  }\r
+Finish:\r
+  if (DecoderState) {\r
+    BrotliDecoderDestroyInstance(DecoderState);\r
+  }\r
+  if (InputFileHandle) {\r
+    fclose(InputFileHandle);\r
+  }\r
+  if (OutputFileHandle) {\r
+    fclose(OutputFileHandle);\r
+  }\r
+  return IsOk;\r
+}\r
+\r
+int main(int argc, char** argv) {\r
+  BROTLI_BOOL CompressBool;\r
+  BROTLI_BOOL DecompressBool;\r
+  char *OutputFile;\r
+  char *InputFile;\r
+  char OutputTmpFile[_MAX_PATH];\r
+  FILE *OutputHandle;\r
+  int Quality;\r
+  int Gap;\r
+  int OutputFileLength;\r
+  int InputFileLength;\r
+  int Ret;\r
+  size_t InputFileSize;\r
+  uint8_t *Buffer;\r
+  uint8_t *InputBuffer;\r
+  uint8_t *OutputBuffer;\r
+  int64_t Size;\r
+\r
+  InputFile = NULL;\r
+  OutputFile = NULL;\r
+  CompressBool = BROTLI_FALSE;\r
+  DecompressBool = BROTLI_FALSE;\r
+  //\r
+  //Set default Quality and Gap\r
+  //\r
+  Quality = 9;\r
+  Gap = 1;\r
+  InputFileSize = 0;\r
+  Ret = 0;\r
+\r
+  if (argc < 2) {\r
+    Usage();\r
+    return 1;\r
+  }\r
+  if (strcmp(argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0 ) {\r
+    Usage();\r
+    return 0;\r
+  }\r
+  if (strcmp(argv[1], "-v") == 0 || strcmp (argv[1], "--version") == 0 ) {\r
+    Version();\r
+    return 0;\r
+  }\r
+  while (argc > 1) {\r
+    if (strcmp(argv[1], "-e") == 0 || strcmp(argv[1], "--compress") == 0 ) {\r
+      CompressBool = BROTLI_TRUE;\r
+      if (DecompressBool) {\r
+        printf("Can't use -e/--compress with -d/--decompess on the same time\n");\r
+        return 1;\r
+      }\r
+      argc--;\r
+      argv++;\r
+      continue;\r
+    }\r
+    if (strcmp(argv[1], "-d") == 0 || strcmp(argv[1], "--decompress") == 0 ) {\r
+      DecompressBool = BROTLI_TRUE;\r
+      if (CompressBool) {\r
+        printf("Can't use -e/--compress with -d/--decompess on the same time\n");\r
+        return 1;\r
+      }\r
+      argc--;\r
+      argv++;\r
+      continue;\r
+    }\r
+    if (strcmp(argv[1], "-o") == 0 || strncmp(argv[1], "--output", 8) == 0) {\r
+      if (strcmp(argv[1], "-o") == 0) {\r
+        OutputFileLength = strlen(argv[2]);\r
+        if (OutputFileLength > _MAX_PATH) {\r
+          printf ("The file path %s is too long\n", argv[2]);\r
+          return 1;\r
+        }\r
+        OutputFile = argv[2];\r
+        if (OutputFile == NULL) {\r
+          fprintf(stderr, "Input file can't be null\n");\r
+          return 1;\r
+        }\r
+        argc--;\r
+        argv++;\r
+      } else {\r
+        OutputFileLength = strlen(argv[1] - 9);\r
+        OutputFile = (char *)argv[1] + 9;\r
+      }\r
+      argc--;\r
+      argv++;\r
+      continue;\r
+    }\r
+    if (strcmp(argv[1], "-q") == 0 || strncmp(argv[1], "--quality", 9) == 0) {\r
+      if (strcmp(argv[1], "-q") == 0) {\r
+        Quality = strtol(argv[2], NULL, 16);\r
+        argc--;\r
+        argv++;\r
+      } else {\r
+        Quality = strtol((char *)argv[1] + 10, NULL, 16);\r
+      }\r
+      argc--;\r
+      argv++;\r
+      continue;\r
+    }\r
+    if (strcmp(argv[1], "-g") == 0 || strncmp(argv[1], "--gap", 5) == 0) {\r
+      if (strcmp(argv[1], "-g") == 0) {\r
+        Gap = strtol(argv[2], NULL, 16);\r
+        argc--;\r
+        argv++;\r
+      } else {\r
+        Gap = strtol((char *)argv[1] + 6, NULL, 16);\r
+      }\r
+      argc--;\r
+      argv++;\r
+      continue;\r
+    }\r
+    if (argc > 1) {\r
+      InputFileLength = strlen(argv[1]);\r
+      if (InputFileLength > _MAX_PATH - 1) {\r
+        printf ("The file path %s is too long\n", argv[2]);\r
+        return 1;\r
+      }\r
+      InputFile = argv[1];\r
+      if (InputFile == NULL) {\r
+       printf("Input file can't be null\n");\r
+       return 1;\r
+      }\r
+      argc--;\r
+      argv++;\r
+    }\r
+  }\r
+\r
+  Buffer = (uint8_t*)malloc(kFileBufferSize * 2);\r
+  if (!Buffer) {\r
+    printf("Out of memory\n");\r
+    goto Finish;\r
+  }\r
+  memset(Buffer, 0, kFileBufferSize*2);\r
+  InputBuffer = Buffer;\r
+  OutputBuffer = Buffer + kFileBufferSize;\r
+  if (CompressBool) {\r
+    //\r
+    // Compress file\r
+    //\r
+    Ret = CompressFile(InputFile, InputBuffer, OutputFile, OutputBuffer, Quality, Gap);\r
+    if (!Ret) {\r
+      printf ("Failed to compress file [%s]\n", InputFile);\r
+      goto Finish;\r
+    }\r
+    //\r
+    // Decompress file for get Outputfile size\r
+    //\r
+    strcpy (OutputTmpFile, OutputFile);\r
+    if (strlen(InputFile) + strlen(".tmp") < _MAX_PATH) {\r
+      strcat(OutputTmpFile, ".tmp");\r
+    } else {\r
+      printf ("Output file path is too long[%s]\n", OutputFile);\r
+      Ret = BROTLI_FALSE;\r
+      goto Finish;\r
+    }\r
+    memset(Buffer, 0, kFileBufferSize*2);\r
+    Ret = DecompressFile(OutputFile, InputBuffer, OutputTmpFile, OutputBuffer, Quality, Gap);\r
+    if (!Ret) {\r
+      printf ("Failed to decompress file [%s]\n", OutputFile);\r
+      goto Finish;\r
+    }\r
+    remove (OutputTmpFile);\r
+\r
+    //\r
+    // fill decoder header\r
+    //\r
+    InputFileSize = FileSize(InputFile);\r
+    Size = (int64_t)InputFileSize;\r
+    OutputHandle = fopen(OutputFile, "rb+"); /* open output_path file and add in head info */\r
+    fwrite(&Size, 1, sizeof(int64_t), OutputHandle);\r
+    ScratchBufferSize += Gap * GAP_MEM_BLOCK; /* there is a memory gap between IA32 and X64 environment*/\r
+    ScratchBufferSize += kFileBufferSize * 2;\r
+    Size = (int64_t) ScratchBufferSize;\r
+    fwrite(&Size, 1, sizeof(int64_t), OutputHandle);\r
+    if (fclose(OutputHandle) != 0) {\r
+      printf("Failed to close output file [%s]\n", OutputFile);\r
+      Ret = BROTLI_FALSE;\r
+      goto Finish;\r
+    }\r
+  } else {\r
+    Ret = DecompressFile(InputFile, InputBuffer, OutputFile, OutputBuffer, Quality, Gap);\r
+    if (!Ret) {\r
+      printf ("Failed to decompress file [%s]\n", InputFile);\r
+      goto Finish;\r
+    }\r
+  }\r
+  Finish:\r
+  if (Buffer != NULL) {\r
+    free (Buffer);\r
+  }\r
+  return !Ret;\r
+}\r