|
1 /* $Id: OSCByteArrayToJavaConverter.java,v 1.1.1.1 2006/11/13 14:47:22 modin Exp $ |
|
2 * Created on 28.10.2003 |
|
3 */ |
|
4 package com.illposed.osc.utility; |
|
5 |
|
6 import java.math.BigInteger; |
|
7 import java.util.Date; |
|
8 |
|
9 import com.illposed.osc.*; |
|
10 |
|
11 /** |
|
12 * @author cramakrishnan |
|
13 * |
|
14 * Copyright (C) 2003, C. Ramakrishnan / Auracle |
|
15 * All rights reserved. |
|
16 * |
|
17 * See license.txt (or license.rtf) for license information. |
|
18 */ |
|
19 public class OSCByteArrayToJavaConverter { |
|
20 |
|
21 byte[] bytes; |
|
22 int bytesLength; |
|
23 int streamPosition; |
|
24 |
|
25 private byte[] intBytes = new byte[4]; |
|
26 private byte[] floatBytes = new byte[4]; |
|
27 |
|
28 private byte[] secondBytes = new byte[8]; |
|
29 private byte[] picosecBytes = new byte[8]; |
|
30 |
|
31 /** |
|
32 * Helper object for converting from a byte array to Java objects |
|
33 */ |
|
34 /*public OSCByteArrayToJavaConverter() { |
|
35 super(); |
|
36 }*/ |
|
37 |
|
38 public OSCPacket convert(byte[] byteArray, int bytesLength) { |
|
39 bytes = byteArray; |
|
40 this.bytesLength = bytesLength; |
|
41 streamPosition = 0; |
|
42 if (isBundle()) |
|
43 return convertBundle(); |
|
44 else |
|
45 return convertMessage(); |
|
46 } |
|
47 |
|
48 private boolean isBundle() { |
|
49 // only need the first 7 to check if it is a bundle |
|
50 String bytesAsString = new String(bytes, 0, 7); |
|
51 return bytesAsString.startsWith("#bundle"); |
|
52 } |
|
53 |
|
54 private OSCBundle convertBundle() { |
|
55 // skip the "#bundle " stuff |
|
56 streamPosition = 8; |
|
57 Date timestamp = readTimeTag(); |
|
58 OSCBundle bundle = new OSCBundle(timestamp); |
|
59 OSCByteArrayToJavaConverter myConverter = new OSCByteArrayToJavaConverter(); |
|
60 while (streamPosition < bytesLength) { |
|
61 // recursively read through the stream and convert packets you find |
|
62 int packetLength = ((Integer) readInteger()).intValue(); |
|
63 byte[] packetBytes = new byte[packetLength]; |
|
64 //streamPosition++; |
|
65 System.arraycopy(bytes,streamPosition,packetBytes,0,packetLength); |
|
66 streamPosition+=packetLength; |
|
67 //for (int i = 0; i < packetLength; i++) |
|
68 // packetBytes[i] = bytes[streamPosition++]; |
|
69 OSCPacket packet = myConverter.convert(packetBytes, packetLength); |
|
70 bundle.addPacket(packet); |
|
71 } |
|
72 return bundle; |
|
73 } |
|
74 |
|
75 private OSCMessage convertMessage() { |
|
76 OSCMessage message = new OSCMessage(); |
|
77 message.setAddress(readString()); |
|
78 char[] types = readTypes(); |
|
79 if (null == types) { |
|
80 // we are done |
|
81 return message; |
|
82 } |
|
83 moveToFourByteBoundry(); |
|
84 for (int i = 0; i < types.length; i++) { |
|
85 if ('[' == types[i]) { |
|
86 // we're looking at an array -- read it in |
|
87 message.addArgument(readArray(types, i)); |
|
88 // then increment i to the end of the array |
|
89 while (']' != types[i]) |
|
90 i++; |
|
91 } else |
|
92 message.addArgument(readArgument(types[i])); |
|
93 } |
|
94 return message; |
|
95 } |
|
96 |
|
97 private String readString() { |
|
98 int strLen = lengthOfCurrentString(); |
|
99 char[] stringChars = new char[strLen]; |
|
100 //System.arraycopy(bytes,streamPosition,stringChars,0,strLen); |
|
101 //streamPosition+=strLen; |
|
102 for (int i = 0; i < strLen; i++) |
|
103 stringChars[i] = (char) bytes[streamPosition++]; |
|
104 moveToFourByteBoundry(); |
|
105 return new String(stringChars); |
|
106 } |
|
107 |
|
108 /** |
|
109 * @return a char array with the types of the arguments |
|
110 */ |
|
111 private char[] readTypes() { |
|
112 // the next byte should be a "," |
|
113 if (bytes[streamPosition] != 0x2C) |
|
114 return null; |
|
115 streamPosition++; |
|
116 // find out how long the list of types is |
|
117 int typesLen = lengthOfCurrentString(); |
|
118 if (0 == typesLen) { |
|
119 return null; |
|
120 } |
|
121 // read in the types |
|
122 char[] typesChars = new char[typesLen]; |
|
123 for (int i = 0; i < typesLen; i++) { |
|
124 typesChars[i] = (char) bytes[streamPosition++]; |
|
125 } |
|
126 return typesChars; |
|
127 } |
|
128 |
|
129 /** |
|
130 * @param c type of argument |
|
131 * @return a Java representation of the argument |
|
132 */ |
|
133 private Object readArgument(char c) { |
|
134 switch (c) { |
|
135 case 'i' : |
|
136 return readInteger(); |
|
137 case 'h' : |
|
138 return readBigInteger(); |
|
139 case 'f' : |
|
140 return readFloat(); |
|
141 case 'd' : |
|
142 return readDouble(); |
|
143 case 's' : |
|
144 return readString(); |
|
145 case 'c' : |
|
146 return readChar(); |
|
147 case 'T' : |
|
148 return Boolean.TRUE; |
|
149 case 'F' : |
|
150 return Boolean.FALSE; |
|
151 } |
|
152 |
|
153 return null; |
|
154 } |
|
155 |
|
156 /** |
|
157 * @return a Character |
|
158 */ |
|
159 private Object readChar() { |
|
160 return new Character((char) bytes[streamPosition++]); |
|
161 } |
|
162 |
|
163 /** |
|
164 * @return a Double |
|
165 */ |
|
166 private Object readDouble() { |
|
167 return readFloat(); |
|
168 } |
|
169 |
|
170 /** |
|
171 * @return a Float |
|
172 */ |
|
173 private Object readFloat() { |
|
174 //byte[] floatBytes = new byte[4]; |
|
175 floatBytes[0] = bytes[streamPosition++]; |
|
176 floatBytes[1] = bytes[streamPosition++]; |
|
177 floatBytes[2] = bytes[streamPosition++]; |
|
178 floatBytes[3] = bytes[streamPosition++]; |
|
179 |
|
180 int floatBits = |
|
181 ((floatBytes[3] & 0xFF) ) + |
|
182 ((floatBytes[2] & 0xFF) << 8) + |
|
183 ((floatBytes[1] & 0xFF) << 16) + |
|
184 ((floatBytes[0] & 0xFF) << 24); |
|
185 |
|
186 return new Float(Float.intBitsToFloat(floatBits)); |
|
187 } |
|
188 |
|
189 /** |
|
190 * @return a BigInteger |
|
191 */ |
|
192 private Object readBigInteger() { |
|
193 //byte[] intBytes = new byte[4]; |
|
194 intBytes[0] = bytes[streamPosition++]; |
|
195 intBytes[1] = bytes[streamPosition++]; |
|
196 intBytes[2] = bytes[streamPosition++]; |
|
197 intBytes[3] = bytes[streamPosition++]; |
|
198 |
|
199 int intBits = |
|
200 ((intBytes[3] & 0xFF) ) + |
|
201 ((intBytes[2] & 0xFF) << 8) + |
|
202 ((intBytes[1] & 0xFF) << 16) + |
|
203 ((intBytes[0] & 0xFF) << 24); |
|
204 |
|
205 return new Integer(intBits); |
|
206 } |
|
207 |
|
208 /** |
|
209 * @return an Integer |
|
210 */ |
|
211 private Object readInteger() { |
|
212 //byte[] intBytes = new byte[4]; |
|
213 intBytes[0] = bytes[streamPosition++]; |
|
214 intBytes[1] = bytes[streamPosition++]; |
|
215 intBytes[2] = bytes[streamPosition++]; |
|
216 intBytes[3] = bytes[streamPosition++]; |
|
217 |
|
218 int intBits = |
|
219 ((intBytes[3] & 0xFF) ) + |
|
220 ((intBytes[2] & 0xFF) << 8) + |
|
221 ((intBytes[1] & 0xFF) << 16) + |
|
222 ((intBytes[0] & 0xFF) << 24); |
|
223 |
|
224 return new Integer(intBits); |
|
225 } |
|
226 |
|
227 /** |
|
228 * @return a Date |
|
229 */ |
|
230 private Date readTimeTag() { |
|
231 //byte[] secondBytes = new byte[8]; |
|
232 //byte[] picosecBytes = new byte[8]; |
|
233 /*for (int i = 4; i < 8; i++) |
|
234 secondBytes[i] = bytes[streamPosition++]; |
|
235 for (int i = 4; i < 8; i++) |
|
236 picosecBytes[i] = bytes[streamPosition++];*/ |
|
237 System.arraycopy(bytes,streamPosition,secondBytes,4,4); |
|
238 streamPosition+=4; |
|
239 System.arraycopy(bytes,streamPosition,picosecBytes,4,4); |
|
240 streamPosition+=4; |
|
241 |
|
242 BigInteger secsSince1900 = new BigInteger(secondBytes); |
|
243 long secsSince1970 = secsSince1900.longValue() - OSCBundle.SECONDS_FROM_1900_to_1970.longValue(); |
|
244 if (secsSince1970 < 0) secsSince1970 = 0; // no point maintaining times in the distant past |
|
245 BigInteger picosecs = new BigInteger(picosecBytes); |
|
246 long millisecs = (secsSince1970 * 1000) + (picosecs.longValue() / 1000); |
|
247 return new Date(millisecs); |
|
248 } |
|
249 |
|
250 /** |
|
251 * @param types |
|
252 * @param i |
|
253 * @return an Array |
|
254 */ |
|
255 private Object[] readArray(char[] types, int i) { |
|
256 int arrayLen = 0; |
|
257 while (types[i + arrayLen] != ']') |
|
258 arrayLen++; |
|
259 Object[] array = new Object[arrayLen]; |
|
260 for (int j = 0; i < arrayLen; j++) { |
|
261 array[j] = readArgument(types[i + j]); |
|
262 } |
|
263 return array; |
|
264 } |
|
265 |
|
266 private int lengthOfCurrentString() { |
|
267 int i = 0; |
|
268 while (bytes[streamPosition + i] != 0) |
|
269 i++; |
|
270 return i; |
|
271 } |
|
272 |
|
273 private void moveToFourByteBoundry() { |
|
274 // If i'm already at a 4 byte boundry, I need to move to the next one |
|
275 int mod = streamPosition % 4; |
|
276 streamPosition += (4 - mod); |
|
277 } |
|
278 |
|
279 } |
|
280 |