1 /* 2 * UncompressedLZMA2OutputStream 3 * 4 * Author: Lasse Collin <lasse.collin (at) tukaani.org> 5 * 6 * This file has been put into the public domain. 7 * You can do whatever you want with this file. 8 */ 9 10 package org.tukaani.xz; 11 12 import java.io.DataOutputStream; 13 import java.io.IOException; 14 15 class UncompressedLZMA2OutputStream extends FinishableOutputStream { 16 private FinishableOutputStream out; 17 private final DataOutputStream outData; 18 19 private final byte[] uncompBuf 20 = new byte[LZMA2OutputStream.COMPRESSED_SIZE_MAX]; 21 private int uncompPos = 0; 22 private boolean dictResetNeeded = true; 23 24 private boolean finished = false; 25 private IOException exception = null; 26 27 private final byte[] tempBuf = new byte[1]; 28 29 static int getMemoryUsage() { 30 // uncompBuf + a little extra 31 return 70; 32 } 33 34 UncompressedLZMA2OutputStream(FinishableOutputStream out) { 35 if (out == null) 36 throw new NullPointerException(); 37 38 this.out = out; 39 outData = new DataOutputStream(out); 40 } 41 42 public void write(int b) throws IOException { 43 tempBuf[0] = (byte)b; 44 write(tempBuf, 0, 1); 45 } 46 47 public void write(byte[] buf, int off, int len) throws IOException { 48 if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length) 49 throw new IndexOutOfBoundsException(); 50 51 if (exception != null) 52 throw exception; 53 54 if (finished) 55 throw new XZIOException("Stream finished or closed"); 56 57 try { 58 while (len > 0) { 59 int copySize = Math.min(uncompBuf.length - uncompPos, len); 60 System.arraycopy(buf, off, uncompBuf, uncompPos, copySize); 61 len -= copySize; 62 uncompPos += copySize; 63 64 if (uncompPos == uncompBuf.length) 65 writeChunk(); 66 } 67 } catch (IOException e) { 68 exception = e; 69 throw e; 70 } 71 } 72 73 private void writeChunk() throws IOException { 74 outData.writeByte(dictResetNeeded ? 0x01 : 0x02); 75 outData.writeShort(uncompPos - 1); 76 outData.write(uncompBuf, 0, uncompPos); 77 uncompPos = 0; 78 dictResetNeeded = false; 79 } 80 81 private void writeEndMarker() throws IOException { 82 if (exception != null) 83 throw exception; 84 85 if (finished) 86 throw new XZIOException("Stream finished or closed"); 87 88 try { 89 if (uncompPos > 0) 90 writeChunk(); 91 92 out.write(0x00); 93 } catch (IOException e) { 94 exception = e; 95 throw e; 96 } 97 } 98 99 public void flush() throws IOException { 100 if (exception != null) 101 throw exception; 102 103 if (finished) 104 throw new XZIOException("Stream finished or closed"); 105 106 try { 107 if (uncompPos > 0) 108 writeChunk(); 109 110 out.flush(); 111 } catch (IOException e) { 112 exception = e; 113 throw e; 114 } 115 } 116 117 public void finish() throws IOException { 118 if (!finished) { 119 writeEndMarker(); 120 121 try { 122 out.finish(); 123 } catch (IOException e) { 124 exception = e; 125 throw e; 126 } 127 128 finished = true; 129 } 130 } 131 132 public void close() throws IOException { 133 if (out != null) { 134 if (!finished) { 135 try { 136 writeEndMarker(); 137 } catch (IOException e) {} 138 } 139 140 try { 141 out.close(); 142 } catch (IOException e) { 143 if (exception == null) 144 exception = e; 145 } 146 147 out = null; 148 } 149 150 if (exception != null) 151 throw exception; 152 } 153 } 154