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