1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.compress.harmony.pack200;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.util.Arrays;
22
23
24
25
26
27 public class PopulationCodec extends Codec {
28
29 private final Codec favouredCodec;
30 private Codec tokenCodec;
31 private final Codec unfavouredCodec;
32 private int l;
33 private int[] favoured;
34
35 public PopulationCodec(final Codec favouredCodec, final Codec tokenCodec, final Codec unvafouredCodec) {
36 this.favouredCodec = favouredCodec;
37 this.tokenCodec = tokenCodec;
38 this.unfavouredCodec = unvafouredCodec;
39 }
40
41 public PopulationCodec(final Codec favouredCodec, final int l, final Codec unfavouredCodec) {
42 if (l >= 256 || l <= 0) {
43 throw new IllegalArgumentException("L must be between 1..255");
44 }
45 this.favouredCodec = favouredCodec;
46 this.l = l;
47 this.unfavouredCodec = unfavouredCodec;
48 }
49
50 @Override
51 public int decode(final InputStream in) throws IOException, Pack200Exception {
52 throw new Pack200Exception("Population encoding does not work unless the number of elements are known");
53 }
54
55 @Override
56 public int decode(final InputStream in, final long last) throws IOException, Pack200Exception {
57 throw new Pack200Exception("Population encoding does not work unless the number of elements are known");
58 }
59
60 @Override
61 public int[] decodeInts(final int n, final InputStream in) throws IOException, Pack200Exception {
62 lastBandLength = 0;
63 favoured = new int[check(n, in)];
64
65 int[] result;
66
67 int smallest = Integer.MAX_VALUE, absoluteSmallest;
68 int last = 0;
69 int value = 0, absoluteValue;
70 int k = -1;
71 while (true) {
72 value = favouredCodec.decode(in, last);
73 if (k > -1 && (value == smallest || value == last)) {
74 break;
75 }
76 favoured[++k] = value;
77 absoluteSmallest = Math.abs(smallest);
78 absoluteValue = Math.abs(value);
79 if (absoluteSmallest > absoluteValue) {
80 smallest = value;
81 } else if (absoluteSmallest == absoluteValue) {
82
83 smallest = absoluteSmallest;
84 }
85 last = value;
86 }
87 lastBandLength += k;
88
89 if (tokenCodec == null) {
90 if (k < 256) {
91 tokenCodec = BYTE1;
92 } else {
93
94 int b = 1;
95 BHSDCodec codec;
96 while (++b < 5) {
97 codec = new BHSDCodec(b, 256 - l, 0);
98 if (codec.encodes(k)) {
99 tokenCodec = codec;
100 break;
101 }
102 }
103 if (tokenCodec == null) {
104 throw new Pack200Exception("Cannot calculate token codec from " + k + " and " + l);
105 }
106 }
107 }
108
109 lastBandLength += n;
110 result = tokenCodec.decodeInts(n, in);
111
112 last = 0;
113 for (int i = 0; i < n; i++) {
114 final int index = result[i];
115 if (index == 0) {
116 lastBandLength++;
117 result[i] = last = unfavouredCodec.decode(in, last);
118 } else {
119 result[i] = favoured[index - 1];
120 }
121 }
122 return result;
123 }
124
125 @Override
126 public byte[] encode(final int value) throws Pack200Exception {
127 throw new Pack200Exception("Population encoding does not work unless the number of elements are known");
128 }
129
130 @Override
131 public byte[] encode(final int value, final int last) throws Pack200Exception {
132 throw new Pack200Exception("Population encoding does not work unless the number of elements are known");
133 }
134
135 public byte[] encode(final int[] favoured, final int[] tokens, final int[] unfavoured) throws Pack200Exception {
136 final int[] favoured2 = Arrays.copyOf(favoured, favoured.length + 1);
137 favoured2[favoured2.length - 1] = favoured[favoured.length - 1];
138 final byte[] favouredEncoded = favouredCodec.encode(favoured2);
139 final byte[] tokensEncoded = tokenCodec.encode(tokens);
140 final byte[] unfavouredEncoded = unfavouredCodec.encode(unfavoured);
141 final byte[] band = new byte[favouredEncoded.length + tokensEncoded.length + unfavouredEncoded.length];
142 System.arraycopy(favouredEncoded, 0, band, 0, favouredEncoded.length);
143 System.arraycopy(tokensEncoded, 0, band, favouredEncoded.length, tokensEncoded.length);
144 System.arraycopy(unfavouredEncoded, 0, band, favouredEncoded.length + tokensEncoded.length, unfavouredEncoded.length);
145 return band;
146 }
147
148 public int[] getFavoured() {
149 return favoured;
150 }
151
152 public Codec getFavouredCodec() {
153 return favouredCodec;
154 }
155
156 public Codec getTokenCodec() {
157 return tokenCodec;
158 }
159
160 public Codec getUnfavouredCodec() {
161 return unfavouredCodec;
162 }
163 }