19439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly/*
28949bfb90c415629dbd0e30d25003fb3e0375fb5Hemant Gupta * Copyright (C) 2014 The Android Open Source Project
39439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Copyright (c) 2008-2009, Motorola, Inc.
49439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
59439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * All rights reserved.
69439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
79439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Redistribution and use in source and binary forms, with or without
89439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * modification, are permitted provided that the following conditions are met:
99439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * - Redistributions of source code must retain the above copyright notice,
119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * this list of conditions and the following disclaimer.
129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * - Redistributions in binary form must reproduce the above copyright notice,
149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * this list of conditions and the following disclaimer in the documentation
159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * and/or other materials provided with the distribution.
169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * - Neither the name of the Motorola, Inc. nor the names of its contributors
189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * may be used to endorse or promote products derived from this software
199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * without specific prior written permission.
209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * POSSIBILITY OF SUCH DAMAGE.
329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */
339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellypackage javax.obex;
359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
362e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellyimport java.io.ByteArrayOutputStream;
372e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellyimport java.io.IOException;
382e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellyimport java.io.UnsupportedEncodingException;
39929a1c219248b62778807cac8ea256c7ac0fda6aBrian Carlstromimport java.security.MessageDigest;
40929a1c219248b62778807cac8ea256c7ac0fda6aBrian Carlstromimport java.security.NoSuchAlgorithmException;
412e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellyimport java.util.Calendar;
422e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellyimport java.util.Date;
432e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellyimport java.util.TimeZone;
449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly/**
462e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * This class defines a set of helper methods for the implementation of Obex.
472e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @hide
489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */
492e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellypublic final class ObexHelper {
502e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly
519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
5205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Defines the basic packet length used by OBEX. Every OBEX packet has the
533998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun     * same basic format:<BR>
5405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Byte 0: Request or Response Code Byte 1&2: Length of the packet.
559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
563998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int BASE_PACKET_LENGTH = 3;
573998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
583998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    /** Prevent object construction of helper class */
593998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private ObexHelper() {
603998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    }
619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
622e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly    /**
6305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * The maximum packet size for OBEX packets that this client can handle. At
6405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * present, this must be changed for each port. TODO: The max packet size
6505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * should be the Max incoming MTU minus TODO: L2CAP package headers and
6605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * RFCOMM package headers. TODO: Retrieve the max incoming MTU from TODO:
6705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * LocalDevice.getProperty().
682e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     */
6905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun    /*
7005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * android note set as 0xFFFE to match remote MPS
712e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     */
722e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly    public static final int MAX_PACKET_SIZE_INT = 0xFFFE;
739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
74e83b744d7d0b3caaf8f5456b795331d5db2495a3Erik Ljungberg    /**
75e83b744d7d0b3caaf8f5456b795331d5db2495a3Erik Ljungberg     * Temporary workaround to be able to push files to Windows 7.
76e83b744d7d0b3caaf8f5456b795331d5db2495a3Erik Ljungberg     * TODO: Should be removed as soon as Microsoft updates their driver.
77e83b744d7d0b3caaf8f5456b795331d5db2495a3Erik Ljungberg     */
78e83b744d7d0b3caaf8f5456b795331d5db2495a3Erik Ljungberg    public static final int MAX_CLIENT_PACKET_SIZE = 0xFC00;
79e83b744d7d0b3caaf8f5456b795331d5db2495a3Erik Ljungberg
803998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_CONNECT = 0x80;
813998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
823998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_DISCONNECT = 0x81;
833998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
843998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_PUT = 0x02;
853998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
863998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_PUT_FINAL = 0x82;
873998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
883998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_GET = 0x03;
893998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
903998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_GET_FINAL = 0x83;
913998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
923998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_RESERVED = 0x04;
933998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
943998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_RESERVED_FINAL = 0x84;
953998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
963998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_SETPATH = 0x85;
973998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
983998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_ABORT = 0xFF;
993998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1003998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ASCII = 0x00;
1013998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1023998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_1 = 0x01;
1033998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1043998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_2 = 0x02;
1053998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1063998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_3 = 0x03;
1073998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1083998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_4 = 0x04;
1093998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1103998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_5 = 0x05;
1113998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1123998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_6 = 0x06;
1133998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1143998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_7 = 0x07;
1153998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1163998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_8 = 0x08;
1173998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1183998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_9 = 0x09;
1193998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1203998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_UNICODE = 0xFF;
1213998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
1239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Updates the HeaderSet with the headers received in the byte array
12405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * provided. Invalid headers are ignored.
1259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <P>
12605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * The first two bits of an OBEX Header specifies the type of object that is
12705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * being sent. The table below specifies the meaning of the high bits.
1289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <TABLE>
12905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TR>
13005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TH>Bits 8 and 7</TH>
13105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TH>Value</TH>
13205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TH>Description</TH>
13305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * </TR>
13405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TR>
13505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>00</TD>
13605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>0x00</TD>
13705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>Null Terminated Unicode text, prefixed with 2 byte unsigned integer</TD>
13805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * </TR>
13905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TR>
14005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>01</TD>
14105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>0x40</TD>
14205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>Byte Sequence, length prefixed with 2 byte unsigned integer</TD>
14305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * </TR>
14405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TR>
14505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>10</TD>
14605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>0x80</TD>
14705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>1 byte quantity</TD>
14805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * </TR>
14905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TR>
15005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>11</TD>
15105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>0xC0</TD>
15205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>4 byte quantity - transmitted in network byte order (high byte first</TD>
15305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * </TR>
1549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * </TABLE>
1559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * This method uses the information in this table to determine the type of
15605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Java object to create and passes that object with the full header to
15705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * setHeader() to update the HeaderSet object. Invalid headers will cause an
15805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * exception to be thrown. When it is thrown, it is ignored.
1599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param header the HeaderSet to update
1609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param headerArray the byte array containing headers
1619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the result of the last start body or end body header provided;
16205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         the first byte in the result will specify if a body or end of
16305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         body is received
1642e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if an invalid header was found
1659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
1669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static byte[] updateHeaderSet(HeaderSet header, byte[] headerArray) throws IOException {
1679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int index = 0;
1689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int length = 0;
1699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int headerID;
1709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] value = null;
1719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] body = null;
1729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        HeaderSet headerImpl = header;
1739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
1749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            while (index < headerArray.length) {
1759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                headerID = 0xFF & headerArray[index];
1769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                switch (headerID & (0xC0)) {
1779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    /*
1799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     * 0x00 is a unicode null terminate string with the first
1809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     * two bytes after the header identifier being the length
1819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     */
1829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    case 0x00:
1839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        // Fall through
1849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        /*
1859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                         * 0x40 is a byte sequence with the first
1869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                         * two bytes after the header identifier being the length
1879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                         */
1889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    case 0x40:
1899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        boolean trimTail = true;
1909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        index++;
1919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        length = 0xFF & headerArray[index];
1929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        length = length << 8;
1939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        index++;
1949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        length += 0xFF & headerArray[index];
1959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        length -= 3;
1969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        index++;
1979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        value = new byte[length];
1989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        System.arraycopy(headerArray, index, value, 0, length);
1999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        if (length == 0 || (length > 0 && (value[length - 1] != 0))) {
2009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            trimTail = false;
2019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        }
2029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        switch (headerID) {
2039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            case HeaderSet.TYPE:
2049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                try {
2059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    // Remove trailing null
2069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    if (trimTail == false) {
2079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                        headerImpl.setHeader(headerID, new String(value, 0,
2089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                                value.length, "ISO8859_1"));
2099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    } else {
2109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                        headerImpl.setHeader(headerID, new String(value, 0,
2119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                                value.length - 1, "ISO8859_1"));
2129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    }
2139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                } catch (UnsupportedEncodingException e) {
2143998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                    throw e;
2159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                }
2169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                break;
2179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2183998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                            case HeaderSet.AUTH_CHALLENGE:
2193998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                headerImpl.mAuthChall = new byte[length];
2203998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                System.arraycopy(headerArray, index, headerImpl.mAuthChall, 0,
2219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                        length);
2229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                break;
2239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2243998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                            case HeaderSet.AUTH_RESPONSE:
2253998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                headerImpl.mAuthResp = new byte[length];
2263998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                System.arraycopy(headerArray, index, headerImpl.mAuthResp, 0,
2273998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                        length);
2289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                break;
2299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2303998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                            case HeaderSet.BODY:
2319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                /* Fall Through */
2323998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                            case HeaderSet.END_OF_BODY:
2339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                body = new byte[length + 1];
2349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                body[0] = (byte)headerID;
2359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                System.arraycopy(headerArray, index, body, 1, length);
2369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                break;
2379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            case HeaderSet.TIME_ISO_8601:
2399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                try {
2409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    String dateString = new String(value, "ISO8859_1");
2419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    Calendar temp = Calendar.getInstance();
2429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    if ((dateString.length() == 16)
2439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                            && (dateString.charAt(15) == 'Z')) {
2449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                        temp.setTimeZone(TimeZone.getTimeZone("UTC"));
2459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    }
2469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    temp.set(Calendar.YEAR, Integer.parseInt(dateString.substring(
2479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                            0, 4)));
2489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    temp.set(Calendar.MONTH, Integer.parseInt(dateString.substring(
2499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                            4, 6)));
2509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    temp.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateString
2519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                            .substring(6, 8)));
2529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    temp.set(Calendar.HOUR_OF_DAY, Integer.parseInt(dateString
2539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                            .substring(9, 11)));
2549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    temp.set(Calendar.MINUTE, Integer.parseInt(dateString
2559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                            .substring(11, 13)));
2569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    temp.set(Calendar.SECOND, Integer.parseInt(dateString
2579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                            .substring(13, 15)));
2589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    headerImpl.setHeader(HeaderSet.TIME_ISO_8601, temp);
2599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                } catch (UnsupportedEncodingException e) {
2603998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                    throw e;
2619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                }
2629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                break;
2639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            default:
2653998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                if ((headerID & 0xC0) == 0x00) {
2663998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                    headerImpl.setHeader(headerID, ObexHelper.convertToUnicode(
2673998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                            value, true));
2683998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                } else {
2693998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                    headerImpl.setHeader(headerID, value);
2709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                }
2719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        }
2729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        index += length;
2749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        break;
2759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    /*
2779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     * 0x80 is a byte header.  The only valid byte headers are
2789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     * the 16 user defined byte headers.
2799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     */
2809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    case 0x80:
2819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        index++;
2829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        try {
2839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            headerImpl.setHeader(headerID, Byte.valueOf(headerArray[index]));
2849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        } catch (Exception e) {
2859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            // Not a valid header so ignore
2869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        }
2879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        index++;
2889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        break;
2899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    /*
2919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     * 0xC0 is a 4 byte unsigned integer header and with the
2929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     * exception of TIME_4_BYTE will be converted to a Long
2939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     * and added.
2949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     */
2959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    case 0xC0:
2969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        index++;
2979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        value = new byte[4];
2989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        System.arraycopy(headerArray, index, value, 0, 4);
2999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        try {
3009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            if (headerID != HeaderSet.TIME_4_BYTE) {
3019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                // Determine if it is a connection ID.  These
3029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                // need to be handled differently
3033998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                if (headerID == HeaderSet.CONNECTION_ID) {
3043998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                    headerImpl.mConnectionID = new byte[4];
3053998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                    System.arraycopy(value, 0, headerImpl.mConnectionID, 0, 4);
3069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                } else {
3079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    headerImpl.setHeader(headerID, Long
3089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                            .valueOf(convertToLong(value)));
3099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                }
3109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            } else {
3119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                Calendar temp = Calendar.getInstance();
3129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                temp.setTime(new Date(convertToLong(value) * 1000L));
3139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                headerImpl.setHeader(HeaderSet.TIME_4_BYTE, temp);
3149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            }
3159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        } catch (Exception e) {
3169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            // Not a valid header so ignore
3179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            throw new IOException("Header was not formatted properly");
3189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        }
3199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        index += 4;
3209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        break;
3219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
3249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } catch (IOException e) {
3259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            throw new IOException("Header was not formatted properly");
3269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
3279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return body;
3299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
3309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
3329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Creates the header part of OBEX packet based on the header provided.
33305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * TODO: Could use getHeaderList() to get the array of headers to include
33405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * and then use the high two bits to determine the the type of the object
33505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * and construct the byte array from that. This will make the size smaller.
3369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param head the header used to construct the byte array
3379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param nullOut <code>true</code> if the header should be set to
33805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        <code>null</code> once it is added to the array or
33905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        <code>false</code> if it should not be nulled out
3409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the header of an OBEX packet
3419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
3429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static byte[] createHeader(HeaderSet head, boolean nullOut) {
3439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        Long intHeader = null;
3449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        String stringHeader = null;
3459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        Calendar dateHeader = null;
3469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        Byte byteHeader = null;
3479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        StringBuffer buffer = null;
3489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] value = null;
3499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] result = null;
3509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] lengthArray = new byte[2];
3519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int length;
3529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        HeaderSet headImpl = null;
3539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        ByteArrayOutputStream out = new ByteArrayOutputStream();
3549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        headImpl = head;
3559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
3579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            /*
3589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             * Determine if there is a connection ID to send.  If there is,
3599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             * then it should be the first header in the packet.
3609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             */
3613998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            if ((headImpl.mConnectionID != null) && (headImpl.getHeader(HeaderSet.TARGET) == null)) {
3629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3633998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                out.write((byte)HeaderSet.CONNECTION_ID);
3643998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                out.write(headImpl.mConnectionID);
3659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
3669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Count Header
3689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            intHeader = (Long)headImpl.getHeader(HeaderSet.COUNT);
3699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (intHeader != null) {
3709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.COUNT);
3712e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                value = ObexHelper.convertToByteArray(intHeader.longValue());
3729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
3739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
3749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.COUNT, null);
3759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
3779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Name Header
3799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            stringHeader = (String)headImpl.getHeader(HeaderSet.NAME);
3809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (stringHeader != null) {
3819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.NAME);
3822e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                value = ObexHelper.convertToUnicodeByteArray(stringHeader);
3839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                length = value.length + 3;
3843998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                lengthArray[0] = (byte)(0xFF & (length >> 8));
3853998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                lengthArray[1] = (byte)(0xFF & length);
3869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
3879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
3889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
3899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.NAME, null);
3909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3918949bfb90c415629dbd0e30d25003fb3e0375fb5Hemant Gupta            } else if (headImpl.getEmptyNameHeader()) {
3928949bfb90c415629dbd0e30d25003fb3e0375fb5Hemant Gupta                out.write((byte) HeaderSet.NAME);
3938949bfb90c415629dbd0e30d25003fb3e0375fb5Hemant Gupta                lengthArray[0] = (byte) 0x00;
3948949bfb90c415629dbd0e30d25003fb3e0375fb5Hemant Gupta                lengthArray[1] = (byte) 0x03;
3958949bfb90c415629dbd0e30d25003fb3e0375fb5Hemant Gupta                out.write(lengthArray);
3969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
3979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Type Header
3999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            stringHeader = (String)headImpl.getHeader(HeaderSet.TYPE);
4009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (stringHeader != null) {
4019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.TYPE);
4029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                try {
4039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    value = stringHeader.getBytes("ISO8859_1");
4049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } catch (UnsupportedEncodingException e) {
4053998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    throw e;
4069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                length = value.length + 4;
4099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
4109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
4119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
4129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
4139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(0x00);
4149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
4159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.TYPE, null);
4169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
4189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Length Header
4209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            intHeader = (Long)headImpl.getHeader(HeaderSet.LENGTH);
4219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (intHeader != null) {
4229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.LENGTH);
4232e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                value = ObexHelper.convertToByteArray(intHeader.longValue());
4249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
4259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
4269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.LENGTH, null);
4279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
4299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Time ISO Header
4319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_ISO_8601);
4329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (dateHeader != null) {
4339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                /*
4359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * The ISO Header should take the form YYYYMMDDTHHMMSSZ.  The
4369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * 'Z' will only be included if it is a UTC time.
4379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 */
4389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                buffer = new StringBuffer();
4399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                int temp = dateHeader.get(Calendar.YEAR);
4409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                for (int i = temp; i < 1000; i = i * 10) {
4419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    buffer.append("0");
4429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                buffer.append(temp);
4449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                temp = dateHeader.get(Calendar.MONTH);
4459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (temp < 10) {
4469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    buffer.append("0");
4479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                buffer.append(temp);
4499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                temp = dateHeader.get(Calendar.DAY_OF_MONTH);
4509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (temp < 10) {
4519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    buffer.append("0");
4529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                buffer.append(temp);
4549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                buffer.append("T");
4559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                temp = dateHeader.get(Calendar.HOUR_OF_DAY);
4569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (temp < 10) {
4579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    buffer.append("0");
4589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                buffer.append(temp);
4609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                temp = dateHeader.get(Calendar.MINUTE);
4619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (temp < 10) {
4629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    buffer.append("0");
4639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                buffer.append(temp);
4659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                temp = dateHeader.get(Calendar.SECOND);
4669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (temp < 10) {
4679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    buffer.append("0");
4689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                buffer.append(temp);
4709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (dateHeader.getTimeZone().getID().equals("UTC")) {
4729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    buffer.append("Z");
4739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                try {
4769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    value = buffer.toString().getBytes("ISO8859_1");
4779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } catch (UnsupportedEncodingException e) {
4783998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    throw e;
4799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                length = value.length + 3;
4829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
4839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
4849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(HeaderSet.TIME_ISO_8601);
4859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
4869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
4879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
4889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.TIME_ISO_8601, null);
4899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
4919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Time 4 Byte Header
4939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_4_BYTE);
4949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (dateHeader != null) {
4959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(HeaderSet.TIME_4_BYTE);
4969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                /*
4989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * Need to call getTime() twice.  The first call will return
4999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * a java.util.Date object.  The second call returns the number
5009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * of milliseconds since January 1, 1970.  We need to convert
5019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * it to seconds since the TIME_4_BYTE expects the number of
5029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * seconds since January 1, 1970.
5039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 */
5042e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                value = ObexHelper.convertToByteArray(dateHeader.getTime().getTime() / 1000L);
5059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
5069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
5079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.TIME_4_BYTE, null);
5089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
5099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Description Header
5129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            stringHeader = (String)headImpl.getHeader(HeaderSet.DESCRIPTION);
5139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (stringHeader != null) {
5149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.DESCRIPTION);
5152e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                value = ObexHelper.convertToUnicodeByteArray(stringHeader);
5169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                length = value.length + 3;
5179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
5189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
5199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
5209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
5219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
5229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.DESCRIPTION, null);
5239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
5249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Target Header
5279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            value = (byte[])headImpl.getHeader(HeaderSet.TARGET);
5289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (value != null) {
5299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.TARGET);
5309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                length = value.length + 3;
5319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
5329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
5339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
5349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
5359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
5369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.TARGET, null);
5379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
5389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // HTTP Header
5419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            value = (byte[])headImpl.getHeader(HeaderSet.HTTP);
5429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (value != null) {
5439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.HTTP);
5449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                length = value.length + 3;
5459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
5469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
5479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
5489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
5499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
5509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.HTTP, null);
5519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
5529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Who Header
5559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            value = (byte[])headImpl.getHeader(HeaderSet.WHO);
5569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (value != null) {
5579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.WHO);
5589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                length = value.length + 3;
5599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
5609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
5619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
5629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
5639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
5649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.WHO, null);
5659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
5669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Connection ID Header
5699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            value = (byte[])headImpl.getHeader(HeaderSet.APPLICATION_PARAMETER);
5709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (value != null) {
5719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.APPLICATION_PARAMETER);
5729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                length = value.length + 3;
5739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
5749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
5759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
5769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
5779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
5789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.APPLICATION_PARAMETER, null);
5799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
5809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Object Class Header
5839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            value = (byte[])headImpl.getHeader(HeaderSet.OBJECT_CLASS);
5849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (value != null) {
5859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.OBJECT_CLASS);
5869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                length = value.length + 3;
5879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
5889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
5899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
5909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
5919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
5929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.OBJECT_CLASS, null);
5939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
5949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Check User Defined Headers
5979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            for (int i = 0; i < 16; i++) {
5989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                //Unicode String Header
6009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                stringHeader = (String)headImpl.getHeader(i + 0x30);
6019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (stringHeader != null) {
6029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    out.write((byte)i + 0x30);
6032e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                    value = ObexHelper.convertToUnicodeByteArray(stringHeader);
6049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    length = value.length + 3;
6059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    lengthArray[0] = (byte)(255 & (length >> 8));
6069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    lengthArray[1] = (byte)(255 & length);
6079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    out.write(lengthArray);
6089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    out.write(value);
6099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    if (nullOut) {
6109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        headImpl.setHeader(i + 0x30, null);
6119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
6129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
6139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                // Byte Sequence Header
6159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                value = (byte[])headImpl.getHeader(i + 0x70);
6169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (value != null) {
6179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    out.write((byte)i + 0x70);
6189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    length = value.length + 3;
6199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    lengthArray[0] = (byte)(255 & (length >> 8));
6209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    lengthArray[1] = (byte)(255 & length);
6219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    out.write(lengthArray);
6229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    out.write(value);
6239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    if (nullOut) {
6249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        headImpl.setHeader(i + 0x70, null);
6259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
6269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
6279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                // Byte Header
6299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                byteHeader = (Byte)headImpl.getHeader(i + 0xB0);
6309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (byteHeader != null) {
6319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    out.write((byte)i + 0xB0);
6329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    out.write(byteHeader.byteValue());
6339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    if (nullOut) {
6349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        headImpl.setHeader(i + 0xB0, null);
6359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
6369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
6379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                // Integer header
6399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                intHeader = (Long)headImpl.getHeader(i + 0xF0);
6409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (intHeader != null) {
6419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    out.write((byte)i + 0xF0);
6422e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                    out.write(ObexHelper.convertToByteArray(intHeader.longValue()));
6439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    if (nullOut) {
6449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        headImpl.setHeader(i + 0xF0, null);
6459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
6469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
6479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
6489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Add the authentication challenge header
6503998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            if (headImpl.mAuthChall != null) {
6513998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                out.write((byte)HeaderSet.AUTH_CHALLENGE);
6523998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                length = headImpl.mAuthChall.length + 3;
6539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
6549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
6559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
6563998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                out.write(headImpl.mAuthChall);
6579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
6583998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    headImpl.mAuthChall = null;
6599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
6609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
6619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Add the authentication response header
6633998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            if (headImpl.mAuthResp != null) {
6643998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                out.write((byte)HeaderSet.AUTH_RESPONSE);
6653998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                length = headImpl.mAuthResp.length + 3;
6669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
6679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
6689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
6693998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                out.write(headImpl.mAuthResp);
6709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
6713998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    headImpl.mAuthResp = null;
6729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
6739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
6749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } catch (IOException e) {
6769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } finally {
6779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            result = out.toByteArray();
6789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            try {
6799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.close();
6809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            } catch (Exception ex) {
6819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
6829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
6839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return result;
6859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
6879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
68905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Determines where the maximum divide is between headers. This method is
6909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * used by put and get operations to separate headers to a size that meets
6919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * the max packet size allowed.
6929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param headerArray the headers to separate
6939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param start the starting index to search
6949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param maxSize the maximum size of a packet
6959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the index of the end of the header block to send or -1 if the
69605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         header could not be divided because the header is too large
6979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
6989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static int findHeaderEnd(byte[] headerArray, int start, int maxSize) {
6999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int fullLength = 0;
7019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int lastLength = -1;
7029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int index = start;
7039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int length = 0;
7049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        while ((fullLength < maxSize) && (index < headerArray.length)) {
7069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            int headerID = (headerArray[index] < 0 ? headerArray[index] + 256 : headerArray[index]);
7079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            lastLength = fullLength;
7089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            switch (headerID & (0xC0)) {
7109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                case 0x00:
7129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // Fall through
7139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                case 0x40:
7149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    index++;
7169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    length = (headerArray[index] < 0 ? headerArray[index] + 256
7179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            : headerArray[index]);
7189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    length = length << 8;
7199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    index++;
7209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    length += (headerArray[index] < 0 ? headerArray[index] + 256
7219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            : headerArray[index]);
7229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    length -= 3;
7239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    index++;
7249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    index += length;
7259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    fullLength += length + 3;
7269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    break;
7279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                case 0x80:
7299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    index++;
7319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    index++;
7329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    fullLength += 2;
7339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    break;
7349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                case 0xC0:
7369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    index += 5;
7389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    fullLength += 5;
7399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    break;
7409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
7429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        /*
7469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Determine if this is the last header or not
7479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         */
7489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (lastLength == 0) {
7499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            /*
7509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             * Since this is the last header, check to see if the size of this
7519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             * header is less then maxSize.  If it is, return the length of the
7529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             * header, otherwise return -1.  The length of the header is
7539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             * returned since it would be the start of the next header
7549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             */
7559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (fullLength < maxSize) {
7569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                return headerArray.length;
7579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            } else {
7589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                return -1;
7599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
7609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
7619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return lastLength + start;
7629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
7649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
7669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Converts the byte array to a long.
7679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param b the byte array to convert to a long
7689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the byte array as a long
7699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
7709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static long convertToLong(byte[] b) {
7719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        long result = 0;
7729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        long value = 0;
7739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        long power = 0;
7749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        for (int i = (b.length - 1); i >= 0; i--) {
7769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            value = b[i];
7779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (value < 0) {
7789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                value += 256;
7799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
7809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            result = result | (value << power);
7829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            power += 8;
7839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return result;
7869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
7879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
78905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Converts the long to a 4 byte array. The long must be non negative.
7909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param l the long to convert
7919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return a byte array that is the same as the long
7929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
7939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static byte[] convertToByteArray(long l) {
7949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] b = new byte[4];
7959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        b[0] = (byte)(255 & (l >> 24));
7979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        b[1] = (byte)(255 & (l >> 16));
7989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        b[2] = (byte)(255 & (l >> 8));
7999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        b[3] = (byte)(255 & l);
8009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return b;
8029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
8039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
80505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Converts the String to a UNICODE byte array. It will also add the ending
8069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * null characters to the end of the string.
8079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param s the string to convert
8089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the unicode byte array of the string
8099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
8109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static byte[] convertToUnicodeByteArray(String s) {
8119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (s == null) {
8129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return null;
8139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        char c[] = s.toCharArray();
8169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] result = new byte[(c.length * 2) + 2];
8179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        for (int i = 0; i < c.length; i++) {
8189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            result[(i * 2)] = (byte)(c[i] >> 8);
8199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            result[((i * 2) + 1)] = (byte)c[i];
8209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // Add the UNICODE null character
8239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        result[result.length - 2] = 0;
8249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        result[result.length - 1] = 0;
8259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return result;
8279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
8289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
83005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Retrieves the value from the byte array for the tag value specified. The
8319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * array should be of the form Tag - Length - Value triplet.
8329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param tag the tag to retrieve from the byte array
8339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param triplet the byte sequence containing the tag length value form
8349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the value of the specified tag
8359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
8369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static byte[] getTagValue(byte tag, byte[] triplet) {
8379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int index = findTag(tag, triplet);
8399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (index == -1) {
8409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return null;
8419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        index++;
8449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int length = triplet[index] & 0xFF;
8459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] result = new byte[length];
8479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        index++;
8489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        System.arraycopy(triplet, index, result, 0, length);
8499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return result;
8519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
8529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
8549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Finds the index that starts the tag value pair in the byte array provide.
8559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param tag the tag to look for
8569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param value the byte array to search
8579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the starting index of the tag or -1 if the tag could not be found
8589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
8599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static int findTag(byte tag, byte[] value) {
8609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int length = 0;
8619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (value == null) {
8639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return -1;
8649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int index = 0;
8679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        while ((index < value.length) && (value[index] != tag)) {
8699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            length = value[index + 1] & 0xFF;
8709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            index += length + 2;
8719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (index >= value.length) {
8749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return -1;
8759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return index;
8789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
8799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
8819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Converts the byte array provided to a unicode string.
8829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param b the byte array to convert to a string
8839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param includesNull determine if the byte string provided contains the
88405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        UNICODE null character at the end or not; if it does, it will be
88505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        removed
8869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return a Unicode string
88705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @throws IllegalArgumentException if the byte array has an odd length
8889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
8899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static String convertToUnicode(byte[] b, boolean includesNull) {
8908d95d0a13a278c4bd4dbffb682acf1e457dfb94bTao Liejun        if (b == null || b.length == 0) {
8919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return null;
8929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int arrayLength = b.length;
8949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (!((arrayLength % 2) == 0)) {
8959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            throw new IllegalArgumentException("Byte array not of a valid form");
8969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        arrayLength = (arrayLength >> 1);
8989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (includesNull) {
8999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            arrayLength -= 1;
9009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
9019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        char[] c = new char[arrayLength];
9039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        for (int i = 0; i < arrayLength; i++) {
9049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            int upper = b[2 * i];
9059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            int lower = b[(2 * i) + 1];
9069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (upper < 0) {
9079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                upper += 256;
9089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
9099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (lower < 0) {
9109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lower += 256;
9119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
9120b309d6ee433d55b7499d7bbd447494366ef1316Jackson Fan            // If upper and lower both equal 0, it should be the end of string.
9130b309d6ee433d55b7499d7bbd447494366ef1316Jackson Fan            // Ignore left bytes from array to avoid potential issues
9140b309d6ee433d55b7499d7bbd447494366ef1316Jackson Fan            if (upper == 0 && lower == 0) {
9150b309d6ee433d55b7499d7bbd447494366ef1316Jackson Fan                return new String(c, 0, i);
9160b309d6ee433d55b7499d7bbd447494366ef1316Jackson Fan            }
9179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            c[i] = (char)((upper << 8) | lower);
9199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
9209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return new String(c);
9229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
9239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
92505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Compute the MD5 hash of the byte array provided. Does not accumulate
92605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * input.
9279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param in the byte array to hash
9289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the MD5 hash of the byte array
9299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
9302e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly    public static byte[] computeMd5Hash(byte[] in) {
931929a1c219248b62778807cac8ea256c7ac0fda6aBrian Carlstrom        try {
932929a1c219248b62778807cac8ea256c7ac0fda6aBrian Carlstrom            MessageDigest md5 = MessageDigest.getInstance("MD5");
933929a1c219248b62778807cac8ea256c7ac0fda6aBrian Carlstrom            return md5.digest(in);
934929a1c219248b62778807cac8ea256c7ac0fda6aBrian Carlstrom        } catch (NoSuchAlgorithmException e) {
935929a1c219248b62778807cac8ea256c7ac0fda6aBrian Carlstrom            throw new RuntimeException(e);
936929a1c219248b62778807cac8ea256c7ac0fda6aBrian Carlstrom        }
9379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
9389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
9409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Computes an authentication challenge header.
94105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @param nonce the challenge that will be provided to the peer; the
94205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        challenge must be 16 bytes long
9439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param realm a short description that describes what password to use
9449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param access if <code>true</code> then full access will be granted if
94505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        successful; if <code>false</code> then read only access will be
94605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        granted if successful
9479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param userID if <code>true</code>, a user ID is required in the reply;
94805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        if <code>false</code>, no user ID is required
94905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @throws IllegalArgumentException if the challenge is not 16 bytes long;
95005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         if the realm can not be encoded in less then 255 bytes
9512e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if the encoding scheme ISO 8859-1 is not supported
9529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
9539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static byte[] computeAuthenticationChallenge(byte[] nonce, String realm, boolean access,
9549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            boolean userID) throws IOException {
9559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] authChall = null;
9569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (nonce.length != 16) {
9589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            throw new IllegalArgumentException("Nonce must be 16 bytes long");
9599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
9609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        /*
9629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * The authentication challenge is a byte sequence of the following form
9639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 0: 0x00 - the tag for the challenge
9649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 1: 0x10 - the length of the challenge; must be 16
9659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 2-17: the authentication challenge
9669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 18: 0x01 - the options tag; this is optional in the spec, but
9679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         *                 we are going to include it in every message
9689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 19: 0x01 - length of the options; must be 1
9699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 20: the value of the options; bit 0 is set if user ID is
9709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         *          required; bit 1 is set if access mode is read only
9719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 21: 0x02 - the tag for authentication realm; only included if
9729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         *                 an authentication realm is specified
9739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 22: the length of the authentication realm; only included if
9749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         *          the authentication realm is specified
9759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 23: the encoding scheme of the authentication realm; we will use
9769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         *          the ISO 8859-1 encoding scheme since it is part of the KVM
9779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 24 & up: the realm if one is specified.
9789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         */
9799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (realm == null) {
9809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            authChall = new byte[21];
9819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
9829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (realm.length() >= 255) {
9839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                throw new IllegalArgumentException("Realm must be less then 255 bytes");
9849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
9859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            authChall = new byte[24 + realm.length()];
9869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            authChall[21] = 0x02;
9879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            authChall[22] = (byte)(realm.length() + 1);
9889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            authChall[23] = 0x01; // ISO 8859-1 Encoding
9899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            System.arraycopy(realm.getBytes("ISO8859_1"), 0, authChall, 24, realm.length());
9909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
9919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // Include the nonce field in the header
9939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        authChall[0] = 0x00;
9949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        authChall[1] = 0x10;
9959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        System.arraycopy(nonce, 0, authChall, 2, 16);
9969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // Include the options header
9989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        authChall[18] = 0x01;
9999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        authChall[19] = 0x01;
10009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        authChall[20] = 0x00;
10019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
10029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (!access) {
10039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            authChall[20] = (byte)(authChall[20] | 0x02);
10049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
10059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (userID) {
10069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            authChall[20] = (byte)(authChall[20] | 0x01);
10079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
10089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
10099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return authChall;
10109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
10119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly}
1012