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 import org.apache.commons.compress.utils.ExactMath;
24
25
26
27
28
29 public class RunCodec extends Codec {
30
31 private int k;
32 private final Codec aCodec;
33 private final Codec bCodec;
34 private int last;
35
36 public RunCodec(final int k, final Codec aCodec, final Codec bCodec) throws Pack200Exception {
37 if (k <= 0) {
38 throw new Pack200Exception("Cannot have a RunCodec for a negative number of numbers");
39 }
40 if (aCodec == null || bCodec == null) {
41 throw new Pack200Exception("Must supply both codecs for a RunCodec");
42 }
43 this.k = k;
44 this.aCodec = aCodec;
45 this.bCodec = bCodec;
46 }
47
48 @Override
49 public int decode(final InputStream in) throws IOException, Pack200Exception {
50 return decode(in, this.last);
51 }
52
53 @Override
54 public int decode(final InputStream in, final long last) throws IOException, Pack200Exception {
55 if (--k >= 0) {
56 final int value = aCodec.decode(in, this.last);
57 this.last = k == 0 ? 0 : value;
58 return normalise(value, aCodec);
59 }
60 this.last = bCodec.decode(in, this.last);
61 return normalise(this.last, bCodec);
62 }
63
64 @Override
65 public int[] decodeInts(final int n, final InputStream in) throws IOException, Pack200Exception {
66 final int[] aValues = aCodec.decodeInts(k, in);
67 normalise(aValues, aCodec);
68 final int[] bValues = bCodec.decodeInts(n - k, in);
69 normalise(bValues, bCodec);
70 final int[] band = new int[check(n, in)];
71 System.arraycopy(aValues, 0, band, 0, k);
72 System.arraycopy(bValues, 0, band, k, n - k);
73 lastBandLength = aCodec.lastBandLength + bCodec.lastBandLength;
74 return band;
75 }
76
77 @Override
78 public byte[] encode(final int value) throws Pack200Exception {
79 throw new Pack200Exception("Must encode entire band at once with a RunCodec");
80 }
81
82 @Override
83 public byte[] encode(final int value, final int last) throws Pack200Exception {
84 throw new Pack200Exception("Must encode entire band at once with a RunCodec");
85 }
86
87 public Codec getACodec() {
88 return aCodec;
89 }
90
91 public Codec getBCodec() {
92 return bCodec;
93 }
94
95 public int getK() {
96 return k;
97 }
98
99 private int normalise(int value, final Codec codecUsed) {
100 if (codecUsed instanceof BHSDCodec) {
101 final BHSDCodec bhsd = (BHSDCodec) codecUsed;
102 if (bhsd.isDelta()) {
103 final long cardinality = bhsd.cardinality();
104 while (value > bhsd.largest()) {
105 value -= cardinality;
106 }
107 while (value < bhsd.smallest()) {
108 value = ExactMath.add(value, cardinality);
109 }
110 }
111 }
112 return value;
113 }
114
115 private void normalise(final int[] band, final Codec codecUsed) {
116 if (codecUsed instanceof BHSDCodec) {
117 final BHSDCodec bhsd = (BHSDCodec) codecUsed;
118 if (bhsd.isDelta()) {
119 final long cardinality = bhsd.cardinality();
120 for (int i = 0; i < band.length; i++) {
121 while (band[i] > bhsd.largest()) {
122 band[i] -= cardinality;
123 }
124 while (band[i] < bhsd.smallest()) {
125 band[i] = ExactMath.add(band[i], cardinality);
126 }
127 }
128 }
129 } else if (codecUsed instanceof PopulationCodec) {
130 final PopulationCodec popCodec = (PopulationCodec) codecUsed;
131 final int[] favoured = popCodec.getFavoured().clone();
132 Arrays.sort(favoured);
133 for (int i = 0; i < band.length; i++) {
134 final boolean favouredValue = Arrays.binarySearch(favoured, band[i]) > -1;
135 final Codec theCodec = favouredValue ? popCodec.getFavouredCodec() : popCodec.getUnfavouredCodec();
136 if (theCodec instanceof BHSDCodec) {
137 final BHSDCodec bhsd = (BHSDCodec) theCodec;
138 if (bhsd.isDelta()) {
139 final long cardinality = bhsd.cardinality();
140 while (band[i] > bhsd.largest()) {
141 band[i] -= cardinality;
142 }
143 while (band[i] < bhsd.smallest()) {
144 band[i] = ExactMath.add(band[i], cardinality);
145 }
146 }
147 }
148 }
149 }
150 }
151
152 @Override
153 public String toString() {
154 return "RunCodec[k=" + k + ";aCodec=" + aCodec + "bCodec=" + bCodec + "]";
155 }
156 }