1 package edu.iris.dmc.seedcodec;
2
3
4
5 /***
6 * Class for decoding or encoding Steim2-compressed data blocks
7 * to or from an array of integer values.
8 * <p>
9 * Steim compression scheme Copyrighted by Dr. Joseph Steim.<p>
10 * <dl>
11 * <dt>Reference material found in:</dt>
12 * <dd>
13 * Appendix B of SEED Reference Manual, 2nd Ed., pp. 119-125
14 * <i>Federation of Digital Seismic Networks, et al.</i>
15 * February, 1993
16 * </dd>
17 * <dt>Coding concepts gleaned from code written by:</dt>
18 * <dd>Guy Stewart, IRIS, 1991</dd>
19 * <dd>Tom McSweeney, IRIS, 2000</dd>
20 * </dl>
21 *
22 * @author Philip Crotwell (U South Carolina)
23 * @author Robert Casey (IRIS DMC)
24 * @version 10/23/2002
25 */
26
27 public class Steim2 {
28
29 /***
30 * Decode the indicated number of samples from the provided byte array and
31 * return an integer array of the decompressed values. Being differencing
32 * compression, there may be an offset carried over from a previous data
33 * record. This offset value can be placed in <b>bias</b>, otherwise leave
34 * the value as 0.
35 * @param b input byte array to be decoded
36 * @param numSamples the number of samples that can be decoded from array
37 * <b>b</b>
38 * @param swapBytes if true, swap reverse the endian-ness of the elements of
39 * byte array <b>b</b>.
40 * @param bias the first difference value will be computed from this value.
41 * If set to 0, the method will attempt to use the X(0) constant instead.
42 * @return int array of length <b>numSamples</b>.
43 * @throws SteimException - encoded data length is not multiple of 64
44 * bytes.
45 */
46 public static int[] decode(byte[] b, int numSamples, boolean swapBytes, int bias) throws SteimException {
47 if (b.length % 64 != 0) {
48 throw new SteimException("encoded data length is not multiple of 64 bytes (" + b.length + ")");
49 }
50 int[] samples = new int[numSamples];
51 int[] tempSamples;
52 int numFrames = b.length / 64;
53 int current = 0;
54 int start=0, end=0;
55 int firstData=0;
56 int lastValue = 0;
57
58
59 for (int i=0; i< numFrames; i++ ) {
60
61 tempSamples = extractSamples(b, i*64, swapBytes);
62 firstData = 0;
63 if (i==0) {
64 lastValue = bias;
65
66 start = tempSamples[1];
67 end = tempSamples[2];
68 firstData = 3;
69
70
71 if (bias == 0) lastValue = start - tempSamples[3];
72 }
73
74 for (int j = firstData; j < tempSamples.length && current < numSamples; j++) {
75 samples[current] = lastValue + tempSamples[j];
76 lastValue = samples[current];
77
78 current++;
79 }
80
81 }
82 if (current != numSamples) {
83 throw new SteimException("Number of samples decompressed doesn't match number in header: "+current+" != "+numSamples);
84 }
85 return samples;
86 }
87
88 /***
89 * Abbreviated, zero-bias version of decode().
90 *
91 * @see edu.iris.Fissures.codec.Steim2#decode(byte[],int,boolean,int)
92 */
93 public static int[] decode(byte[] b, int numSamples, boolean swapBytes) throws SteimException {
94
95 return decode(b,numSamples,swapBytes,0);
96 }
97
98 public static byte[] encode(int[] samples) {
99 byte[] b = new byte[0];
100 return b;
101 }
102
103 /***
104 * Extracts differences from the next 64 byte frame of the given compressed
105 * byte array (starting at offset) and returns those differences in an int
106 * array.
107 * An offset of 0 means that we are at the first frame, so include the header
108 * bytes in the returned int array...else, do not include the header bytes
109 * in the returned array.
110 * @param bytes byte array of compressed data differences
111 * @param offset index to begin reading compressed bytes for decoding
112 * @param swapBytes reverse the endian-ness of the compressed bytes being read
113 * @return integer array of difference (and constant) values
114 */
115 protected static int[] extractSamples(byte[] bytes,
116 int offset,
117 boolean swapBytes)
118 {
119
120 int nibbles = Utility.bytesToInt(bytes[offset],
121 bytes[offset+1],
122 bytes[offset+2],
123 bytes[offset+3],
124 swapBytes);
125 int currNibble = 0;
126 int dnib = 0;
127 int[] temp = new int[106];
128 int tempInt;
129 int currNum = 0;
130 for (int i=0; i<16; i++) {
131 currNibble = (nibbles >> (30 - i*2 ) ) & 0x03;
132 switch (currNibble) {
133 case 0:
134
135
136 if (offset == 0) {
137 temp[currNum++] = Utility.bytesToInt(bytes[offset+(i*4)],
138 bytes[offset+(i*4)+1],
139 bytes[offset+(i*4)+2],
140 bytes[offset+(i*4)+3],
141 swapBytes);
142 }
143 break;
144 case 1:
145
146 temp[currNum++] = Utility.bytesToInt(bytes[offset+(i*4)]);
147 temp[currNum++] = Utility.bytesToInt(bytes[offset+(i*4)+1]);
148 temp[currNum++] = Utility.bytesToInt(bytes[offset+(i*4)+2]);
149 temp[currNum++] = Utility.bytesToInt(bytes[offset+(i*4)+3]);
150 break;
151 case 2:
152 tempInt = Utility.bytesToInt(bytes[offset+(i*4)],
153 bytes[offset+(i*4)+1],
154 bytes[offset+(i*4)+2],
155 bytes[offset+(i*4)+3],
156 swapBytes);
157 dnib = (tempInt >> 30) & 0x03;
158 switch (dnib) {
159 case 1:
160
161 temp[currNum++] = (tempInt << 2) >> 2;
162 break;
163 case 2:
164
165 temp[currNum++] = (tempInt << 2) >> 17;
166 temp[currNum++] = (tempInt << 17) >> 17;
167 break;
168 case 3:
169
170 temp[currNum++] = (tempInt << 2) >> 22;
171 temp[currNum++] = (tempInt << 12) >> 22;
172 temp[currNum++] = (tempInt << 22) >> 22;
173 break;
174 default:
175
176 }
177 break;
178 case 3:
179 tempInt = Utility.bytesToInt(bytes[offset+(i*4)],
180 bytes[offset+(i*4)+1],
181 bytes[offset+(i*4)+2],
182 bytes[offset+(i*4)+3],
183 swapBytes);
184 dnib = (tempInt >> 30) & 0x03;
185
186
187 int diffCount = 0;
188 int bitSize = 0;
189 int headerSize = 0;
190 switch (dnib) {
191 case 0:
192
193 headerSize = 2;
194 diffCount = 5;
195 bitSize = 6;
196 break;
197 case 1:
198
199 headerSize = 2;
200 diffCount = 6;
201 bitSize = 5;
202 break;
203 case 2:
204
205 headerSize = 4;
206 diffCount = 7;
207 bitSize = 4;
208 break;
209 default:
210
211 }
212 if (diffCount > 0) {
213 for (int d=0; d<diffCount; d++) {
214 temp[currNum++] = ( tempInt << (headerSize+(d*bitSize)) ) >> (((diffCount-1)*bitSize) + headerSize);
215 }
216 }
217 }
218 }
219 int[] out = new int[currNum];
220 System.arraycopy(temp, 0, out, 0, currNum);
221 return out;
222 }
223
224 /***
225 * Static method for testing the decode() method.
226 * @param args not used
227 * @throws SteimException from called method(s)
228 */
229 public static void main(String[] args) throws SteimException {
230 byte[] b = new byte[64];
231 int[] temp;
232
233 for (int i=0; i< 64 ; i++) {
234 b[i] = 0x00;
235 }
236 b[0] = 0x01;
237 b[1] = (byte)0xb0;
238 System.out.println(b[1]);
239 b[2] = (byte)0xff;
240 b[3] = (byte)0xff;
241
242 b[4] = 0;
243 b[5] = 0;
244 b[6] = 0;
245 b[7] = 0;
246
247 b[8] = 0;
248 b[9] = 0;
249 b[10] = 0;
250 b[11] = 0;
251
252 b[12] = 1;
253 b[13] = 2;
254 b[14] = 3;
255 b[15] = 0;
256
257 b[16] = 1;
258 b[17] = 1;
259 b[18] = 0;
260 b[19] = 0;
261
262 b[20] = 0;
263 b[21] = 1;
264 b[22] = 0;
265 b[23] = 0;
266 temp = Steim2.decode(b, 17, false);
267 }
268
269 }