1 /* 2 * UncompressedLZMA2OutputStream 3 * 4 * Author: Lasse Collin <lasse.collin@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 final ArrayCache arrayCache; 17 18 private FinishableOutputStream out; 19 private final DataOutputStream outData; 20 21 private final byte[] uncompBuf; 22 private int uncompPos = 0; 23 private boolean dictResetNeeded = true; 24 25 private boolean finished = false; 26 private IOException exception = null; 27 28 private final byte[] tempBuf = new byte[1]; 29 getMemoryUsage()30 static int getMemoryUsage() { 31 // uncompBuf + a little extra 32 return 70; 33 } 34 UncompressedLZMA2OutputStream(FinishableOutputStream out, ArrayCache arrayCache)35 UncompressedLZMA2OutputStream(FinishableOutputStream out, 36 ArrayCache arrayCache) { 37 if (out == null) 38 throw new NullPointerException(); 39 40 this.out = out; 41 outData = new DataOutputStream(out); 42 43 // We only allocate one array from the cache. We will call 44 // putArray directly in writeEndMarker and thus we don't use 45 // ResettableArrayCache here. 46 this.arrayCache = arrayCache; 47 uncompBuf = arrayCache.getByteArray( 48 LZMA2OutputStream.COMPRESSED_SIZE_MAX, false); 49 } 50 write(int b)51 public void write(int b) throws IOException { 52 tempBuf[0] = (byte)b; 53 write(tempBuf, 0, 1); 54 } 55 write(byte[] buf, int off, int len)56 public void write(byte[] buf, int off, int len) throws IOException { 57 if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length) 58 throw new IndexOutOfBoundsException(); 59 60 if (exception != null) 61 throw exception; 62 63 if (finished) 64 throw new XZIOException("Stream finished or closed"); 65 66 try { 67 while (len > 0) { 68 int copySize = Math.min(LZMA2OutputStream.COMPRESSED_SIZE_MAX 69 - uncompPos, len); 70 System.arraycopy(buf, off, uncompBuf, uncompPos, copySize); 71 len -= copySize; 72 uncompPos += copySize; 73 74 if (uncompPos == LZMA2OutputStream.COMPRESSED_SIZE_MAX) 75 writeChunk(); 76 } 77 } catch (IOException e) { 78 exception = e; 79 throw e; 80 } 81 } 82 writeChunk()83 private void writeChunk() throws IOException { 84 outData.writeByte(dictResetNeeded ? 0x01 : 0x02); 85 outData.writeShort(uncompPos - 1); 86 outData.write(uncompBuf, 0, uncompPos); 87 uncompPos = 0; 88 dictResetNeeded = false; 89 } 90 writeEndMarker()91 private void writeEndMarker() throws IOException { 92 if (exception != null) 93 throw exception; 94 95 if (finished) 96 throw new XZIOException("Stream finished or closed"); 97 98 try { 99 if (uncompPos > 0) 100 writeChunk(); 101 102 out.write(0x00); 103 } catch (IOException e) { 104 exception = e; 105 throw e; 106 } 107 108 finished = true; 109 arrayCache.putArray(uncompBuf); 110 } 111 flush()112 public void flush() throws IOException { 113 if (exception != null) 114 throw exception; 115 116 if (finished) 117 throw new XZIOException("Stream finished or closed"); 118 119 try { 120 if (uncompPos > 0) 121 writeChunk(); 122 123 out.flush(); 124 } catch (IOException e) { 125 exception = e; 126 throw e; 127 } 128 } 129 finish()130 public void finish() throws IOException { 131 if (!finished) { 132 writeEndMarker(); 133 134 try { 135 out.finish(); 136 } catch (IOException e) { 137 exception = e; 138 throw e; 139 } 140 } 141 } 142 close()143 public void close() throws IOException { 144 if (out != null) { 145 if (!finished) { 146 try { 147 writeEndMarker(); 148 } catch (IOException e) {} 149 } 150 151 try { 152 out.close(); 153 } catch (IOException e) { 154 if (exception == null) 155 exception = e; 156 } 157 158 out = null; 159 } 160 161 if (exception != null) 162 throw exception; 163 } 164 } 165