1// Copyright 2016 Google Inc. All Rights Reserved. 2// 3// Distributed under MIT license. 4// See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 5 6// Package decoder wraps the brotli decoder C API used by package brotli. 7package decoder 8 9/* 10#include <brotli/decode.h> 11 12// Wrap BrotliDecoderDecompressStream so that it doesn't take variable (in-out) 13// pointers. Instead of updated pointer, deltas are saved in auxiliary struct. 14 15struct DecompressStreamResult { 16 size_t bytes_consumed; 17 const uint8_t* output_data; 18 size_t output_data_size; 19 BrotliDecoderResult status; 20}; 21 22struct DecompressStreamResult DecompressStream(BrotliDecoderState* s, 23 const uint8_t* encoded_data, size_t encoded_data_size) { 24 struct DecompressStreamResult result; 25 size_t available_in = encoded_data_size; 26 const uint8_t* next_in = encoded_data; 27 size_t available_out = 0; 28 result.status = BrotliDecoderDecompressStream(s, 29 &available_in, &next_in, &available_out, 0, 0); 30 result.bytes_consumed = encoded_data_size - available_in; 31 result.output_data = 0; 32 result.output_data_size = 0; 33 if (result.status != BROTLI_DECODER_RESULT_ERROR) { 34 result.output_data = BrotliDecoderTakeOutput(s, &result.output_data_size); 35 if (BrotliDecoderIsFinished(s)) { 36 result.status = BROTLI_DECODER_RESULT_SUCCESS; 37 } 38 } 39 return result; 40} 41 42*/ 43import "C" 44import ( 45 "unsafe" 46) 47 48// Status represents internal state after DecompressStream invokation 49type Status int 50 51const ( 52 // Error happened 53 Error Status = iota 54 // Done means that no more output will be produced 55 Done 56 // Ok means that more output might be produced with no additional input 57 Ok 58) 59 60// Decoder is the Brotli c-decoder handle. 61type Decoder struct { 62 state *C.BrotliDecoderState 63} 64 65// New returns a new Brotli c-decoder handle. 66// Close MUST be called to free resources. 67func New() Decoder { 68 return Decoder{state: C.BrotliDecoderCreateInstance(nil, nil, nil)} 69} 70 71// Close frees resources used by decoder. 72func (z *Decoder) Close() { 73 C.BrotliDecoderDestroyInstance(z.state) 74 z.state = nil 75} 76 77func goStatus(cStatus C.BrotliDecoderResult) (status Status) { 78 switch cStatus { 79 case C.BROTLI_DECODER_RESULT_SUCCESS: 80 return Done 81 case C.BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT: 82 return Ok 83 case C.BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT: 84 return Ok 85 } 86 return Error 87} 88 89// cBytes casts a Go []byte into a C uint8_t*. We pass &buf[0] directly to C, 90// which is legal because C doesn't save the pointer longer than the call and 91// the byte array itself doesn't contain any pointers. 92func cBytes(buf []byte) (*C.uint8_t, C.size_t) { 93 if len(buf) == 0 { 94 return (*C.uint8_t)(nil), 0 95 } 96 return (*C.uint8_t)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)) 97} 98 99// DecompressStream reads Brotli-encoded bytes from in, and returns produced 100// bytes. Output contents should not be modified. Liveness of output is 101// hard-limited by Decoder liveness; slice becomes invalid when any Decoder 102// method is invoked. 103func (z *Decoder) DecompressStream(in []byte) ( 104 bytesConsumed int, output []byte, status Status) { 105 cin, cinSize := cBytes(in) 106 result := C.DecompressStream(z.state, cin, cinSize) 107 output = C.GoBytes( 108 unsafe.Pointer(result.output_data), C.int(result.output_data_size)) 109 return int(result.bytes_consumed), output, goStatus(result.status) 110} 111