]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.compressions/src/org/simantics/compressions/impl/CompressingOutputStream.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.compressions / src / org / simantics / compressions / impl / CompressingOutputStream.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.FileNotFoundException;
16 import java.io.FileOutputStream;
17 import java.io.IOException;
18 import java.io.OutputStream;
19 import java.nio.ByteBuffer;
20 import java.nio.ByteOrder;
21 import java.nio.IntBuffer;
22 import java.nio.channels.WritableByteChannel;
23
24 /**
25  * @author Hannu Niemistö
26  * @author Tuukka Lehtonen
27  */
28 public abstract class CompressingOutputStream extends OutputStream {
29
30     protected static final int    BLOCK_SIZE = 1024 * 1024;
31
32     protected OutputStream        stream;
33     protected WritableByteChannel channel;
34     protected ByteBuffer          compressed;
35     protected byte[]              compressedArray;
36     protected ByteBuffer          uncompressed;
37     protected IntBuffer           header;
38     protected int                 bytes      = 0;
39
40     public CompressingOutputStream(File file) throws FileNotFoundException {
41         this(new FileOutputStream(file));
42     }
43
44     public CompressingOutputStream(FileOutputStream stream) {
45         this(stream, stream.getChannel());
46     }
47
48     public CompressingOutputStream(OutputStream stream) {
49         this(stream, null);
50     }
51
52     public CompressingOutputStream(OutputStream stream, WritableByteChannel channel) {
53         this.stream = stream;
54         this.channel = channel;
55         uncompressed = allocateBuffer(BLOCK_SIZE);
56     }
57
58     @Override
59     public void write(int b) throws IOException {
60         if(uncompressed.remaining() == 0)
61             flushBuffer();
62         uncompressed.put((byte)b);
63         ++bytes;
64     }
65
66     @Override
67     public void write(byte[] b, int off, int len) throws IOException {
68         bytes += len;
69         while(len > 0) {
70             int s = Math.min(len, uncompressed.remaining());
71             uncompressed.put(b, off, s);
72             len -= s;
73             off += s;
74             if(uncompressed.remaining() == 0)
75                 flushBuffer();
76         }
77     }
78
79     @Override
80     public void close() throws IOException {
81         try {
82             flushBuffer();
83
84             if (channel != null) {
85                 header.position(0);
86                 header.put(0);
87                 header.put(0);
88                 compressed.position(0);
89                 compressed.limit(8);
90                 channel.write(compressed);
91             } else if (stream != null) {
92                 stream.write(new byte[8]);
93             }
94             //System.out.println("Wrote " + bytes + " uncompressed bytes.");
95         } finally {
96             if (channel != null) {
97                 channel.close();
98                 channel = null;
99             }
100             if (stream != null) {
101                 stream.close();
102                 stream = null;
103             }
104         }
105     }
106
107     private void flushBuffer() throws IOException {
108         int uncompressedSize = uncompressed.position();
109         uncompressed.position(0);
110         int maxCompressedSize = compressBound(uncompressedSize) + 8;
111         if(compressed == null || compressed.capacity() < maxCompressedSize) {
112             compressed = allocateBuffer(maxCompressedSize);
113             compressed.order(ByteOrder.LITTLE_ENDIAN);
114             header = compressed.asIntBuffer();
115             if (channel == null)
116                 compressedArray = new byte[maxCompressedSize];
117         }
118         int compressedSize = compress(uncompressed, 0, uncompressedSize, 
119                 compressed, 8);
120         header.position(0);
121         header.put(compressedSize);
122         header.put(uncompressedSize);
123         compressed.position(0);
124         compressed.limit(compressedSize+8);
125         if (channel != null) {
126             channel.write(compressed);
127         } else {
128             compressed.get(compressedArray, 0, compressedSize+8);
129             stream.write(compressedArray, 0, compressedSize+8);
130         }
131     }
132
133     protected abstract int compressBound(int inputSize);
134
135     protected abstract int compress(ByteBuffer uncompressed, int uncompressedOffset, int uncompressedSize,
136             ByteBuffer compressed, int compressedOffset) throws IOException;
137
138     protected abstract ByteBuffer allocateBuffer(int capacity);
139
140 }