1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.handler.codec.compression;
17
18 import static io.netty5.handler.codec.compression.Bzip2Constants.HUFFMAN_MAX_ALPHABET_SIZE;
19 import static io.netty5.handler.codec.compression.Bzip2Constants.HUFFMAN_SYMBOL_RUNA;
20 import static io.netty5.handler.codec.compression.Bzip2Constants.HUFFMAN_SYMBOL_RUNB;
21
22
23
24
25
26
27 final class Bzip2MTFAndRLE2StageEncoder {
28
29
30
31 private final int[] bwtBlock;
32
33
34
35
36 private final int bwtLength;
37
38
39
40
41
42 private final boolean[] bwtValuesPresent;
43
44
45
46
47 private final char[] mtfBlock;
48
49
50
51
52 private int mtfLength;
53
54
55
56
57 private final int[] mtfSymbolFrequencies = new int[HUFFMAN_MAX_ALPHABET_SIZE];
58
59
60
61
62 private int alphabetSize;
63
64
65
66
67
68
69
70 Bzip2MTFAndRLE2StageEncoder(final int[] bwtBlock, final int bwtLength, final boolean[] bwtValuesPresent) {
71 this.bwtBlock = bwtBlock;
72 this.bwtLength = bwtLength;
73 this.bwtValuesPresent = bwtValuesPresent;
74 mtfBlock = new char[bwtLength + 1];
75 }
76
77
78
79
80 void encode() {
81 final int bwtLength = this.bwtLength;
82 final boolean[] bwtValuesPresent = this.bwtValuesPresent;
83 final int[] bwtBlock = this.bwtBlock;
84 final char[] mtfBlock = this.mtfBlock;
85 final int[] mtfSymbolFrequencies = this.mtfSymbolFrequencies;
86 final byte[] huffmanSymbolMap = new byte[256];
87 final Bzip2MoveToFrontTable symbolMTF = new Bzip2MoveToFrontTable();
88
89 int totalUniqueValues = 0;
90 for (int i = 0; i < huffmanSymbolMap.length; i++) {
91 if (bwtValuesPresent[i]) {
92 huffmanSymbolMap[i] = (byte) totalUniqueValues++;
93 }
94 }
95 final int endOfBlockSymbol = totalUniqueValues + 1;
96
97 int mtfIndex = 0;
98 int repeatCount = 0;
99 int totalRunAs = 0;
100 int totalRunBs = 0;
101 for (int i = 0; i < bwtLength; i++) {
102
103 final int mtfPosition = symbolMTF.valueToFront(huffmanSymbolMap[bwtBlock[i] & 0xff]);
104
105 if (mtfPosition == 0) {
106 repeatCount++;
107 } else {
108 if (repeatCount > 0) {
109 repeatCount--;
110 while (true) {
111 if ((repeatCount & 1) == 0) {
112 mtfBlock[mtfIndex++] = HUFFMAN_SYMBOL_RUNA;
113 totalRunAs++;
114 } else {
115 mtfBlock[mtfIndex++] = HUFFMAN_SYMBOL_RUNB;
116 totalRunBs++;
117 }
118
119 if (repeatCount <= 1) {
120 break;
121 }
122 repeatCount = (repeatCount - 2) >>> 1;
123 }
124 repeatCount = 0;
125 }
126 mtfBlock[mtfIndex++] = (char) (mtfPosition + 1);
127 mtfSymbolFrequencies[mtfPosition + 1]++;
128 }
129 }
130
131 if (repeatCount > 0) {
132 repeatCount--;
133 while (true) {
134 if ((repeatCount & 1) == 0) {
135 mtfBlock[mtfIndex++] = HUFFMAN_SYMBOL_RUNA;
136 totalRunAs++;
137 } else {
138 mtfBlock[mtfIndex++] = HUFFMAN_SYMBOL_RUNB;
139 totalRunBs++;
140 }
141
142 if (repeatCount <= 1) {
143 break;
144 }
145 repeatCount = (repeatCount - 2) >>> 1;
146 }
147 }
148
149 mtfBlock[mtfIndex] = (char) endOfBlockSymbol;
150 mtfSymbolFrequencies[endOfBlockSymbol]++;
151 mtfSymbolFrequencies[HUFFMAN_SYMBOL_RUNA] += totalRunAs;
152 mtfSymbolFrequencies[HUFFMAN_SYMBOL_RUNB] += totalRunBs;
153
154 mtfLength = mtfIndex + 1;
155 alphabetSize = endOfBlockSymbol + 1;
156 }
157
158
159
160
161 char[] mtfBlock() {
162 return mtfBlock;
163 }
164
165
166
167
168 int mtfLength() {
169 return mtfLength;
170 }
171
172
173
174
175 int mtfAlphabetSize() {
176 return alphabetSize;
177 }
178
179
180
181
182 int[] mtfSymbolFrequencies() {
183 return mtfSymbolFrequencies;
184 }
185 }