1 package org.simantics.db.server.internal;
\r
3 import java.nio.ByteBuffer;
\r
4 import java.util.Arrays;
\r
6 import org.simantics.fastlz.FastLZ;
\r
7 import org.simantics.fastlz.FastLZJava;
\r
11 * @author Tuukka Lehtonen
\r
13 public class ClusterDecompressor {
\r
15 private byte[] inflateBuffer;
\r
17 public Object[] inflateCluster(int inflateSize, ByteBuffer deflatedCluster)
\r
18 throws CompressionException {
\r
19 int deflatedSize = deflatedCluster.limit();
\r
20 Object[] arrays = new Object[3];
\r
21 int inflated = decompressCluster(deflatedCluster, deflatedSize, inflateSize, arrays);
\r
22 if (inflated != inflateSize)
\r
23 throw new CompressionException("decompression error, inflated "
\r
24 + inflated + " bytes when " + inflateSize + " expected.");
\r
29 * Wrapper for the old native direct byte buffer version of cluster
\r
33 * @param deflatedSize
\r
34 * @param inflatedSize
\r
36 * expects an array of 3 elements. The decompression result will
\r
37 * be stored in here. [0] = cluster long array (long[]), [1] =
\r
38 * cluster int array (int[]), [2] = cluster byte array (byte[]).
\r
39 * @return the amount of bytes inflated from the deflated cluster. Matches
\r
40 * inflatedSize when successful.
\r
42 * @see FastLZ#decompressCluster(ByteBuffer, int, int, Object[])
\r
44 public int decompressCluster(ByteBuffer deflated, int deflatedSize, int inflatedSize, Object[] arrays) {
\r
45 if (deflated.isDirect()) {
\r
46 if (FastLZ.isNativeInitialized()) {
\r
47 FastLZ.decompressCluster(deflated, deflatedSize, inflatedSize, arrays);
\r
48 return inflatedSize;
\r
50 // REALLY SLOW FALLBACK: java code for direct byte buffers
\r
52 byte[] array = null;
\r
53 if (deflated.hasArray()) {
\r
54 array = deflated.array();
\r
56 // SLOW FALLBACK: read-only heap byte buffer
\r
57 array = new byte[deflatedSize];
\r
58 int pos = deflated.position();
\r
59 deflated.position(0);
\r
60 deflated.get(array, 0, deflatedSize);
\r
61 deflated.position(pos);
\r
63 return decompressCluster(array, deflatedSize, inflatedSize, arrays);
\r
68 * @param deflatedSize
\r
69 * @param inflatedSize
\r
73 public synchronized int decompressCluster(byte[] deflated, int deflatedSize, int inflatedSize, Object[] arrays) {
\r
74 if (inflateBuffer == null) {
\r
75 inflateBuffer = new byte[inflatedSize];
\r
76 } else if (inflateBuffer.length < inflatedSize) {
\r
77 inflateBuffer = new byte[inflatedSize];
\r
79 return decompressCluster(deflated, deflatedSize, inflateBuffer, inflatedSize, arrays);
\r
84 * @param deflatedSize
\r
86 * @param inflatedSize
\r
88 * @return amount of bytes inflated from the original deflated buffer.
\r
89 * Should match inflatedSize if everything went ok, otherwise will
\r
92 public static int decompressCluster(byte[] deflated, int deflatedSize, byte[] inflated, int inflatedSize, Object[] arrays) {
\r
93 if (inflated.length < inflatedSize)
\r
94 throw new IllegalArgumentException("inflate buffer size (" + inflated.length + ") is smaller than inflated size (" + inflatedSize + ")");
\r
96 int decompressedBytes = FastLZJava.decompress(deflated, 0, deflatedSize, inflated, 0, inflatedSize);
\r
97 if (decompressedBytes != inflatedSize)
\r
98 return decompressedBytes;
\r
102 int longCount = readInt(inflated, offset);
\r
103 long[] longs = new long[longCount];
\r
104 copyLongs(inflated, offset + 4, longs);
\r
105 offset += 4 + 8*longCount;
\r
107 int intCount = readInt(inflated, offset);
\r
108 int[] ints = new int[intCount];
\r
109 copyInts(inflated, offset + 4, ints);
\r
110 offset += 4 + 4*intCount;
\r
112 int byteCount = readInt(inflated, offset);
\r
113 byte[] bytes = Arrays.copyOfRange(inflated, offset + 4, offset + 4 + byteCount);
\r
119 return decompressedBytes;
\r
122 private static void copyInts(byte[] bytes, int i, int[] ints) {
\r
124 int count = ints.length;
\r
125 for (int a = 0; a < count; ++a, offset += 4) {
\r
126 int value = (((int) bytes[offset] & 0xff)) |
\r
127 (((int) bytes[offset+1] & 0xff) << 8) |
\r
128 (((int) bytes[offset+2] & 0xff) << 16) |
\r
129 (((int) bytes[offset+3] & 0xff) << 24);
\r
134 private static void copyLongs(byte[] bytes, int i, long[] longs) {
\r
136 int count = longs.length;
\r
137 for (int a = 0; a < count; ++a, offset += 8) {
\r
138 long value = (((long) bytes[offset] & 0xff)) |
\r
139 (((long) bytes[offset+1] & 0xff) << 8) |
\r
140 (((long) bytes[offset+2] & 0xff) << 16) |
\r
141 (((long) bytes[offset+3] & 0xff) << 24) |
\r
142 (((long) bytes[offset+4] & 0xff) << 32) |
\r
143 (((long) bytes[offset+5] & 0xff) << 40) |
\r
144 (((long) bytes[offset+6] & 0xff) << 48) |
\r
145 (((long) bytes[offset+7] & 0xff) << 56);
\r
150 private static int readInt(byte[] array, int offset) {
\r
151 return (((int) array[offset] & 0xff)) |
\r
152 (((int) array[offset+1] & 0xff) << 8) |
\r
153 (((int) array[offset+2] & 0xff) << 16) |
\r
154 (((int) array[offset+3] & 0xff) << 24);
\r