]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.compressions/src/org/simantics/compressions/impl/DecompressingInputStream.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.compressions / src / org / simantics / compressions / impl / DecompressingInputStream.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2012 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.compressions.impl;
13
14 import java.io.File;
15 import java.io.FileInputStream;
16 import java.io.FileNotFoundException;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.nio.ByteBuffer;
20 import java.nio.ByteOrder;
21 import java.nio.IntBuffer;
22 import java.nio.channels.ReadableByteChannel;
23
24 /**
25  * @author Hannu Niemistö
26  * @author Tuukka Lehtonen
27  */
28 public abstract class DecompressingInputStream extends InputStream {
29
30     protected InputStream         stream;
31     protected ReadableByteChannel channel;
32     protected ByteBuffer          header;
33     protected IntBuffer           intHeader;
34     protected ByteBuffer          compressed;
35     protected ByteBuffer          uncompressed;
36     protected byte[]              compressedArray;
37
38     public DecompressingInputStream(File file) throws FileNotFoundException {
39         this(new FileInputStream(file));
40     }
41
42     public DecompressingInputStream(FileInputStream stream) {
43         this(stream, stream.getChannel());
44     }
45
46     public DecompressingInputStream(InputStream stream) {
47         this(stream, null);
48     }
49
50     public DecompressingInputStream(InputStream stream, ReadableByteChannel channel) {
51         this.stream = stream;
52         this.channel = channel;
53         header = ByteBuffer.allocate(8);
54         header.order(ByteOrder.LITTLE_ENDIAN);
55         intHeader = header.asIntBuffer();
56     }
57
58     @Override
59     public int read() throws IOException {
60         if(uncompressed == null || uncompressed.remaining() == 0)
61             if(!fillBuffer())
62                 return -1;
63         return uncompressed.get();
64     }
65
66     @Override
67     public int read(byte[] b, int off, int len) throws IOException {
68         int bytes = 0;
69         while(len > 0) {
70             if(uncompressed == null || uncompressed.remaining() == 0) {
71                 if(!fillBuffer()) {
72                     return bytes == 0 ? -1 : bytes;
73                 }
74             }
75             int s = Math.min(len, uncompressed.remaining());
76             uncompressed.get(b, off, s);
77             off += s;
78             len -= s;
79             bytes += s;
80         }
81         return bytes;
82     }
83
84     @Override
85     public void close() throws IOException {
86         if (channel != null) {
87             channel.close();
88             channel = null;
89         }
90         if (stream != null) {
91             stream.close();
92             stream = null;
93         }
94     }
95
96     private boolean fillBuffer() throws IOException {   
97         header.position(0);
98         if (channel != null) {
99             if (Channels.read(channel, header) < 8)
100                 return false;
101         } else {
102             if (Channels.readStream(stream, header.array(), 8) < 8)
103                 return false;
104         }
105
106         intHeader.position(0);
107         int compressedSize = intHeader.get();
108         int uncompressedSize = intHeader.get();
109
110         if(uncompressedSize == 0)
111             return false;
112
113         uncompressed = ensureBufferSize(uncompressed, uncompressedSize);
114         compressed = ensureBufferSize(compressed, compressedSize);
115
116         compressed.position(0);
117         compressed.limit(compressedSize);
118         if (channel != null) {
119             if (Channels.read(channel, compressed) < compressedSize)
120                 return false;
121         } else {
122             if (compressedArray == null || compressedArray.length < compressedSize) 
123                 compressedArray = new byte[compressedSize];
124             if (Channels.readStream(stream, compressedArray, compressedSize) < 8)
125                 return false;
126             compressed.put(compressedArray, 0, compressedSize);
127         }
128
129         decompress(compressed, 0, compressedSize, uncompressed, 0, uncompressedSize);
130
131         uncompressed.position(0);
132         uncompressed.limit(uncompressedSize);
133
134         return true;
135     }
136
137     private ByteBuffer ensureBufferSize(ByteBuffer buffer, int minCapacity) {
138         int oldCapacity = buffer != null ? buffer.capacity() : 0;
139         if (buffer == null || oldCapacity < minCapacity) {
140             int newCapacity = grow(oldCapacity, minCapacity);
141             //System.out.println("ensureBufferSize(" + oldCapacity + ", " + minCapacity + "), new capacity " + newCapacity);
142             buffer = allocateBuffer(newCapacity);
143         }
144         return buffer;
145     }
146
147     protected ByteBuffer allocateBuffer(int capacity) {
148         return ByteBuffer.allocateDirect(capacity);
149     }
150     
151     /**
152      * @param oldCapacity current capacity of a buffer
153      * @param minCapacity
154      * @return new capacity
155      */
156     private static int grow(int oldCapacity, int minCapacity) {
157         // overflow-conscious code
158         int newCapacity = oldCapacity + (oldCapacity >> 1);
159         if (newCapacity - minCapacity < 0)
160             newCapacity = minCapacity;
161         if (newCapacity < 0) // overflow
162             throw new OutOfMemoryError();
163         return newCapacity;
164     }
165
166     public abstract void decompress(ByteBuffer compressed, int compressedOffset, int compressedSize,
167             ByteBuffer uncompressed, int uncompressedOffset, int uncompressedSize) throws IOException;
168
169 }