1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2012 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.compressions.impl;
\r
14 import java.io.File;
\r
15 import java.io.FileInputStream;
\r
16 import java.io.FileNotFoundException;
\r
17 import java.io.IOException;
\r
18 import java.io.InputStream;
\r
19 import java.nio.ByteBuffer;
\r
20 import java.nio.ByteOrder;
\r
21 import java.nio.IntBuffer;
\r
22 import java.nio.channels.ReadableByteChannel;
\r
25 * @author Hannu Niemistö
\r
26 * @author Tuukka Lehtonen
\r
28 public abstract class DecompressingInputStream extends InputStream {
\r
30 protected InputStream stream;
\r
31 protected ReadableByteChannel channel;
\r
32 protected ByteBuffer header;
\r
33 protected IntBuffer intHeader;
\r
34 protected ByteBuffer compressed;
\r
35 protected ByteBuffer uncompressed;
\r
36 protected byte[] compressedArray;
\r
38 public DecompressingInputStream(File file) throws FileNotFoundException {
\r
39 this(new FileInputStream(file));
\r
42 public DecompressingInputStream(FileInputStream stream) {
\r
43 this(stream, stream.getChannel());
\r
46 public DecompressingInputStream(InputStream stream) {
\r
50 public DecompressingInputStream(InputStream stream, ReadableByteChannel channel) {
\r
51 this.stream = stream;
\r
52 this.channel = channel;
\r
53 header = ByteBuffer.allocate(8);
\r
54 header.order(ByteOrder.LITTLE_ENDIAN);
\r
55 intHeader = header.asIntBuffer();
\r
59 public int read() throws IOException {
\r
60 if(uncompressed == null || uncompressed.remaining() == 0)
\r
63 return uncompressed.get();
\r
67 public int read(byte[] b, int off, int len) throws IOException {
\r
70 if(uncompressed == null || uncompressed.remaining() == 0) {
\r
72 return bytes == 0 ? -1 : bytes;
\r
75 int s = Math.min(len, uncompressed.remaining());
\r
76 uncompressed.get(b, off, s);
\r
85 public void close() throws IOException {
\r
86 if (channel != null) {
\r
90 if (stream != null) {
\r
96 private boolean fillBuffer() throws IOException {
\r
98 if (channel != null) {
\r
99 if (Channels.read(channel, header) < 8)
\r
102 if (Channels.readStream(stream, header.array(), 8) < 8)
\r
106 intHeader.position(0);
\r
107 int compressedSize = intHeader.get();
\r
108 int uncompressedSize = intHeader.get();
\r
110 if(uncompressedSize == 0)
\r
113 uncompressed = ensureBufferSize(uncompressed, uncompressedSize);
\r
114 compressed = ensureBufferSize(compressed, compressedSize);
\r
116 compressed.position(0);
\r
117 compressed.limit(compressedSize);
\r
118 if (channel != null) {
\r
119 if (Channels.read(channel, compressed) < compressedSize)
\r
122 if (compressedArray == null || compressedArray.length < compressedSize)
\r
123 compressedArray = new byte[compressedSize];
\r
124 if (Channels.readStream(stream, compressedArray, compressedSize) < 8)
\r
126 compressed.put(compressedArray, 0, compressedSize);
\r
129 decompress(compressed, 0, compressedSize, uncompressed, 0, uncompressedSize);
\r
131 uncompressed.position(0);
\r
132 uncompressed.limit(uncompressedSize);
\r
137 private static ByteBuffer ensureBufferSize(ByteBuffer buffer, int minCapacity) {
\r
138 int oldCapacity = buffer != null ? buffer.capacity() : 0;
\r
139 if (buffer == null || oldCapacity < minCapacity) {
\r
140 int newCapacity = grow(oldCapacity, minCapacity);
\r
141 //System.out.println("ensureBufferSize(" + oldCapacity + ", " + minCapacity + "), new capacity " + newCapacity);
\r
142 buffer = ByteBuffer.allocateDirect(newCapacity);
\r
148 * @param oldCapacity current capacity of a buffer
\r
149 * @param minCapacity
\r
150 * @return new capacity
\r
152 private static int grow(int oldCapacity, int minCapacity) {
\r
153 // overflow-conscious code
\r
154 int newCapacity = oldCapacity + (oldCapacity >> 1);
\r
155 if (newCapacity - minCapacity < 0)
\r
156 newCapacity = minCapacity;
\r
157 if (newCapacity < 0) // overflow
\r
158 throw new OutOfMemoryError();
\r
159 return newCapacity;
\r
162 public abstract void decompress(ByteBuffer compressed, int compressedOffset, int compressedSize,
\r
163 ByteBuffer uncompressed, int uncompressedOffset, int uncompressedSize) throws IOException;
\r