1*f4ee7fbaSAndroid Build Coastguard Worker// Copyright 2016 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// Package cbrotli compresses and decompresses data with C-Brotli library. 7*f4ee7fbaSAndroid Build Coastguard Workerpackage cbrotli 8*f4ee7fbaSAndroid Build Coastguard Worker 9*f4ee7fbaSAndroid Build Coastguard Worker/* 10*f4ee7fbaSAndroid Build Coastguard Worker#include <stddef.h> 11*f4ee7fbaSAndroid Build Coastguard Worker#include <stdint.h> 12*f4ee7fbaSAndroid Build Coastguard Worker 13*f4ee7fbaSAndroid Build Coastguard Worker#include <brotli/decode.h> 14*f4ee7fbaSAndroid Build Coastguard Worker 15*f4ee7fbaSAndroid Build Coastguard Workerstatic BrotliDecoderResult DecompressStream(BrotliDecoderState* s, 16*f4ee7fbaSAndroid Build Coastguard Worker uint8_t* out, size_t out_len, 17*f4ee7fbaSAndroid Build Coastguard Worker const uint8_t* in, size_t in_len, 18*f4ee7fbaSAndroid Build Coastguard Worker size_t* bytes_written, 19*f4ee7fbaSAndroid Build Coastguard Worker size_t* bytes_consumed) { 20*f4ee7fbaSAndroid Build Coastguard Worker size_t in_remaining = in_len; 21*f4ee7fbaSAndroid Build Coastguard Worker size_t out_remaining = out_len; 22*f4ee7fbaSAndroid Build Coastguard Worker BrotliDecoderResult result = BrotliDecoderDecompressStream( 23*f4ee7fbaSAndroid Build Coastguard Worker s, &in_remaining, &in, &out_remaining, &out, NULL); 24*f4ee7fbaSAndroid Build Coastguard Worker *bytes_written = out_len - out_remaining; 25*f4ee7fbaSAndroid Build Coastguard Worker *bytes_consumed = in_len - in_remaining; 26*f4ee7fbaSAndroid Build Coastguard Worker return result; 27*f4ee7fbaSAndroid Build Coastguard Worker} 28*f4ee7fbaSAndroid Build Coastguard Worker*/ 29*f4ee7fbaSAndroid Build Coastguard Workerimport "C" 30*f4ee7fbaSAndroid Build Coastguard Worker 31*f4ee7fbaSAndroid Build Coastguard Workerimport ( 32*f4ee7fbaSAndroid Build Coastguard Worker "bytes" 33*f4ee7fbaSAndroid Build Coastguard Worker "errors" 34*f4ee7fbaSAndroid Build Coastguard Worker "io" 35*f4ee7fbaSAndroid Build Coastguard Worker "io/ioutil" 36*f4ee7fbaSAndroid Build Coastguard Worker) 37*f4ee7fbaSAndroid Build Coastguard Worker 38*f4ee7fbaSAndroid Build Coastguard Workertype decodeError C.BrotliDecoderErrorCode 39*f4ee7fbaSAndroid Build Coastguard Worker 40*f4ee7fbaSAndroid Build Coastguard Workerfunc (err decodeError) Error() string { 41*f4ee7fbaSAndroid Build Coastguard Worker return "cbrotli: " + 42*f4ee7fbaSAndroid Build Coastguard Worker C.GoString(C.BrotliDecoderErrorString(C.BrotliDecoderErrorCode(err))) 43*f4ee7fbaSAndroid Build Coastguard Worker} 44*f4ee7fbaSAndroid Build Coastguard Worker 45*f4ee7fbaSAndroid Build Coastguard Workervar errExcessiveInput = errors.New("cbrotli: excessive input") 46*f4ee7fbaSAndroid Build Coastguard Workervar errInvalidState = errors.New("cbrotli: invalid state") 47*f4ee7fbaSAndroid Build Coastguard Workervar errReaderClosed = errors.New("cbrotli: Reader is closed") 48*f4ee7fbaSAndroid Build Coastguard Worker 49*f4ee7fbaSAndroid Build Coastguard Worker// Reader implements io.ReadCloser by reading Brotli-encoded data from an 50*f4ee7fbaSAndroid Build Coastguard Worker// underlying Reader. 51*f4ee7fbaSAndroid Build Coastguard Workertype Reader struct { 52*f4ee7fbaSAndroid Build Coastguard Worker src io.Reader 53*f4ee7fbaSAndroid Build Coastguard Worker state *C.BrotliDecoderState 54*f4ee7fbaSAndroid Build Coastguard Worker buf []byte // scratch space for reading from src 55*f4ee7fbaSAndroid Build Coastguard Worker in []byte // current chunk to decode; usually aliases buf 56*f4ee7fbaSAndroid Build Coastguard Worker} 57*f4ee7fbaSAndroid Build Coastguard Worker 58*f4ee7fbaSAndroid Build Coastguard Worker// readBufSize is a "good" buffer size that avoids excessive round-trips 59*f4ee7fbaSAndroid Build Coastguard Worker// between C and Go but doesn't waste too much memory on buffering. 60*f4ee7fbaSAndroid Build Coastguard Worker// It is arbitrarily chosen to be equal to the constant used in io.Copy. 61*f4ee7fbaSAndroid Build Coastguard Workerconst readBufSize = 32 * 1024 62*f4ee7fbaSAndroid Build Coastguard Worker 63*f4ee7fbaSAndroid Build Coastguard Worker// NewReader initializes new Reader instance. 64*f4ee7fbaSAndroid Build Coastguard Worker// Close MUST be called to free resources. 65*f4ee7fbaSAndroid Build Coastguard Workerfunc NewReader(src io.Reader) *Reader { 66*f4ee7fbaSAndroid Build Coastguard Worker return &Reader{ 67*f4ee7fbaSAndroid Build Coastguard Worker src: src, 68*f4ee7fbaSAndroid Build Coastguard Worker state: C.BrotliDecoderCreateInstance(nil, nil, nil), 69*f4ee7fbaSAndroid Build Coastguard Worker buf: make([]byte, readBufSize), 70*f4ee7fbaSAndroid Build Coastguard Worker } 71*f4ee7fbaSAndroid Build Coastguard Worker} 72*f4ee7fbaSAndroid Build Coastguard Worker 73*f4ee7fbaSAndroid Build Coastguard Worker// Close implements io.Closer. Close MUST be invoked to free native resources. 74*f4ee7fbaSAndroid Build Coastguard Workerfunc (r *Reader) Close() error { 75*f4ee7fbaSAndroid Build Coastguard Worker if r.state == nil { 76*f4ee7fbaSAndroid Build Coastguard Worker return errReaderClosed 77*f4ee7fbaSAndroid Build Coastguard Worker } 78*f4ee7fbaSAndroid Build Coastguard Worker // Close despite the state; i.e. there might be some unread decoded data. 79*f4ee7fbaSAndroid Build Coastguard Worker C.BrotliDecoderDestroyInstance(r.state) 80*f4ee7fbaSAndroid Build Coastguard Worker r.state = nil 81*f4ee7fbaSAndroid Build Coastguard Worker return nil 82*f4ee7fbaSAndroid Build Coastguard Worker} 83*f4ee7fbaSAndroid Build Coastguard Worker 84*f4ee7fbaSAndroid Build Coastguard Workerfunc (r *Reader) Read(p []byte) (n int, err error) { 85*f4ee7fbaSAndroid Build Coastguard Worker if r.state == nil { 86*f4ee7fbaSAndroid Build Coastguard Worker return 0, errReaderClosed 87*f4ee7fbaSAndroid Build Coastguard Worker } 88*f4ee7fbaSAndroid Build Coastguard Worker if int(C.BrotliDecoderHasMoreOutput(r.state)) == 0 && len(r.in) == 0 { 89*f4ee7fbaSAndroid Build Coastguard Worker m, readErr := r.src.Read(r.buf) 90*f4ee7fbaSAndroid Build Coastguard Worker if m == 0 { 91*f4ee7fbaSAndroid Build Coastguard Worker // If readErr is `nil`, we just proxy underlying stream behavior. 92*f4ee7fbaSAndroid Build Coastguard Worker return 0, readErr 93*f4ee7fbaSAndroid Build Coastguard Worker } 94*f4ee7fbaSAndroid Build Coastguard Worker r.in = r.buf[:m] 95*f4ee7fbaSAndroid Build Coastguard Worker } 96*f4ee7fbaSAndroid Build Coastguard Worker 97*f4ee7fbaSAndroid Build Coastguard Worker if len(p) == 0 { 98*f4ee7fbaSAndroid Build Coastguard Worker return 0, nil 99*f4ee7fbaSAndroid Build Coastguard Worker } 100*f4ee7fbaSAndroid Build Coastguard Worker 101*f4ee7fbaSAndroid Build Coastguard Worker for { 102*f4ee7fbaSAndroid Build Coastguard Worker var written, consumed C.size_t 103*f4ee7fbaSAndroid Build Coastguard Worker var data *C.uint8_t 104*f4ee7fbaSAndroid Build Coastguard Worker if len(r.in) != 0 { 105*f4ee7fbaSAndroid Build Coastguard Worker data = (*C.uint8_t)(&r.in[0]) 106*f4ee7fbaSAndroid Build Coastguard Worker } 107*f4ee7fbaSAndroid Build Coastguard Worker result := C.DecompressStream(r.state, 108*f4ee7fbaSAndroid Build Coastguard Worker (*C.uint8_t)(&p[0]), C.size_t(len(p)), 109*f4ee7fbaSAndroid Build Coastguard Worker data, C.size_t(len(r.in)), 110*f4ee7fbaSAndroid Build Coastguard Worker &written, &consumed) 111*f4ee7fbaSAndroid Build Coastguard Worker r.in = r.in[int(consumed):] 112*f4ee7fbaSAndroid Build Coastguard Worker n = int(written) 113*f4ee7fbaSAndroid Build Coastguard Worker 114*f4ee7fbaSAndroid Build Coastguard Worker switch result { 115*f4ee7fbaSAndroid Build Coastguard Worker case C.BROTLI_DECODER_RESULT_SUCCESS: 116*f4ee7fbaSAndroid Build Coastguard Worker if len(r.in) > 0 { 117*f4ee7fbaSAndroid Build Coastguard Worker return n, errExcessiveInput 118*f4ee7fbaSAndroid Build Coastguard Worker } 119*f4ee7fbaSAndroid Build Coastguard Worker return n, nil 120*f4ee7fbaSAndroid Build Coastguard Worker case C.BROTLI_DECODER_RESULT_ERROR: 121*f4ee7fbaSAndroid Build Coastguard Worker return n, decodeError(C.BrotliDecoderGetErrorCode(r.state)) 122*f4ee7fbaSAndroid Build Coastguard Worker case C.BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT: 123*f4ee7fbaSAndroid Build Coastguard Worker if n == 0 { 124*f4ee7fbaSAndroid Build Coastguard Worker return 0, io.ErrShortBuffer 125*f4ee7fbaSAndroid Build Coastguard Worker } 126*f4ee7fbaSAndroid Build Coastguard Worker return n, nil 127*f4ee7fbaSAndroid Build Coastguard Worker case C.BROTLI_DECODER_NEEDS_MORE_INPUT: 128*f4ee7fbaSAndroid Build Coastguard Worker } 129*f4ee7fbaSAndroid Build Coastguard Worker 130*f4ee7fbaSAndroid Build Coastguard Worker if len(r.in) != 0 { 131*f4ee7fbaSAndroid Build Coastguard Worker return 0, errInvalidState 132*f4ee7fbaSAndroid Build Coastguard Worker } 133*f4ee7fbaSAndroid Build Coastguard Worker 134*f4ee7fbaSAndroid Build Coastguard Worker // Calling r.src.Read may block. Don't block if we have data to return. 135*f4ee7fbaSAndroid Build Coastguard Worker if n > 0 { 136*f4ee7fbaSAndroid Build Coastguard Worker return n, nil 137*f4ee7fbaSAndroid Build Coastguard Worker } 138*f4ee7fbaSAndroid Build Coastguard Worker 139*f4ee7fbaSAndroid Build Coastguard Worker // Top off the buffer. 140*f4ee7fbaSAndroid Build Coastguard Worker encN, err := r.src.Read(r.buf) 141*f4ee7fbaSAndroid Build Coastguard Worker if encN == 0 { 142*f4ee7fbaSAndroid Build Coastguard Worker // Not enough data to complete decoding. 143*f4ee7fbaSAndroid Build Coastguard Worker if err == io.EOF { 144*f4ee7fbaSAndroid Build Coastguard Worker return 0, io.ErrUnexpectedEOF 145*f4ee7fbaSAndroid Build Coastguard Worker } 146*f4ee7fbaSAndroid Build Coastguard Worker return 0, err 147*f4ee7fbaSAndroid Build Coastguard Worker } 148*f4ee7fbaSAndroid Build Coastguard Worker r.in = r.buf[:encN] 149*f4ee7fbaSAndroid Build Coastguard Worker } 150*f4ee7fbaSAndroid Build Coastguard Worker 151*f4ee7fbaSAndroid Build Coastguard Worker return n, nil 152*f4ee7fbaSAndroid Build Coastguard Worker} 153*f4ee7fbaSAndroid Build Coastguard Worker 154*f4ee7fbaSAndroid Build Coastguard Worker// Decode decodes Brotli encoded data. 155*f4ee7fbaSAndroid Build Coastguard Workerfunc Decode(encodedData []byte) ([]byte, error) { 156*f4ee7fbaSAndroid Build Coastguard Worker r := &Reader{ 157*f4ee7fbaSAndroid Build Coastguard Worker src: bytes.NewReader(nil), 158*f4ee7fbaSAndroid Build Coastguard Worker state: C.BrotliDecoderCreateInstance(nil, nil, nil), 159*f4ee7fbaSAndroid Build Coastguard Worker buf: make([]byte, 4), // arbitrarily small but nonzero so that r.src.Read returns io.EOF 160*f4ee7fbaSAndroid Build Coastguard Worker in: encodedData, 161*f4ee7fbaSAndroid Build Coastguard Worker } 162*f4ee7fbaSAndroid Build Coastguard Worker defer r.Close() 163*f4ee7fbaSAndroid Build Coastguard Worker return ioutil.ReadAll(r) 164*f4ee7fbaSAndroid Build Coastguard Worker} 165