1 /* Copyright 2017 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 7 package org.brotli.wrapper.enc; 8 9 import java.io.IOException; 10 import java.io.OutputStream; 11 import java.nio.channels.Channels; 12 13 /** 14 * Output stream that wraps native brotli encoder. 15 */ 16 public class BrotliOutputStream extends OutputStream { 17 /** The default internal buffer size used by the encoder. */ 18 private static final int DEFAULT_BUFFER_SIZE = 16384; 19 20 private final Encoder encoder; 21 22 /** 23 * Creates a BrotliOutputStream. 24 * 25 * @param destination underlying destination 26 * @param params encoding settings 27 * @param bufferSize intermediate buffer size 28 */ 29 public BrotliOutputStream(OutputStream destination, Encoder.Parameters params, int bufferSize) 30 throws IOException { 31 this.encoder = new Encoder(Channels.newChannel(destination), params, bufferSize); 32 } 33 34 public BrotliOutputStream(OutputStream destination, Encoder.Parameters params) 35 throws IOException { 36 this(destination, params, DEFAULT_BUFFER_SIZE); 37 } 38 39 public BrotliOutputStream(OutputStream destination) throws IOException { 40 this(destination, new Encoder.Parameters()); 41 } 42 43 @Override 44 public void close() throws IOException { 45 encoder.close(); 46 } 47 48 @Override 49 public void flush() throws IOException { 50 if (encoder.closed) { 51 throw new IOException("write after close"); 52 } 53 encoder.flush(); 54 } 55 56 @Override 57 public void write(int b) throws IOException { 58 if (encoder.closed) { 59 throw new IOException("write after close"); 60 } 61 while (!encoder.encode(EncoderJNI.Operation.PROCESS)) { 62 // Busy-wait loop. 63 } 64 encoder.inputBuffer.put((byte) b); 65 } 66 67 @Override 68 public void write(byte[] b) throws IOException { 69 this.write(b, 0, b.length); 70 } 71 72 @Override 73 public void write(byte[] b, int off, int len) throws IOException { 74 if (encoder.closed) { 75 throw new IOException("write after close"); 76 } 77 while (len > 0) { 78 if (!encoder.encode(EncoderJNI.Operation.PROCESS)) { 79 continue; 80 } 81 int limit = Math.min(len, encoder.inputBuffer.remaining()); 82 encoder.inputBuffer.put(b, off, limit); 83 off += limit; 84 len -= limit; 85 } 86 } 87 } 88