Home | History | Annotate | Download | only in research
      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 
     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 
     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 
     39 void fail(Context* ctx, const char* message) {
     40   fprintf(stderr, "%s\n", message);
     41   exit(1);
     42 }
     43 
     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