]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/BrotliCompress/BrotliCompress.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / BaseTools / Source / C / BrotliCompress / BrotliCompress.c
CommitLineData
662b42db
YF
1/** @file\r
2 BrotliCompress Compress/Decompress tool (BrotliCompress)\r
3\r
4 Copyright (c) 2020, ByoSoft Corporation. All rights reserved.<BR>\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9/* Command line interface for Brotli library. */\r
10\r
11#include <errno.h>\r
12#include <fcntl.h>\r
13#include <stdio.h>\r
14#include <stdlib.h>\r
15#include <string.h>\r
16#include <sys/stat.h>\r
17#include <sys/types.h>\r
18#include <time.h>\r
19\r
20#include "./brotli/c/common/constants.h"\r
21#include "./brotli/c/common/version.h"\r
22#include <brotli/decode.h>\r
23#include <brotli/encode.h>\r
24\r
25#if !defined(_WIN32)\r
26#include <unistd.h>\r
27#include <utime.h>\r
28#else\r
29#include <io.h>\r
30#include <share.h>\r
31#include <sys/utime.h>\r
32\r
33#if !defined(__MINGW32__)\r
34#define STDIN_FILENO _fileno(stdin)\r
35#define STDOUT_FILENO _fileno(stdout)\r
36#define S_IRUSR S_IREAD\r
37#define S_IWUSR S_IWRITE\r
38#endif\r
39\r
40#define fopen ms_fopen\r
41#define open ms_open\r
42\r
43#if defined(_MSC_VER) && (_MSC_VER >= 1400)\r
44#define fseek _fseeki64\r
45#define ftell _ftelli64\r
46#endif\r
47\r
48static FILE* ms_fopen(const char* FileName, const char* Mode) {\r
49 FILE* Result;\r
50 Result = NULL;\r
51 fopen_s(&Result, FileName, Mode);\r
52 return Result;\r
53}\r
54\r
55static int ms_open(const char* FileName, int Oflag, int Pmode) {\r
56 int Result;\r
57 Result = -1;\r
58 _sopen_s(&Result, FileName, Oflag | O_BINARY, _SH_DENYNO, Pmode);\r
59 return Result;\r
60}\r
61#endif /* WIN32 */\r
62\r
63\r
64#ifndef _MAX_PATH\r
65#define _MAX_PATH 500\r
66#endif\r
67\r
68#define DEFAULT_LGWIN 22\r
69#define DECODE_HEADER_SIZE 0x10\r
70#define GAP_MEM_BLOCK 0x1000\r
71size_t ScratchBufferSize = 0;\r
72static const size_t kFileBufferSize = 1 << 19;\r
73\r
74static void Version(void) {\r
75 int Major;\r
76 int Minor;\r
77 int Patch;\r
78 Major = BROTLI_VERSION >> 24;\r
79 Minor = (BROTLI_VERSION >> 12) & 0xFFF;\r
80 Patch = BROTLI_VERSION & 0xFFF;\r
81 printf("BrotliCompress %d.%d.%d\n", Major, Minor, Patch);\r
82}\r
83\r
84static void Usage() {\r
85 printf("Usage: %s [OPTION]... [FILE]...\n", __FILE__);\r
86 printf(\r
87"Options:\n"\r
88" -e, --compress compress\n"\r
89" -d, --decompress decompress\n"\r
90" -h, --help display this help and exit\n");\r
91 printf(\r
92" -o FILE, --output=FILE output file (only if 1 input file)\n");\r
93 printf(\r
94" -g NUM, --gap=NUM scratch memory gap level (1-16)\n");\r
95 printf(\r
96" -q NUM, --quality=NUM compression level (%d-%d)\n",\r
97 BROTLI_MIN_QUALITY, BROTLI_MAX_QUALITY);\r
98 printf(\r
99" -v, --version display version and exit\n");\r
100}\r
101\r
102static int64_t FileSize(const char* Path) {\r
103 FILE *FileHandle;\r
104 int64_t RetVal;\r
105 FileHandle = fopen(Path, "rb");\r
106\r
107 if (FileHandle == NULL) {\r
108 printf ("Failed to open file [%s]\n", Path);\r
109 return -1;\r
110 }\r
111 if (fseek(FileHandle, 0L, SEEK_END) != 0) {\r
112 printf ("Failed to seek file [%s]\n", Path);\r
113 fclose(FileHandle);\r
114 return -1;\r
115 }\r
116 RetVal = ftell(FileHandle);\r
117 if (fclose(FileHandle) != 0) {\r
118 printf ("Failed to close file [%s]\n", Path);\r
119 return -1;\r
120 }\r
121 return RetVal;\r
122}\r
123\r
124static BROTLI_BOOL HasMoreInput(FILE *FileHandle) {\r
125 return feof(FileHandle) ? BROTLI_FALSE : BROTLI_TRUE;\r
126}\r
127\r
128int OpenFiles(char *InputFile, FILE **InHandle, char *OutputFile, FILE **OutHandle) {\r
129 *InHandle = NULL;\r
130 *OutHandle = NULL;\r
131 *InHandle = fopen(InputFile, "rb");\r
132 if (*InHandle == NULL) {\r
133 printf("Failed to open input file [%s]\n", InputFile);\r
134 return BROTLI_FALSE;\r
135 }\r
136\r
137 *OutHandle = fopen(OutputFile, "wb+");\r
138 if (*OutHandle == NULL) {\r
139 printf("Failed to open output file [%s]\n", OutputFile);\r
140 fclose(*InHandle);\r
141 return BROTLI_FALSE;\r
142 }\r
143 return BROTLI_TRUE;\r
144}\r
145\r
146int CompressFile(char *InputFile, uint8_t *InputBuffer, char *OutputFile, uint8_t *OutputBuffer, int Quality, int Gap) {\r
147 int64_t InputFileSize;\r
148 FILE *InputFileHandle;\r
149 FILE *OutputFileHandle;\r
150 BrotliEncoderState *EncodeState;\r
151 uint32_t LgWin;\r
152 BROTLI_BOOL IsEof;\r
153 size_t AvailableIn;\r
154 const uint8_t *NextIn;\r
155 size_t AvailableOut;\r
156 uint8_t *NextOut;\r
157 uint8_t *Input;\r
158 uint8_t *Output;\r
9cd854e1 159 size_t TotalOut;\r
662b42db
YF
160 size_t OutSize;\r
161 uint32_t SizeHint;\r
162 BROTLI_BOOL IsOk;\r
163 AvailableIn = 0;\r
164 IsEof = BROTLI_FALSE;\r
165 Input = InputBuffer;\r
166 Output = OutputBuffer;\r
167 IsOk = BROTLI_TRUE;\r
168 LgWin = DEFAULT_LGWIN;\r
169\r
170 InputFileSize = FileSize(InputFile);\r
171\r
172 IsOk = OpenFiles(InputFile, &InputFileHandle, OutputFile, &OutputFileHandle);\r
173 if (!IsOk) {\r
174 return IsOk;\r
175 }\r
176\r
177 fseek (OutputFileHandle, DECODE_HEADER_SIZE, SEEK_SET);\r
178\r
179 EncodeState = BrotliEncoderCreateInstance(NULL, NULL, NULL);\r
180 if (!EncodeState) {\r
181 printf("Out of memory\n");\r
182 IsOk = BROTLI_FALSE;\r
183 goto Finish;\r
184 }\r
185 BrotliEncoderSetParameter(EncodeState, BROTLI_PARAM_QUALITY, (uint32_t)Quality);\r
186\r
187 if (InputFileSize >= 0) {\r
188 LgWin = BROTLI_MIN_WINDOW_BITS;\r
189 while (BROTLI_MAX_BACKWARD_LIMIT(LgWin) < InputFileSize) {\r
190 LgWin++;\r
191 if (LgWin == BROTLI_MAX_WINDOW_BITS) {\r
192 break;\r
193 }\r
194 }\r
195 }\r
196 BrotliEncoderSetParameter(EncodeState, BROTLI_PARAM_LGWIN, LgWin);\r
197 if (InputFileSize > 0) {\r
198 SizeHint = InputFileSize < (1 << 30)? (uint32_t)InputFileSize : (1u << 30);\r
199 BrotliEncoderSetParameter(EncodeState, BROTLI_PARAM_SIZE_HINT, SizeHint);\r
200 }\r
201\r
202 AvailableIn = 0;\r
203 NextIn = NULL;\r
204 AvailableOut = kFileBufferSize;\r
205 NextOut = Output;\r
206 for (;;) {\r
207 if (AvailableIn == 0 && !IsEof) {\r
208 AvailableIn = fread(Input, 1, kFileBufferSize, InputFileHandle);\r
209 NextIn = Input;\r
210 if (ferror(InputFileHandle)) {\r
211 printf("Failed to read input [%s]\n", InputFile);\r
212 IsOk = BROTLI_FALSE;\r
213 goto Finish;\r
214 }\r
215 IsEof = !HasMoreInput(InputFileHandle);\r
216 }\r
217\r
9cd854e1
CC
218 if (!IsEof){\r
219 do{\r
220 if (!BrotliEncoderCompressStream(EncodeState,\r
221 BROTLI_OPERATION_FLUSH,\r
222 &AvailableIn, &NextIn, &AvailableOut, &NextOut, &TotalOut)) {\r
223 printf("Failed to compress data [%s]\n", InputFile);\r
662b42db
YF
224 IsOk = BROTLI_FALSE;\r
225 goto Finish;\r
226 }\r
9cd854e1
CC
227 OutSize = (size_t)(NextOut - Output);\r
228 if (OutSize > 0) {\r
229 fwrite(Output, 1, OutSize, OutputFileHandle);\r
230 if (ferror(OutputFileHandle)) {\r
231 printf("Failed to write output [%s]\n", OutputFile);\r
232 IsOk = BROTLI_FALSE;\r
233 goto Finish;\r
234 }\r
235 }\r
236 NextOut = Output;\r
237 AvailableOut = kFileBufferSize;\r
662b42db 238 }\r
9cd854e1 239 while (AvailableIn > 0 || BrotliEncoderHasMoreOutput(EncodeState));\r
662b42db 240 }\r
9cd854e1
CC
241 else{\r
242 do{\r
243 if (!BrotliEncoderCompressStream(EncodeState,\r
244 BROTLI_OPERATION_FINISH,\r
245 &AvailableIn, &NextIn, &AvailableOut, &NextOut, &TotalOut)) {\r
246 printf("Failed to compress data [%s]\n", InputFile);\r
662b42db
YF
247 IsOk = BROTLI_FALSE;\r
248 goto Finish;\r
249 }\r
9cd854e1
CC
250 OutSize = (size_t)(NextOut - Output);\r
251 if (OutSize > 0) {\r
252 fwrite(Output, 1, OutSize, OutputFileHandle);\r
253 if (ferror(OutputFileHandle)) {\r
254 printf("Failed to write output [%s]\n", OutputFile);\r
255 IsOk = BROTLI_FALSE;\r
256 goto Finish;\r
257 }\r
258 }\r
259 NextOut = Output;\r
260 AvailableOut = kFileBufferSize;\r
662b42db 261 }\r
9cd854e1 262 while (AvailableIn > 0 || BrotliEncoderHasMoreOutput(EncodeState));\r
662b42db 263 }\r
9cd854e1 264 if (BrotliEncoderIsFinished(EncodeState)){\r
662b42db
YF
265 break;\r
266 }\r
267 }\r
268\r
269Finish:\r
270 if (EncodeState) {\r
271 BrotliEncoderDestroyInstance(EncodeState);\r
272 }\r
273 if (InputFileHandle) {\r
274 fclose(InputFileHandle);\r
275 }\r
276 if (OutputFileHandle) {\r
277 fclose(OutputFileHandle);\r
278 }\r
279 return IsOk;\r
280}\r
281\r
282/* Default BrotliAllocFunc */\r
283void* BrotliAllocFunc(void* Opaque, size_t Size) {\r
284 *(size_t *)Opaque = *(size_t *) Opaque + Size;\r
285 return malloc(Size);\r
286}\r
287\r
288/* Default BrotliFreeFunc */\r
289void BrotliFreeFunc(void* Opaque, void* Address) {\r
290 free(Address);\r
291}\r
292\r
293int DecompressFile(char *InputFile, uint8_t *InputBuffer, char *OutputFile, uint8_t *OutputBuffer, int Quality, int Gap) {\r
294 FILE *InputFileHandle;\r
295 FILE *OutputFileHandle;\r
296 BrotliDecoderState *DecoderState;\r
297 BrotliDecoderResult Result;\r
298 size_t AvailableIn;\r
299 const uint8_t *NextIn;\r
300 size_t AvailableOut;\r
301 uint8_t *NextOut;\r
302 uint8_t *Input;\r
303 uint8_t *Output;\r
304 size_t OutSize;\r
305 BROTLI_BOOL IsOk;\r
306 AvailableIn = 0;\r
307 Input = InputBuffer;\r
308 Output = OutputBuffer;\r
309 IsOk = BROTLI_TRUE;\r
310\r
311 IsOk = OpenFiles(InputFile, &InputFileHandle, OutputFile, &OutputFileHandle);\r
312 if (!IsOk) {\r
313 return IsOk;\r
314 }\r
315 fseek(InputFileHandle, DECODE_HEADER_SIZE, SEEK_SET);\r
316\r
317 DecoderState = BrotliDecoderCreateInstance(BrotliAllocFunc, BrotliFreeFunc, &ScratchBufferSize);\r
318 if (!DecoderState) {\r
319 printf("Out of memory\n");\r
320 IsOk = BROTLI_FALSE;\r
321 goto Finish;\r
322 }\r
323 /* This allows decoding "large-window" streams. Though it creates\r
324 fragmentation (new builds decode streams that old builds don't),\r
325 it is better from used experience perspective. */\r
326 BrotliDecoderSetParameter(DecoderState, BROTLI_DECODER_PARAM_LARGE_WINDOW, 1u);\r
327\r
328 AvailableIn = 0;\r
329 NextIn = NULL;\r
330 AvailableOut = kFileBufferSize;\r
331 NextOut = Output;\r
332 Result = BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;\r
333 for (;;) {\r
334 if (Result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {\r
335 if (!HasMoreInput(InputFileHandle)) {\r
336 printf("Corrupt input [%s]\n", InputFile);\r
337 IsOk = BROTLI_FALSE;\r
338 goto Finish;\r
339 }\r
340 AvailableIn = fread(Input, 1, kFileBufferSize, InputFileHandle);\r
341 NextIn = Input;\r
342 if (ferror(InputFileHandle)) {\r
343 printf("Failed to read input [%s]\n", InputFile);\r
344 IsOk = BROTLI_FALSE;\r
345 goto Finish;\r
346 }\r
347 } else if (Result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {\r
348 OutSize = (size_t) (NextOut - Output);\r
349 if (OutSize > 0) {\r
350 fwrite(Output, 1, OutSize, OutputFileHandle);\r
351 if (ferror(OutputFileHandle)) {\r
352 printf("Failed to write output [%s]\n", OutputFile);\r
353 IsOk = BROTLI_FALSE;\r
354 goto Finish;\r
355 }\r
356 }\r
357 AvailableOut = kFileBufferSize;\r
358 NextOut = Output;\r
359 } else if (Result == BROTLI_DECODER_RESULT_SUCCESS) {\r
360 OutSize = (size_t) (NextOut - Output);\r
361 if (OutSize > 0) {\r
362 fwrite(Output, 1, OutSize, OutputFileHandle);\r
363 if (ferror(OutputFileHandle)) {\r
364 printf("Failed to write output [%s]\n", OutputFile);\r
365 IsOk = BROTLI_FALSE;\r
366 goto Finish;\r
367 }\r
368 }\r
369 AvailableOut = 0;\r
370 if (AvailableIn != 0 || HasMoreInput(InputFileHandle)) {\r
371 printf("Corrupt input [%s]\n", InputFile);\r
372 IsOk = BROTLI_FALSE;\r
373 goto Finish;\r
374 }\r
375 } else {\r
376 printf("Corrupt input [%s]\n", InputFile);\r
377 IsOk = BROTLI_FALSE;\r
378 goto Finish;\r
379 }\r
380 if (!HasMoreInput(InputFileHandle) && Result == BROTLI_DECODER_RESULT_SUCCESS ) {\r
381 break;\r
382 }\r
383 Result = BrotliDecoderDecompressStream(DecoderState, &AvailableIn, &NextIn, &AvailableOut, &NextOut, 0);\r
384 }\r
385Finish:\r
386 if (DecoderState) {\r
387 BrotliDecoderDestroyInstance(DecoderState);\r
388 }\r
389 if (InputFileHandle) {\r
390 fclose(InputFileHandle);\r
391 }\r
392 if (OutputFileHandle) {\r
393 fclose(OutputFileHandle);\r
394 }\r
395 return IsOk;\r
396}\r
397\r
398int main(int argc, char** argv) {\r
399 BROTLI_BOOL CompressBool;\r
400 BROTLI_BOOL DecompressBool;\r
401 char *OutputFile;\r
402 char *InputFile;\r
403 char OutputTmpFile[_MAX_PATH];\r
404 FILE *OutputHandle;\r
405 int Quality;\r
406 int Gap;\r
407 int OutputFileLength;\r
408 int InputFileLength;\r
409 int Ret;\r
410 size_t InputFileSize;\r
411 uint8_t *Buffer;\r
412 uint8_t *InputBuffer;\r
413 uint8_t *OutputBuffer;\r
414 int64_t Size;\r
415\r
416 InputFile = NULL;\r
417 OutputFile = NULL;\r
418 CompressBool = BROTLI_FALSE;\r
419 DecompressBool = BROTLI_FALSE;\r
420 //\r
421 //Set default Quality and Gap\r
422 //\r
423 Quality = 9;\r
424 Gap = 1;\r
425 InputFileSize = 0;\r
426 Ret = 0;\r
427\r
428 if (argc < 2) {\r
429 Usage();\r
430 return 1;\r
431 }\r
432 if (strcmp(argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0 ) {\r
433 Usage();\r
434 return 0;\r
435 }\r
436 if (strcmp(argv[1], "-v") == 0 || strcmp (argv[1], "--version") == 0 ) {\r
437 Version();\r
438 return 0;\r
439 }\r
440 while (argc > 1) {\r
441 if (strcmp(argv[1], "-e") == 0 || strcmp(argv[1], "--compress") == 0 ) {\r
442 CompressBool = BROTLI_TRUE;\r
443 if (DecompressBool) {\r
444 printf("Can't use -e/--compress with -d/--decompess on the same time\n");\r
445 return 1;\r
446 }\r
447 argc--;\r
448 argv++;\r
449 continue;\r
450 }\r
451 if (strcmp(argv[1], "-d") == 0 || strcmp(argv[1], "--decompress") == 0 ) {\r
452 DecompressBool = BROTLI_TRUE;\r
453 if (CompressBool) {\r
454 printf("Can't use -e/--compress with -d/--decompess on the same time\n");\r
455 return 1;\r
456 }\r
457 argc--;\r
458 argv++;\r
459 continue;\r
460 }\r
461 if (strcmp(argv[1], "-o") == 0 || strncmp(argv[1], "--output", 8) == 0) {\r
462 if (strcmp(argv[1], "-o") == 0) {\r
463 OutputFileLength = strlen(argv[2]);\r
464 if (OutputFileLength > _MAX_PATH) {\r
465 printf ("The file path %s is too long\n", argv[2]);\r
466 return 1;\r
467 }\r
468 OutputFile = argv[2];\r
469 if (OutputFile == NULL) {\r
470 fprintf(stderr, "Input file can't be null\n");\r
471 return 1;\r
472 }\r
473 argc--;\r
474 argv++;\r
475 } else {\r
476 OutputFileLength = strlen(argv[1] - 9);\r
477 OutputFile = (char *)argv[1] + 9;\r
478 }\r
479 argc--;\r
480 argv++;\r
481 continue;\r
482 }\r
483 if (strcmp(argv[1], "-q") == 0 || strncmp(argv[1], "--quality", 9) == 0) {\r
484 if (strcmp(argv[1], "-q") == 0) {\r
485 Quality = strtol(argv[2], NULL, 16);\r
486 argc--;\r
487 argv++;\r
488 } else {\r
489 Quality = strtol((char *)argv[1] + 10, NULL, 16);\r
490 }\r
491 argc--;\r
492 argv++;\r
493 continue;\r
494 }\r
495 if (strcmp(argv[1], "-g") == 0 || strncmp(argv[1], "--gap", 5) == 0) {\r
496 if (strcmp(argv[1], "-g") == 0) {\r
497 Gap = strtol(argv[2], NULL, 16);\r
498 argc--;\r
499 argv++;\r
500 } else {\r
501 Gap = strtol((char *)argv[1] + 6, NULL, 16);\r
502 }\r
503 argc--;\r
504 argv++;\r
505 continue;\r
506 }\r
507 if (argc > 1) {\r
508 InputFileLength = strlen(argv[1]);\r
509 if (InputFileLength > _MAX_PATH - 1) {\r
510 printf ("The file path %s is too long\n", argv[2]);\r
511 return 1;\r
512 }\r
513 InputFile = argv[1];\r
514 if (InputFile == NULL) {\r
515 printf("Input file can't be null\n");\r
516 return 1;\r
517 }\r
518 argc--;\r
519 argv++;\r
520 }\r
521 }\r
522\r
523 Buffer = (uint8_t*)malloc(kFileBufferSize * 2);\r
524 if (!Buffer) {\r
525 printf("Out of memory\n");\r
526 goto Finish;\r
527 }\r
528 memset(Buffer, 0, kFileBufferSize*2);\r
529 InputBuffer = Buffer;\r
530 OutputBuffer = Buffer + kFileBufferSize;\r
531 if (CompressBool) {\r
532 //\r
533 // Compress file\r
534 //\r
535 Ret = CompressFile(InputFile, InputBuffer, OutputFile, OutputBuffer, Quality, Gap);\r
536 if (!Ret) {\r
537 printf ("Failed to compress file [%s]\n", InputFile);\r
538 goto Finish;\r
539 }\r
540 //\r
541 // Decompress file for get Outputfile size\r
542 //\r
543 strcpy (OutputTmpFile, OutputFile);\r
544 if (strlen(InputFile) + strlen(".tmp") < _MAX_PATH) {\r
545 strcat(OutputTmpFile, ".tmp");\r
546 } else {\r
547 printf ("Output file path is too long[%s]\n", OutputFile);\r
548 Ret = BROTLI_FALSE;\r
549 goto Finish;\r
550 }\r
551 memset(Buffer, 0, kFileBufferSize*2);\r
552 Ret = DecompressFile(OutputFile, InputBuffer, OutputTmpFile, OutputBuffer, Quality, Gap);\r
553 if (!Ret) {\r
554 printf ("Failed to decompress file [%s]\n", OutputFile);\r
555 goto Finish;\r
556 }\r
557 remove (OutputTmpFile);\r
558\r
559 //\r
560 // fill decoder header\r
561 //\r
562 InputFileSize = FileSize(InputFile);\r
563 Size = (int64_t)InputFileSize;\r
564 OutputHandle = fopen(OutputFile, "rb+"); /* open output_path file and add in head info */\r
565 fwrite(&Size, 1, sizeof(int64_t), OutputHandle);\r
566 ScratchBufferSize += Gap * GAP_MEM_BLOCK; /* there is a memory gap between IA32 and X64 environment*/\r
567 ScratchBufferSize += kFileBufferSize * 2;\r
568 Size = (int64_t) ScratchBufferSize;\r
569 fwrite(&Size, 1, sizeof(int64_t), OutputHandle);\r
570 if (fclose(OutputHandle) != 0) {\r
571 printf("Failed to close output file [%s]\n", OutputFile);\r
572 Ret = BROTLI_FALSE;\r
573 goto Finish;\r
574 }\r
575 } else {\r
576 Ret = DecompressFile(InputFile, InputBuffer, OutputFile, OutputBuffer, Quality, Gap);\r
577 if (!Ret) {\r
578 printf ("Failed to decompress file [%s]\n", InputFile);\r
579 goto Finish;\r
580 }\r
581 }\r
582 Finish:\r
583 if (Buffer != NULL) {\r
584 free (Buffer);\r
585 }\r
586 return !Ret;\r
587}\r