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