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