• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2018 Google Inc. All Rights Reserved.
2 
3    Distributed under MIT license.
4    See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
5 */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 
11 #include <brotli/decode.h>
12 
13 #define BUFFER_SIZE (1u << 20)
14 
15 typedef struct Context {
16   FILE* fin;
17   FILE* fout;
18   uint8_t* input_buffer;
19   uint8_t* output_buffer;
20   BrotliDecoderState* decoder;
21 } Context;
22 
init(Context * ctx)23 void init(Context* ctx) {
24   ctx->fin = 0;
25   ctx->fout = 0;
26   ctx->input_buffer = 0;
27   ctx->output_buffer = 0;
28   ctx->decoder = 0;
29 }
30 
cleanup(Context * ctx)31 void cleanup(Context* ctx) {
32   if (ctx->decoder) BrotliDecoderDestroyInstance(ctx->decoder);
33   if (ctx->output_buffer) free(ctx->output_buffer);
34   if (ctx->input_buffer) free(ctx->input_buffer);
35   if (ctx->fout) fclose(ctx->fout);
36   if (ctx->fin) fclose(ctx->fin);
37 }
38 
fail(Context * ctx,const char * message)39 void fail(Context* ctx, const char* message) {
40   fprintf(stderr, "%s\n", message);
41   exit(1);
42 }
43 
main(int argc,char ** argv)44 int main(int argc, char** argv) {
45   Context ctx;
46   BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
47   size_t available_in;
48   const uint8_t* next_in;
49   size_t available_out = BUFFER_SIZE;
50   uint8_t* next_out;
51   init(&ctx);
52 
53   ctx.fin = fdopen(STDIN_FILENO, "rb");
54   if (!ctx.fin) fail(&ctx, "can't open input file");
55   ctx.fout = fdopen(STDOUT_FILENO, "wb");
56   if (!ctx.fout) fail(&ctx, "can't open output file");
57   ctx.input_buffer = (uint8_t*)malloc(BUFFER_SIZE);
58   if (!ctx.input_buffer) fail(&ctx, "out of memory / input buffer");
59   ctx.output_buffer = (uint8_t*)malloc(BUFFER_SIZE);
60   if (!ctx.output_buffer) fail(&ctx, "out of memory / output buffer");
61   ctx.decoder = BrotliDecoderCreateInstance(0, 0, 0);
62   if (!ctx.decoder) fail(&ctx, "out of memory / decoder");
63   BrotliDecoderSetParameter(ctx.decoder, BROTLI_DECODER_PARAM_LARGE_WINDOW, 1);
64 
65   next_out = ctx.output_buffer;
66   while (1) {
67     if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
68       if (feof(ctx.fin)) break;
69       available_in = fread(ctx.input_buffer, 1, BUFFER_SIZE, ctx.fin);
70       next_in = ctx.input_buffer;
71       if (ferror(ctx.fin)) break;
72     } else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
73       fwrite(ctx.output_buffer, 1, BUFFER_SIZE, ctx.fout);
74       if (ferror(ctx.fout)) break;
75       available_out = BUFFER_SIZE;
76       next_out = ctx.output_buffer;
77     } else {
78       break;
79     }
80     result = BrotliDecoderDecompressStream(
81         ctx.decoder, &available_in, &next_in, &available_out, &next_out, 0);
82   }
83   if (next_out != ctx.output_buffer) {
84     fwrite(ctx.output_buffer, 1, next_out - ctx.output_buffer, ctx.fout);
85   }
86   if ((result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) || ferror(ctx.fout)) {
87     fail(&ctx, "failed to write output");
88   } else if (result != BROTLI_DECODER_RESULT_SUCCESS) {
89     fail(&ctx, "corrupt input");
90   }
91   cleanup(&ctx);
92   return 0;
93 }
94