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.FileNotFoundException;
\r
16 import java.io.FileOutputStream;
\r
17 import java.io.IOException;
\r
18 import java.io.OutputStream;
\r
19 import java.nio.ByteBuffer;
\r
20 import java.nio.ByteOrder;
\r
21 import java.nio.IntBuffer;
\r
22 import java.nio.channels.WritableByteChannel;
\r
25 * @author Hannu Niemistö
\r
26 * @author Tuukka Lehtonen
\r
28 public abstract class CompressingOutputStream extends OutputStream {
\r
30 protected static final int BLOCK_SIZE = 1024 * 1024;
\r
32 protected OutputStream stream;
\r
33 protected WritableByteChannel channel;
\r
34 protected ByteBuffer compressed;
\r
35 protected byte[] compressedArray;
\r
36 protected ByteBuffer uncompressed;
\r
37 protected IntBuffer header;
\r
38 protected int bytes = 0;
\r
40 public CompressingOutputStream(File file) throws FileNotFoundException {
\r
41 this(new FileOutputStream(file));
\r
44 public CompressingOutputStream(FileOutputStream stream) {
\r
45 this(stream, stream.getChannel());
\r
48 public CompressingOutputStream(OutputStream stream) {
\r
52 public CompressingOutputStream(OutputStream stream, WritableByteChannel channel) {
\r
53 this.stream = stream;
\r
54 this.channel = channel;
\r
55 uncompressed = allocateBuffer(BLOCK_SIZE);
\r
59 public void write(int b) throws IOException {
\r
60 if(uncompressed.remaining() == 0)
\r
62 uncompressed.put((byte)b);
\r
67 public void write(byte[] b, int off, int len) throws IOException {
\r
70 int s = Math.min(len, uncompressed.remaining());
\r
71 uncompressed.put(b, off, s);
\r
74 if(uncompressed.remaining() == 0)
\r
80 public void close() throws IOException {
\r
84 if (channel != null) {
\r
88 compressed.position(0);
\r
89 compressed.limit(8);
\r
90 channel.write(compressed);
\r
91 } else if (stream != null) {
\r
92 stream.write(new byte[8]);
\r
94 //System.out.println("Wrote " + bytes + " uncompressed bytes.");
\r
96 if (channel != null) {
\r
100 if (stream != null) {
\r
107 private void flushBuffer() throws IOException {
\r
108 int uncompressedSize = uncompressed.position();
\r
109 uncompressed.position(0);
\r
110 int maxCompressedSize = compressBound(uncompressedSize) + 8;
\r
111 if(compressed == null || compressed.capacity() < maxCompressedSize) {
\r
112 compressed = allocateBuffer(maxCompressedSize);
\r
113 compressed.order(ByteOrder.LITTLE_ENDIAN);
\r
114 header = compressed.asIntBuffer();
\r
115 if (channel == null)
\r
116 compressedArray = new byte[maxCompressedSize];
\r
118 int compressedSize = compress(uncompressed, 0, uncompressedSize,
\r
120 header.position(0);
\r
121 header.put(compressedSize);
\r
122 header.put(uncompressedSize);
\r
123 compressed.position(0);
\r
124 compressed.limit(compressedSize+8);
\r
125 if (channel != null) {
\r
126 channel.write(compressed);
\r
128 compressed.get(compressedArray, 0, compressedSize+8);
\r
129 stream.write(compressedArray, 0, compressedSize+8);
\r
133 protected abstract int compressBound(int inputSize);
\r
135 protected abstract int compress(ByteBuffer uncompressed, int uncompressedOffset, int uncompressedSize,
\r
136 ByteBuffer compressed, int compressedOffset) throws IOException;
\r
138 protected abstract ByteBuffer allocateBuffer(int capacity);
\r