brotli_decoder.c 3.0 KB

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