xref: /aosp_15_r20/external/brotli/research/brotli_decoder.c (revision f4ee7fba7774faf2a30f13154332c0a06550dbc4)
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