• 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   cleanup(ctx);
42   exit(1);
43 }
44 
main(int argc,char ** argv)45 int main(int argc, char** argv) {
46   Context ctx;
47   BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
48   size_t available_in;
49   const uint8_t* next_in;
50   size_t available_out = BUFFER_SIZE;
51   uint8_t* next_out;
52   init(&ctx);
53 
54   ctx.fin = fdopen(STDIN_FILENO, "rb");
55   if (!ctx.fin) fail(&ctx, "can't open input file");
56   ctx.fout = fdopen(STDOUT_FILENO, "wb");
57   if (!ctx.fout) fail(&ctx, "can't open output file");
58   ctx.input_buffer = (uint8_t*)malloc(BUFFER_SIZE);
59   if (!ctx.input_buffer) fail(&ctx, "out of memory / input buffer");
60   ctx.output_buffer = (uint8_t*)malloc(BUFFER_SIZE);
61   if (!ctx.output_buffer) fail(&ctx, "out of memory / output buffer");
62   ctx.decoder = BrotliDecoderCreateInstance(0, 0, 0);
63   if (!ctx.decoder) fail(&ctx, "out of memory / decoder");
64   BrotliDecoderSetParameter(ctx.decoder, BROTLI_DECODER_PARAM_LARGE_WINDOW, 1);
65 
66   next_out = ctx.output_buffer;
67   while (1) {
68     if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
69       if (feof(ctx.fin)) break;
70       available_in = fread(ctx.input_buffer, 1, BUFFER_SIZE, ctx.fin);
71       next_in = ctx.input_buffer;
72       if (ferror(ctx.fin)) break;
73     } else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
74       fwrite(ctx.output_buffer, 1, BUFFER_SIZE, ctx.fout);
75       if (ferror(ctx.fout)) break;
76       available_out = BUFFER_SIZE;
77       next_out = ctx.output_buffer;
78     } else {
79       break;
80     }
81     result = BrotliDecoderDecompressStream(
82         ctx.decoder, &available_in, &next_in, &available_out, &next_out, 0);
83   }
84   if (next_out != ctx.output_buffer) {
85     fwrite(ctx.output_buffer, 1, next_out - ctx.output_buffer, ctx.fout);
86   }
87   if ((result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) || ferror(ctx.fout)) {
88     fail(&ctx, "failed to write output");
89   } else if (result != BROTLI_DECODER_RESULT_SUCCESS) {
90     fail(&ctx, "corrupt input");
91   }
92   cleanup(&ctx);
93   return 0;
94 }
95