Edit

kc3-lang/brotli/research/brotli_decoder.c

Branch :

  • Show log

    Commit

  • Author : Evgenii Kliuchnikov
    Date : 2022-11-17 13:03:09
    Hash : a8f5813b
    Message : Update Documentation: - add note that brotli is a "stream" format, not an archive-like - regenerate .1 with Pandoc Build: - drop legacy "BROTLI_BUILD_PORTABLE" option - drop "BROTLI_SANITIZED" definition Code: - c: comb includes - c/enc: extract encoder state into separate header - c/enc: drop designated q10 codepath - c/enc: dealing better with flushing of empty stream - fix MSVC compilation API: - py: use library version instead of one in version.h - c: add plugable API to report consumed input / produced output - c/java: support "lean" prepared dictionaries (without copy of source)

  • research/brotli_decoder.c
  • /* Copyright 2018 Google Inc. All Rights Reserved.
    
       Distributed under MIT license.
       See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    
    #include <brotli/decode.h>
    
    #if !defined(_WIN32)
    #include <unistd.h>
    #else
    #include <io.h>
    #define fdopen _fdopen
    #if !defined(__MINGW32__)
    #define STDIN_FILENO _fileno(stdin)
    #define STDOUT_FILENO _fileno(stdout)
    #endif
    #endif
    
    #define BUFFER_SIZE (1u << 20)
    
    typedef struct Context {
      FILE* fin;
      FILE* fout;
      uint8_t* input_buffer;
      uint8_t* output_buffer;
      BrotliDecoderState* decoder;
    } Context;
    
    void init(Context* ctx) {
      ctx->fin = 0;
      ctx->fout = 0;
      ctx->input_buffer = 0;
      ctx->output_buffer = 0;
      ctx->decoder = 0;
    }
    
    void cleanup(Context* ctx) {
      if (ctx->decoder) BrotliDecoderDestroyInstance(ctx->decoder);
      if (ctx->output_buffer) free(ctx->output_buffer);
      if (ctx->input_buffer) free(ctx->input_buffer);
      if (ctx->fout) fclose(ctx->fout);
      if (ctx->fin) fclose(ctx->fin);
    }
    
    void fail(Context* ctx, const char* message) {
      fprintf(stderr, "%s\n", message);
      cleanup(ctx);
      exit(1);
    }
    
    int main(int argc, char** argv) {
      Context ctx;
      BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
      size_t available_in;
      const uint8_t* next_in;
      size_t available_out = BUFFER_SIZE;
      uint8_t* next_out;
      init(&ctx);
    
      ctx.fin = fdopen(STDIN_FILENO, "rb");
      if (!ctx.fin) fail(&ctx, "can't open input file");
      ctx.fout = fdopen(STDOUT_FILENO, "wb");
      if (!ctx.fout) fail(&ctx, "can't open output file");
      ctx.input_buffer = (uint8_t*)malloc(BUFFER_SIZE);
      if (!ctx.input_buffer) fail(&ctx, "out of memory / input buffer");
      ctx.output_buffer = (uint8_t*)malloc(BUFFER_SIZE);
      if (!ctx.output_buffer) fail(&ctx, "out of memory / output buffer");
      ctx.decoder = BrotliDecoderCreateInstance(0, 0, 0);
      if (!ctx.decoder) fail(&ctx, "out of memory / decoder");
      BrotliDecoderSetParameter(ctx.decoder, BROTLI_DECODER_PARAM_LARGE_WINDOW, 1);
    
      next_out = ctx.output_buffer;
      while (1) {
        if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
          if (feof(ctx.fin)) break;
          available_in = fread(ctx.input_buffer, 1, BUFFER_SIZE, ctx.fin);
          next_in = ctx.input_buffer;
          if (ferror(ctx.fin)) break;
        } else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
          fwrite(ctx.output_buffer, 1, BUFFER_SIZE, ctx.fout);
          if (ferror(ctx.fout)) break;
          available_out = BUFFER_SIZE;
          next_out = ctx.output_buffer;
        } else {
          break;
        }
        result = BrotliDecoderDecompressStream(
            ctx.decoder, &available_in, &next_in, &available_out, &next_out, 0);
      }
      if (next_out != ctx.output_buffer) {
        fwrite(ctx.output_buffer, 1, next_out - ctx.output_buffer, ctx.fout);
      }
      if ((result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) || ferror(ctx.fout)) {
        fail(&ctx, "failed to write output");
      } else if (result != BROTLI_DECODER_RESULT_SUCCESS) {
        fail(&ctx, "corrupt input");
      }
      cleanup(&ctx);
      return 0;
    }