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