text: # -*- coding: utf-8 -*-
  import sys
  
  from cffi import FFI
  ffi = FFI()
  
  libraries = ['libbrotli']
  if 'win32' not in str(sys.platform).lower():
      libraries.append('stdc++')
  
  
  ffi.set_source(
      "_brotli",
      """#include <brotli/decode.h>
         #include <brotli/encode.h>
      """,
      libraries=libraries,
      include_dirs=["libbrotli", "libbrotli/include"]
  )
  
  ffi.cdef("""
      /* common/types.h */
      typedef bool BROTLI_BOOL;
      #define BROTLI_TRUE ...
      #define BROTLI_FALSE ...
  
      /* dec/state.h */
      /* Allocating function pointer. Function MUST return 0 in the case of
         failure. Otherwise it MUST return a valid pointer to a memory region of
         at least size length. Neither items nor size are allowed to be 0.
         opaque argument is a pointer provided by client and could be used to
         bind function to specific object (memory pool). */
      typedef void* (*brotli_alloc_func)(void* opaque, size_t size);
  
      /* Deallocating function pointer. Function SHOULD be no-op in the case the
         address is 0. */
      typedef void (*brotli_free_func)(void* opaque, void* address);
  
      /* dec/decode.h */
  
      typedef enum {
        /* Decoding error, e.g. corrupt input or memory allocation problem */
        BROTLI_DECODER_RESULT_ERROR = 0,
        /* Decoding successfully completed */
        BROTLI_DECODER_RESULT_SUCCESS = 1,
        /* Partially done; should be called again with more input */
        BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT = 2,
        /* Partially done; should be called again with more output */
        BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT = 3
      } BrotliDecoderResult;
  
      typedef enum {...} BrotliDecoderErrorCode;
      typedef ... BrotliDecoderState;
  
      /* Creates the instance of BrotliDecoderState and initializes it.
         |alloc_func| and |free_func| MUST be both zero or both non-zero. In the
         case they are both zero, default memory allocators are used. |opaque| is
         passed to |alloc_func| and |free_func| when they are called. */
      BrotliDecoderState* BrotliDecoderCreateInstance(brotli_alloc_func,
                                                      brotli_free_func,
                                                      void *);
  
      /* Deinitializes and frees BrotliDecoderState instance. */
      void BrotliDecoderDestroyInstance(BrotliDecoderState* state);
  
      /* Decompresses the data. Supports partial input and output.
  
         Must be called with an allocated input buffer in |*next_in| and an
         allocated output buffer in |*next_out|. The values |*available_in| and
         |*available_out| must specify the allocated size in |*next_in| and
         |*next_out| respectively.
  
         After each call, |*available_in| will be decremented by the amount of
         input bytes consumed, and the |*next_in| pointer will be incremented by
         that amount. Similarly, |*available_out| will be decremented by the
         amount of output bytes written, and the |*next_out| pointer will be
         incremented by that amount. |total_out|, if it is not a null-pointer,
         will be set to the number of bytes decompressed since the last state
         initialization.
  
         Input is never overconsumed, so |next_in| and |available_in| could be
         passed to the next consumer after decoding is complete. */
      BrotliDecoderResult BrotliDecoderDecompressStream(BrotliDecoderState* s,
                                                        size_t* available_in,
                                                        const uint8_t** next_in,
                                                        size_t* available_out,
                                                        uint8_t** next_out,
                                                        size_t* total_out);
  
      /* Fills the new state with a dictionary for LZ77, warming up the
         ringbuffer, e.g. for custom static dictionaries for data formats.
         Not to be confused with the built-in transformable dictionary of Brotli.
         |size| should be less or equal to 2^24 (16MiB), otherwise the dictionary
         will be ignored. The dictionary must exist in memory until decoding is
         done and is owned by the caller. To use:
          1) Allocate and initialize state with BrotliCreateInstance
          2) Use BrotliSetCustomDictionary
          3) Use BrotliDecompressStream
          4) Clean up and free state with BrotliDestroyState
      */
      void BrotliDecoderSetCustomDictionary(
          BrotliDecoderState* s, size_t size, const uint8_t* dict);
  
      /* Returns true, if decoder has some unconsumed output.
         Otherwise returns false. */
      BROTLI_BOOL BrotliDecoderHasMoreOutput(const BrotliDecoderState* s);
  
      /* Returns true, if decoder has already received some input bytes.
         Otherwise returns false. */
      BROTLI_BOOL BrotliDecoderIsUsed(const BrotliDecoderState* s);
  
      /* Returns true, if decoder is in a state where we reached the end of the
         input and produced all of the output; returns false otherwise. */
      BROTLI_BOOL BrotliDecoderIsFinished(const BrotliDecoderState* s);
  
      /* Returns detailed error code after BrotliDecompressStream returns
         BROTLI_DECODER_RESULT_ERROR. */
      BrotliDecoderErrorCode BrotliDecoderGetErrorCode(
                                                    const BrotliDecoderState* s);
  
      const char* BrotliDecoderErrorString(BrotliDecoderErrorCode c);
  
      /* enc/encode.h */
      typedef ... BrotliEncoderState;
  
      typedef enum BrotliEncoderParameter {
        BROTLI_PARAM_MODE = 0,
        /* Controls the compression-speed vs compression-density tradeoffs. The
           higher the quality, the slower the compression. Range is 0 to 11. */
        BROTLI_PARAM_QUALITY = 1,
        /* Base 2 logarithm of the sliding window size. Range is 10 to 24. */
        BROTLI_PARAM_LGWIN = 2,
        /* Base 2 logarithm of the maximum input block size. Range is 16 to 24.
           If set to 0, the value will be set based on the quality. */
        BROTLI_PARAM_LGBLOCK = 3
      } BrotliEncoderParameter;
  
      typedef enum BrotliEncoderMode {
        /* Default compression mode. The compressor does not know anything in
           advance about the properties of the input. */
        BROTLI_MODE_GENERIC = 0,
        /* Compression mode for UTF-8 format text input. */
        BROTLI_MODE_TEXT = 1,
        /* Compression mode used in WOFF 2.0. */
        BROTLI_MODE_FONT = 2
      } BrotliEncoderMode;
  
      int BROTLI_DEFAULT_QUALITY = 11;
      int BROTLI_DEFAULT_WINDOW = 22;
      #define BROTLI_DEFAULT_MODE ...
  
      typedef enum BrotliEncoderOperation {
        BROTLI_OPERATION_PROCESS = 0,
        /* Request output stream to flush. Performed when input stream is
           depleted and there is enough space in output stream. */
        BROTLI_OPERATION_FLUSH = 1,
        /* Request output stream to finish. Performed when input stream is
           depleted and there is enough space in output stream. */
        BROTLI_OPERATION_FINISH = 2
      } BrotliEncoderOperation;
  
      /* Creates the instance of BrotliEncoderState and initializes it.
         |alloc_func| and |free_func| MUST be both zero or both non-zero. In the
         case they are both zero, default memory allocators are used. |opaque| is
         passed to |alloc_func| and |free_func| when they are called. */
      BrotliEncoderState* BrotliEncoderCreateInstance(brotli_alloc_func,
                                                      brotli_free_func,
                                                      void *);
  
      /* Deinitializes and frees BrotliEncoderState instance. */
      void BrotliEncoderDestroyInstance(BrotliEncoderState* state);
  
      /* Compresses the data in |input_buffer| into |encoded_buffer|, and sets
         |*encoded_size| to the compressed length.
         BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW and BROTLI_DEFAULT_MODE
         should be used as |quality|, |lgwin| and |mode| if there are no specific
         requirements to encoder speed and compression ratio.
         If compression fails, |*encoded_size| is set to 0.
         If BrotliEncoderMaxCompressedSize(|input_size|) is not zero, then
         |*encoded_size| is never set to the bigger value.
         Returns false if there was an error and true otherwise. */
      BROTLI_BOOL BrotliEncoderCompress(int quality,
                                        int lgwin,
                                        BrotliEncoderMode mode,
                                        size_t input_size,
                                        const uint8_t* input_buffer,
                                        size_t* encoded_size,
                                        uint8_t* encoded_buffer);
  
      BROTLI_BOOL BrotliEncoderCompressStream(BrotliEncoderState* s,
                                              BrotliEncoderOperation op,
                                              size_t* available_in,
                                              const uint8_t** next_in,
                                              size_t* available_out,
                                              uint8_t** next_out,
                                              size_t* total_out);
  
      BROTLI_BOOL BrotliEncoderSetParameter(BrotliEncoderState* state,
                                            BrotliEncoderParameter p,
                                            uint32_t value);
  
      /* Fills the new state with a dictionary for LZ77, warming up the
         ringbuffer, e.g. for custom static dictionaries for data formats.
         Not to be confused with the built-in transformable dictionary of Brotli.
         To decode, use BrotliSetCustomDictionary() of the decoder with the same
         dictionary. */
      void BrotliEncoderSetCustomDictionary(BrotliEncoderState* state,
                                            size_t size,
                                            const uint8_t* dict);
  
      /* Check if encoder is in "finished" state, i.e. no more input is
         acceptable and no more output will be produced.
         Works only with BrotliEncoderCompressStream workflow.
         Returns 1 if stream is finished and 0 otherwise. */
      BROTLI_BOOL BrotliEncoderIsFinished(BrotliEncoderState* s);
  
      /* Check if encoder has more output bytes in internal buffer.
         Works only with BrotliEncoderCompressStream workflow.
         Returns 1 if has more output (in internal buffer) and 0 otherwise. */
      BROTLI_BOOL BrotliEncoderHasMoreOutput(BrotliEncoderState* s);
  """)
  
  if __name__ == '__main__':
      ffi.compile()
  