1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package org.waarp.compress.zstdsafe;
35
36 import static org.waarp.compress.zstdsafe.Constants.*;
37 import static org.waarp.compress.zstdsafe.UnsafeUtil.*;
38
39 class HuffmanCompressor {
40 private HuffmanCompressor() {
41 }
42
43 public static int compress4streams(final byte[] outputBase,
44 final int outputAddress,
45 final int outputSize,
46 final byte[] inputBase,
47 final int inputAddress,
48 final int inputSize,
49 final HuffmanCompressionTable table) {
50 int input = inputAddress;
51 final int inputLimit = inputAddress + inputSize;
52 int output = outputAddress;
53 final int outputLimit = outputAddress + outputSize;
54
55 final int segmentSize = (inputSize + 3) / 4;
56
57 if (outputSize <
58 6 + 1 + 1 +
59 1 +
60 8 ) {
61 return 0;
62 }
63
64 if (inputSize <= 6 + 1 + 1 + 1) {
65 return 0;
66 }
67
68 output += SIZE_OF_SHORT + SIZE_OF_SHORT + SIZE_OF_SHORT;
69
70 int compressedSize;
71
72
73 compressedSize =
74 compressSingleStream(outputBase, output, outputLimit - output,
75 inputBase, input, segmentSize, table);
76 if (compressedSize == 0) {
77 return 0;
78 }
79 putShort(outputBase, outputAddress, (short) compressedSize);
80 output += compressedSize;
81 input += segmentSize;
82
83
84 compressedSize =
85 compressSingleStream(outputBase, output, outputLimit - output,
86 inputBase, input, segmentSize, table);
87 if (compressedSize == 0) {
88 return 0;
89 }
90 putShort(outputBase, outputAddress + SIZE_OF_SHORT, (short) compressedSize);
91 output += compressedSize;
92 input += segmentSize;
93
94
95 compressedSize =
96 compressSingleStream(outputBase, output, outputLimit - output,
97 inputBase, input, segmentSize, table);
98 if (compressedSize == 0) {
99 return 0;
100 }
101 putShort(outputBase, outputAddress + SIZE_OF_SHORT + SIZE_OF_SHORT,
102 (short) compressedSize);
103 output += compressedSize;
104 input += segmentSize;
105
106
107 compressedSize =
108 compressSingleStream(outputBase, output, outputLimit - output,
109 inputBase, input, inputLimit - input, table);
110 if (compressedSize == 0) {
111 return 0;
112 }
113 output += compressedSize;
114
115 return output - outputAddress;
116 }
117
118 public static int compressSingleStream(final byte[] outputBase,
119 final int outputAddress,
120 final int outputSize,
121 final byte[] inputBase,
122 final int inputAddress,
123 final int inputSize,
124 final HuffmanCompressionTable table) {
125 if (outputSize < SIZE_OF_LONG) {
126 return 0;
127 }
128 final BitOutputStream bitstream =
129 new BitOutputStream(outputBase, outputAddress, outputSize);
130
131 int n = inputSize & ~3;
132
133 switch (inputSize & 3) {
134 case 3:
135 table.encodeSymbol(bitstream, inputBase[inputAddress + n + 2] & 0xFF);
136
137 case 2:
138 table.encodeSymbol(bitstream, inputBase[inputAddress + n + 1] & 0xFF);
139
140 case 1:
141 table.encodeSymbol(bitstream, inputBase[inputAddress + n] & 0xFF);
142 bitstream.flush();
143
144 case 0:
145 default:
146 break;
147 }
148
149 for (; n > 0; n -= 4) {
150 table.encodeSymbol(bitstream, inputBase[inputAddress + n - 1] & 0xFF);
151 table.encodeSymbol(bitstream, inputBase[inputAddress + n - 2] & 0xFF);
152 table.encodeSymbol(bitstream, inputBase[inputAddress + n - 3] & 0xFF);
153 table.encodeSymbol(bitstream, inputBase[inputAddress + n - 4] & 0xFF);
154 bitstream.flush();
155 }
156
157 return bitstream.close();
158 }
159 }