001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026: package com.sun.kvem.jsr082.obex;
027:
028: import java.util.Calendar;
029: import java.util.Vector;
030: import java.io.IOException;
031: import java.io.UnsupportedEncodingException;
032:
033: public class QueuedHeader {
034:
035: /** Debug information, should be false for RR. */
036: private static final boolean DEBUG = false;
037:
038: private ObexPacketStream stream;
039: private int type;
040: private Object value;
041: byte[] buffer;
042: int packetLength;
043:
044: QueuedHeader(ObexPacketStream stream) {
045: this .stream = stream;
046: }
047:
048: /**
049: *
050: * @param type
051: * @param value
052: * @throws IOException
053: */
054: void sendOrQueue(int type, Object value) throws IOException {
055: if (stream.moreHeaders && send(type, value)) {
056: stream.challengesToSend = true;
057: return;
058: }
059: queue(type, value);
060: }
061:
062: /**
063: * Adds the header to queue in ObexPacketStream.
064: * @param type header's type defined in <code>HeaderSetImpl<code> class.
065: * @param value header's value.
066: * @throws IOException thrown if the header is too large.
067: */
068: void queue(int type, Object value) throws IOException {
069: int maxSendLength = stream.maxSendLength;
070: boolean fail = false;
071:
072: switch (HeaderSetImpl.internalType(type)) {
073: // ids which require special handling
074: case HeaderSetImpl.TYPE_SPECIAL_TIME_ISO:
075: case HeaderSetImpl.TYPE_SPECIAL_TIME_4:
076: case HeaderSetImpl.TYPE_LONG:
077: case HeaderSetImpl.TYPE_BYTE:
078: break;
079:
080: case HeaderSetImpl.TYPE_SPECIAL_TYPE:
081: // type8 + len16 + head + len16 + bytes[length] + zero8
082: if (((String) value).length() + 7 > maxSendLength) {
083: fail = true;
084: }
085: break;
086:
087: case HeaderSetImpl.TYPE_UNICODE:
088: // type8 + len16 + head + len16 + bytes[length] + zero16
089: if ((((String) value).length() << 1) + 8 > maxSendLength) {
090: fail = true;
091: }
092: break;
093:
094: case HeaderSetImpl.TYPE_BYTEARRAY:
095: // type8 + len16 + head + len16 + bytes[length]
096: if (((byte[]) value).length + 6 > maxSendLength) {
097: fail = true;
098: }
099: break;
100:
101: case HeaderSetImpl.TYPE_AUTH_CHALLENGE:
102: Vector challenges = (Vector) value;
103: if (challenges.isEmpty())
104: return;
105: int len = 0;
106: for (int i = 0; i < challenges.size(); i++) {
107: len += ((ObexAuth) challenges.elementAt(i))
108: .prepareChallenge();
109: }
110: if (len + 3 > maxSendLength) {
111: fail = true;
112: }
113: break;
114: }
115:
116: if (fail) {
117: stream.headerTooLarge();
118: return;
119: }
120: this .type = type;
121: this .value = value;
122: newHeader();
123: }
124:
125: boolean trySendAgain() throws IOException {
126: return send(type, value);
127: }
128:
129: boolean send(int type, Object value) throws IOException {
130: buffer = stream.buffer;
131: packetLength = stream.packetLength;
132: int maxSendLength = stream.maxSendLength;
133: if (DEBUG) {
134: System.out.println("Sending header 0x"
135: + Integer.toHexString(type));
136: }
137:
138: try {
139: buffer[packetLength++] = (byte) type;
140: switch (HeaderSetImpl.internalType(type)) {
141: // ids which require special handling
142: case HeaderSetImpl.TYPE_SPECIAL_TIME_ISO:
143: encodeTime8601((Calendar) value);
144: break;
145:
146: case HeaderSetImpl.TYPE_SPECIAL_TIME_4:
147: encodeInt(((Calendar) value).getTime().getTime() / 1000L);
148: break;
149:
150: case HeaderSetImpl.TYPE_SPECIAL_TYPE:
151: byte[] str = ((String) value).getBytes("ISO-8859-1");
152:
153: // head + len16 + bytes[length] + zero8
154: encodeLength16(str.length + 4);
155: System.arraycopy(str, 0, buffer, packetLength,
156: str.length);
157: packetLength += str.length;
158: // null terminator required by protocol spec
159: buffer[packetLength++] = 0;
160: break;
161:
162: case HeaderSetImpl.TYPE_AUTH_CHALLENGE:
163: packetLength--;
164: Vector challenges = (Vector) value;
165:
166: stream.authFailed = false;
167:
168: for (int i = 0; i < challenges.size(); i++) {
169: ObexAuth auth = (ObexAuth) challenges.elementAt(i);
170: packetLength += auth.addChallenge(buffer,
171: packetLength);
172: }
173:
174: // need to be shure - challenges are added
175: if (packetLength > maxSendLength) {
176: break;
177: }
178:
179: // if we still there, then authChallenges
180: // successfully added
181: for (int i = 0; i < challenges.size(); i++) {
182: stream.authFailed = true;
183: stream.authChallenges.addElement(challenges
184: .elementAt(i));
185: }
186: break;
187:
188: // normal ids
189:
190: // 4 byte integer values, range (0xC0 - 0xFF)
191: // system and user defined
192: case HeaderSetImpl.TYPE_LONG:
193: encodeInt(((Long) value).longValue());
194: break;
195:
196: // unicode encoded string values, range (0x00 - 0x3F)
197: // system and user defined
198: case HeaderSetImpl.TYPE_UNICODE:
199: str = ((String) value).getBytes("UTF-16BE");
200: // str = ((String)value).getBytes("ISO-8859-1");
201:
202: // head + len16 + bytes[length] + zero16
203: encodeLength16(str.length + 5);
204: System.arraycopy(str, 0, buffer, packetLength,
205: str.length);
206: packetLength += str.length;
207: // end of unicode string
208: buffer[packetLength++] = 0;
209: buffer[packetLength++] = 0;
210: break;
211:
212: // byte[] array values, range (0x40 - 0x7F)
213: // system and user defined
214: case HeaderSetImpl.TYPE_BYTEARRAY:
215: byte[] array = (byte[]) value;
216:
217: // head + len16 + bytes[length]
218: encodeLength16(array.length + 3);
219: System.arraycopy(array, 0, buffer, packetLength,
220: array.length);
221: packetLength += array.length;
222: stream.containsTargetHeader |= (type == HeaderSetImpl.TARGET);
223: break;
224:
225: // byte values, range (0x80 - 0xBF)
226: // user defined
227: case HeaderSetImpl.TYPE_BYTE:
228: buffer[packetLength++] = (byte) ((Byte) value)
229: .byteValue();
230: break;
231:
232: // case HeaderSetImpl.TYPE_UNSUPPORTED:
233: default:
234: if (DEBUG) {
235: System.out.println("wrong or unsupported header");
236: }
237: }
238: } catch (UnsupportedEncodingException e) {
239: throw new RuntimeException(e.toString());
240: } catch (ArrayIndexOutOfBoundsException e) {
241: stream.moreHeaders = false;
242: return false;
243: }
244: if (packetLength > maxSendLength) {
245: stream.moreHeaders = false;
246: return false;
247: }
248:
249: // finally closing body headers if opened
250: if (stream.dataOpened) {
251: int dataOffset = stream.dataOffset;
252: int len = stream.packetLength - dataOffset;
253: buffer[dataOffset + 1] = (byte) (len >> 8);
254: buffer[dataOffset + 2] = (byte) len;
255: stream.dataOpened = false;
256: stream.dataClosed = true;
257: }
258: stream.packetLength = packetLength;
259:
260: // gc header value
261: this .value = null;
262: if (DEBUG) {
263: System.out.println(" -> sent!");
264: }
265: return true;
266: }
267:
268: private void newHeader() {
269: stream.queuedHeaders.addElement(this );
270: if (stream.emptyHeadersPool.empty()) {
271: stream.newHeader = new QueuedHeader(stream);
272: } else {
273: stream.newHeader = (QueuedHeader) stream.emptyHeadersPool
274: .pop();
275: }
276: }
277:
278: boolean sendAllQueued() throws IOException {
279: while (stream.queuedHeaders.size() > 0 && stream.moreHeaders) {
280: QueuedHeader header = (QueuedHeader) stream.queuedHeaders
281: .firstElement();
282: boolean res = header.trySendAgain();
283: if (!res) {
284: return false;
285: }
286: stream.queuedHeaders.removeElementAt(0);
287: }
288: return true;
289: }
290:
291: private final void encodeInt(long val) {
292: buffer[packetLength++] = (byte) (val >> 24);
293: buffer[packetLength++] = (byte) (val >> 16);
294: buffer[packetLength++] = (byte) (val >> 8);
295: buffer[packetLength++] = (byte) val;
296: }
297:
298: private final void encodeLength16(int value) {
299: buffer[packetLength++] = (byte) (value >> 8);
300: buffer[packetLength++] = (byte) value;
301: }
302:
303: private final void encodeTime8601(Calendar cal) {
304: encodeLength16(19);
305:
306: // copy calendar as it can be with wrong timezone.
307: Calendar cal2 = Calendar
308: .getInstance(ObexPacketStream.utcTimeZone);
309: cal2.setTime(cal.getTime());
310: int year = cal2.get(Calendar.YEAR);
311: int month = cal2.get(Calendar.MONTH) + 1; // Calendar.JANUARY = 0
312: int date = cal2.get(Calendar.DATE);
313: int hour = cal2.get(Calendar.HOUR_OF_DAY);
314: int minute = cal2.get(Calendar.MINUTE);
315: int second = cal2.get(Calendar.SECOND);
316: int zero = 0x30; // zero ('0') code in latin1
317:
318: if (year < 0 || year > 9999) {
319: if (DEBUG) {
320: System.out.println("wrong date header");
321: }
322: }
323: buffer[packetLength++] = (byte) (year / 1000 + zero);
324: year = year % 1000;
325: buffer[packetLength++] = (byte) (year / 100 + zero);
326: year = year % 100;
327: buffer[packetLength++] = (byte) (year / 10 + zero);
328: year = year % 10;
329: buffer[packetLength++] = (byte) (year + zero);
330: buffer[packetLength++] = (byte) (month / 10 + zero);
331: buffer[packetLength++] = (byte) (month % 10 + zero);
332: buffer[packetLength++] = (byte) (date / 10 + zero);
333: buffer[packetLength++] = (byte) (date % 10 + zero);
334: buffer[packetLength++] = 0x54; // 'T' code in latin1
335: buffer[packetLength++] = (byte) (hour / 10 + zero);
336: buffer[packetLength++] = (byte) (hour % 10 + zero);
337: buffer[packetLength++] = (byte) (minute / 10 + zero);
338: buffer[packetLength++] = (byte) (minute % 10 + zero);
339: buffer[packetLength++] = (byte) (second / 10 + zero);
340: buffer[packetLength++] = (byte) (second % 10 + zero);
341: buffer[packetLength++] = (byte) 0x5A; // 'Z' code in latin1
342: }
343: }
|