1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
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
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.db.procore.cluster;
14 import java.nio.ByteBuffer;
15 import java.nio.ByteOrder;
17 import org.simantics.db.exception.InternalException;
20 static private final int InLength = 1<<20;
22 public static class DecompressStruct {
27 static class SourceData {
28 SourceData(byte[] data) {
33 return data.length - offset;
36 int inLength = 4; // sizeof(int)
37 assert(left() >= inLength); // must have data for input
38 ByteBuffer buffer = ByteBuffer.wrap(data, offset, inLength);
39 buffer.order(ByteOrder.LITTLE_ENDIAN); // argh!
40 int t = buffer.getInt();
44 void readBytes(byte[] bytes, int aOffset, int inLength) {
45 assert(left() >= inLength); // must have data for input
46 System.arraycopy(data, offset, bytes, aOffset, inLength);
52 public static DecompressStruct decompress(byte[] data) throws InternalException {
53 assert(data.length > 12); // 3*(table size)
54 SourceData sourceData = new SourceData(data);
55 DecompressStruct struct = new DecompressStruct();
56 int longSize = sourceData.readInt();
57 int intSize = sourceData.readInt();
58 int byteSize = sourceData.readInt();
59 struct.longs = new long[longSize];
61 decompress(sourceData, struct.longs);
62 struct.ints = new int[intSize];
63 decompress(sourceData, struct.ints);
64 struct.bytes = new byte[byteSize];
65 decompress(sourceData, struct.bytes);
66 } catch (CompressionException e) {
67 throw new InternalException("Failed to decompress.", e);
71 private static void decompress(SourceData sourceData, long[] longs) throws CompressionException {
72 int length = longs.length * 8;
73 ByteBuffer bytes = ByteBuffer.allocate(length);
74 int size = decompressRaw(sourceData, bytes.array());
75 assert(size == length);
76 bytes.order(ByteOrder.LITTLE_ENDIAN); // argh
77 for (int i=0; i<longs.length; ++i)
78 longs[i] = bytes.getLong();
80 private static void decompress(SourceData sourceData, int[] ints) throws CompressionException {
81 int length = ints.length * 4;
82 ByteBuffer bytes = ByteBuffer.allocate(length);
83 int size = decompressRaw(sourceData, bytes.array());
84 assert(size == length);
85 bytes.order(ByteOrder.LITTLE_ENDIAN); // argh
86 for (int i=0; i<ints.length; ++i)
87 ints[i] = bytes.getInt();
89 private static void decompress(SourceData sourceData, byte[] bytes) throws CompressionException {
90 int size = decompressRaw(sourceData, bytes);
91 assert(size == bytes.length);
93 private static int decompressRaw(SourceData sourceData, byte[] bytes) throws CompressionException {
94 int aDstSize = bytes.length;
98 for (int dstSize = 0;;) {
99 int dataLength = sourceData.readInt();
100 assert(dataLength <= InLength); // data is written in blocks
101 if (0 == dataLength) // EOF
103 dstSize += dataLength;
104 int inLength = sourceData.readInt();
106 assert(aDstSize >= dstSize); // must have space for data
107 assert(sourceData.left() >= inLength); // must have data for input
108 assert(inLength > 0); // no data no block
109 assert(inLength <= InLength); // input size is block size or less
110 assert(inLength <= dataLength); // input size is never bigger than data size
112 if (inLength < dataLength) {// block was actually compressed
113 decompress(sourceData.data, sourceData.offset, inLength, bytes, dstOffset, dataLength);
114 sourceData.offset += inLength;
115 dstOffset += dataLength;
117 sourceData.readBytes(bytes, dstOffset, inLength);
118 dstOffset += inLength;
122 private static void decompress(byte[] in, int inOffset, int inLength, byte[] out, int outOffset, int outLength) throws CompressionException {
123 ByteBuffer inBuffer = ByteBuffer.allocateDirect(inLength);
124 inBuffer.put(in, inOffset, inLength);
126 ByteBuffer outBuffer = ByteBuffer.allocateDirect(outLength);
127 int inflateSize = org.simantics.fastlz.FastLZ.decompressBuffer(inBuffer, 0, inLength, outBuffer, 0, outLength);
128 if (inflateSize != outLength)
129 throw new RuntimeException("Decompression error.");
131 outBuffer.get(out, outOffset, outLength);