View Javadoc

1   package edu.iris.dmc.seedcodec;
2   
3   //import edu.iris.Fissures.seed.util.*;
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  		//System.err.println("DEBUG: number of samples: " + numSamples + ", number of frames: " + numFrames + ", byte array size: " + b.length);
59  		for (int i=0; i< numFrames; i++ ) {
60  			//System.err.println("DEBUG: start of frame " + i);
61  			tempSamples = extractSamples(b, i*64, swapBytes);   // returns only differences except for frame 0
62  			firstData = 0; // d(0) is byte 0 by default
63  			if (i==0) {   // special case for first frame
64  				lastValue = bias; // assign our X(-1)
65  				// x0 and xn are in 1 and 2 spots
66  				start = tempSamples[1];  // X(0) is byte 1 for frame 0
67  				end = tempSamples[2];    // X(n) is byte 2 for frame 0
68  				firstData = 3; // d(0) is byte 3 for frame 0
69  				//System.err.println("DEBUG: frame " + i + ", bias = " + bias + ", x(0) = " + start + ", x(n) = " + end);
70  				// if bias was zero, then we want the first sample to be X(0) constant
71  				if (bias == 0) lastValue = start - tempSamples[3];  // X(-1) = X(0) - d(0)
72  			}
73  			//System.err.print("DEBUG: ");
74  			for (int j = firstData; j < tempSamples.length && current < numSamples; j++) {
75  				samples[current] = lastValue + tempSamples[j];  // X(n) = X(n-1) + d(n)
76  				lastValue = samples[current];
77  				//System.err.print("d(" + (j-firstData) + ")" + tempSamples[j] + ", x(" + current + ")" + samples[current] + ";");
78  				current++;
79  			}
80  			//System.err.println("DEBUG: end of frame " + i);
81  		}  // end for each frame...
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  		// zero-bias version of decode
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 		/* get nibbles */
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]; // 7 samples * 15 long words + 1 nibble int
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 					//System.out.println("0 means header info");
135 					// only include header info if offset is 0
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 					//System.out.println("1 means 4 one byte differences");
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 							//System.out.println("2,1 means 1 thirty bit difference");
161 							temp[currNum++] = (tempInt << 2) >> 2;
162 							break;
163 						case 2:
164 							//System.out.println("2,2 means 2 fifteen bit differences");
165 							temp[currNum++] = (tempInt << 2) >> 17;  // d0
166 							temp[currNum++] = (tempInt << 17) >> 17; // d1
167 							break;
168 						case 3:
169 							//System.out.println("2,3 means 3 ten bit differences");
170 							temp[currNum++] = (tempInt << 2) >> 22;  // d0
171 							temp[currNum++] = (tempInt << 12) >> 22; // d1
172 							temp[currNum++] = (tempInt << 22) >> 22; // d2
173 							break;
174 						default:
175 							//System.out.println("default");
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 					// for case 3, we are going to use a for-loop formulation that
186 					// accomplishes the same thing as case 2, just less verbose.
187 					int diffCount = 0;  // number of differences
188 					int bitSize = 0;    // bit size
189 					int headerSize = 0; // number of header/unused bits at top
190 					switch (dnib) {
191 						case 0:
192 							//System.out.println("3,0 means 5 six bit differences");
193 							headerSize = 2;
194 							diffCount = 5;
195 							bitSize = 6;
196 							break;
197 						case 1:
198 							//System.out.println("3,1 means 6 five bit differences");
199 							headerSize = 2;
200 							diffCount = 6;
201 							bitSize = 5;
202 							break;
203 						case 2:
204 							//System.out.println("3,2 means 7 four bit differences, with 2 unused bits");
205 							headerSize = 4;
206 							diffCount = 7;
207 							bitSize = 4;
208 							break;
209 						default:
210 							//System.out.println("default");
211 					}
212 					if (diffCount > 0) {
213 						for (int d=0; d<diffCount; d++) {  // for-loop formulation
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 }