ObexHelper.java revision 05ff98bbefda39b9ff26f8bca132cfd0248745c6
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 android.security.Md5MessageDigest;
362e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly
372e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellyimport java.io.ByteArrayOutputStream;
382e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellyimport java.io.IOException;
392e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellyimport java.io.UnsupportedEncodingException;
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
733998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_CONNECT = 0x80;
743998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
753998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_DISCONNECT = 0x81;
763998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
773998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_PUT = 0x02;
783998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
793998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_PUT_FINAL = 0x82;
803998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
813998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_GET = 0x03;
823998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
833998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_GET_FINAL = 0x83;
843998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
853998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_RESERVED = 0x04;
863998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
873998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_RESERVED_FINAL = 0x84;
883998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
893998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_SETPATH = 0x85;
903998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
913998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_OPCODE_ABORT = 0xFF;
923998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
933998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ASCII = 0x00;
943998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
953998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_1 = 0x01;
963998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
973998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_2 = 0x02;
983998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
993998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_3 = 0x03;
1003998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1013998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_4 = 0x04;
1023998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1033998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_5 = 0x05;
1043998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1053998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_6 = 0x06;
1063998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1073998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_7 = 0x07;
1083998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1093998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_8 = 0x08;
1103998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1113998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_9 = 0x09;
1123998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1133998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public static final int OBEX_AUTH_REALM_CHARSET_UNICODE = 0xFF;
1143998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
1159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
1169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Updates the HeaderSet with the headers received in the byte array
11705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * provided. Invalid headers are ignored.
1189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <P>
11905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * The first two bits of an OBEX Header specifies the type of object that is
12005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * being sent. The table below specifies the meaning of the high bits.
1219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <TABLE>
12205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TR>
12305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TH>Bits 8 and 7</TH>
12405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TH>Value</TH>
12505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TH>Description</TH>
12605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * </TR>
12705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TR>
12805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>00</TD>
12905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>0x00</TD>
13005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>Null Terminated Unicode text, prefixed with 2 byte unsigned integer</TD>
13105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * </TR>
13205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TR>
13305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>01</TD>
13405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>0x40</TD>
13505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>Byte Sequence, length prefixed with 2 byte unsigned integer</TD>
13605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * </TR>
13705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TR>
13805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>10</TD>
13905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>0x80</TD>
14005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>1 byte quantity</TD>
14105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * </TR>
14205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TR>
14305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>11</TD>
14405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>0xC0</TD>
14505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * <TD>4 byte quantity - transmitted in network byte order (high byte first</TD>
14605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * </TR>
1479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * </TABLE>
1489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * This method uses the information in this table to determine the type of
14905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Java object to create and passes that object with the full header to
15005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * setHeader() to update the HeaderSet object. Invalid headers will cause an
15105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * exception to be thrown. When it is thrown, it is ignored.
1529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param header the HeaderSet to update
1539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param headerArray the byte array containing headers
1549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the result of the last start body or end body header provided;
15505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         the first byte in the result will specify if a body or end of
15605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         body is received
1572e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if an invalid header was found
1589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
1599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static byte[] updateHeaderSet(HeaderSet header, byte[] headerArray) throws IOException {
1609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int index = 0;
1619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int length = 0;
1629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int headerID;
1639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] value = null;
1649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] body = null;
1659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        HeaderSet headerImpl = header;
1669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
1679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            while (index < headerArray.length) {
1689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                headerID = 0xFF & headerArray[index];
1699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                switch (headerID & (0xC0)) {
1709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    /*
1729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     * 0x00 is a unicode null terminate string with the first
1739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     * two bytes after the header identifier being the length
1749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     */
1759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    case 0x00:
1769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        // Fall through
1779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        /*
1789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                         * 0x40 is a byte sequence with the first
1799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                         * two bytes after the header identifier being the length
1809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                         */
1819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    case 0x40:
1829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        boolean trimTail = true;
1839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        index++;
1849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        length = 0xFF & headerArray[index];
1859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        length = length << 8;
1869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        index++;
1879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        length += 0xFF & headerArray[index];
1889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        length -= 3;
1899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        index++;
1909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        value = new byte[length];
1919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        System.arraycopy(headerArray, index, value, 0, length);
1929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        if (length == 0 || (length > 0 && (value[length - 1] != 0))) {
1939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            trimTail = false;
1949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        }
1959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        switch (headerID) {
1969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            case HeaderSet.TYPE:
1979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                try {
1989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    // Remove trailing null
1999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    if (trimTail == false) {
2009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                        headerImpl.setHeader(headerID, new String(value, 0,
2019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                                value.length, "ISO8859_1"));
2029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    } else {
2039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                        headerImpl.setHeader(headerID, new String(value, 0,
2049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                                value.length - 1, "ISO8859_1"));
2059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    }
2069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                } catch (UnsupportedEncodingException e) {
2073998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                    throw e;
2089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                }
2099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                break;
2109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2113998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                            case HeaderSet.AUTH_CHALLENGE:
2123998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                headerImpl.mAuthChall = new byte[length];
2133998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                System.arraycopy(headerArray, index, headerImpl.mAuthChall, 0,
2149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                        length);
2159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                break;
2169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2173998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                            case HeaderSet.AUTH_RESPONSE:
2183998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                headerImpl.mAuthResp = new byte[length];
2193998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                System.arraycopy(headerArray, index, headerImpl.mAuthResp, 0,
2203998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                        length);
2219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                break;
2229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2233998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                            case HeaderSet.BODY:
2249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                /* Fall Through */
2253998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                            case HeaderSet.END_OF_BODY:
2269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                body = new byte[length + 1];
2279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                body[0] = (byte)headerID;
2289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                System.arraycopy(headerArray, index, body, 1, length);
2299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                break;
2309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            case HeaderSet.TIME_ISO_8601:
2329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                try {
2339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    String dateString = new String(value, "ISO8859_1");
2349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    Calendar temp = Calendar.getInstance();
2359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    if ((dateString.length() == 16)
2369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                            && (dateString.charAt(15) == 'Z')) {
2379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                        temp.setTimeZone(TimeZone.getTimeZone("UTC"));
2389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    }
2399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    temp.set(Calendar.YEAR, Integer.parseInt(dateString.substring(
2409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                            0, 4)));
2419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    temp.set(Calendar.MONTH, Integer.parseInt(dateString.substring(
2429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                            4, 6)));
2439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    temp.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateString
2449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                            .substring(6, 8)));
2459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    temp.set(Calendar.HOUR_OF_DAY, Integer.parseInt(dateString
2469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                            .substring(9, 11)));
2479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    temp.set(Calendar.MINUTE, Integer.parseInt(dateString
2489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                            .substring(11, 13)));
2499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    temp.set(Calendar.SECOND, Integer.parseInt(dateString
2509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                            .substring(13, 15)));
2519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    headerImpl.setHeader(HeaderSet.TIME_ISO_8601, temp);
2529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                } catch (UnsupportedEncodingException e) {
2533998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                    throw e;
2549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                }
2559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                break;
2569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            default:
2583998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                if ((headerID & 0xC0) == 0x00) {
2593998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                    headerImpl.setHeader(headerID, ObexHelper.convertToUnicode(
2603998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                            value, true));
2613998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                } else {
2623998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                    headerImpl.setHeader(headerID, value);
2639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                }
2649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        }
2659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        index += length;
2679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        break;
2689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    /*
2709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     * 0x80 is a byte header.  The only valid byte headers are
2719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     * the 16 user defined byte headers.
2729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     */
2739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    case 0x80:
2749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        index++;
2759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        try {
2769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            headerImpl.setHeader(headerID, Byte.valueOf(headerArray[index]));
2779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        } catch (Exception e) {
2789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            // Not a valid header so ignore
2799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        }
2809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        index++;
2819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        break;
2829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    /*
2849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     * 0xC0 is a 4 byte unsigned integer header and with the
2859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     * exception of TIME_4_BYTE will be converted to a Long
2869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     * and added.
2879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                     */
2889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    case 0xC0:
2899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        index++;
2909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        value = new byte[4];
2919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        System.arraycopy(headerArray, index, value, 0, 4);
2929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        try {
2939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            if (headerID != HeaderSet.TIME_4_BYTE) {
2949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                // Determine if it is a connection ID.  These
2959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                // need to be handled differently
2963998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                if (headerID == HeaderSet.CONNECTION_ID) {
2973998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                    headerImpl.mConnectionID = new byte[4];
2983998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                    System.arraycopy(value, 0, headerImpl.mConnectionID, 0, 4);
2999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                } else {
3009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                    headerImpl.setHeader(headerID, Long
3019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                            .valueOf(convertToLong(value)));
3029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                }
3039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            } else {
3049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                Calendar temp = Calendar.getInstance();
3059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                temp.setTime(new Date(convertToLong(value) * 1000L));
3069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                headerImpl.setHeader(HeaderSet.TIME_4_BYTE, temp);
3079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            }
3089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        } catch (Exception e) {
3099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            // Not a valid header so ignore
3109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            throw new IOException("Header was not formatted properly");
3119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        }
3129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        index += 4;
3139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        break;
3149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
3179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } catch (IOException e) {
3189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            throw new IOException("Header was not formatted properly");
3199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
3209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return body;
3229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
3239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
3259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Creates the header part of OBEX packet based on the header provided.
32605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * TODO: Could use getHeaderList() to get the array of headers to include
32705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * and then use the high two bits to determine the the type of the object
32805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * and construct the byte array from that. This will make the size smaller.
3299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param head the header used to construct the byte array
3309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param nullOut <code>true</code> if the header should be set to
33105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        <code>null</code> once it is added to the array or
33205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        <code>false</code> if it should not be nulled out
3339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the header of an OBEX packet
3349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
3359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static byte[] createHeader(HeaderSet head, boolean nullOut) {
3369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        Long intHeader = null;
3379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        String stringHeader = null;
3389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        Calendar dateHeader = null;
3399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        Byte byteHeader = null;
3409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        StringBuffer buffer = null;
3419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] value = null;
3429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] result = null;
3439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] lengthArray = new byte[2];
3449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int length;
3459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        HeaderSet headImpl = null;
3469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        ByteArrayOutputStream out = new ByteArrayOutputStream();
3479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        headImpl = head;
3489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
3509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            /*
3519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             * Determine if there is a connection ID to send.  If there is,
3529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             * then it should be the first header in the packet.
3539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             */
3543998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            if ((headImpl.mConnectionID != null) && (headImpl.getHeader(HeaderSet.TARGET) == null)) {
3559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3563998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                out.write((byte)HeaderSet.CONNECTION_ID);
3573998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                out.write(headImpl.mConnectionID);
3589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
3599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Count Header
3619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            intHeader = (Long)headImpl.getHeader(HeaderSet.COUNT);
3629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (intHeader != null) {
3639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.COUNT);
3642e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                value = ObexHelper.convertToByteArray(intHeader.longValue());
3659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
3669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
3679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.COUNT, null);
3689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
3709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Name Header
3729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            stringHeader = (String)headImpl.getHeader(HeaderSet.NAME);
3739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (stringHeader != null) {
3749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.NAME);
3752e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                value = ObexHelper.convertToUnicodeByteArray(stringHeader);
3769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                length = value.length + 3;
3773998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                lengthArray[0] = (byte)(0xFF & (length >> 8));
3783998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                lengthArray[1] = (byte)(0xFF & length);
3799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
3809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
3819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
3829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.NAME, null);
3839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
3859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Type Header
3879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            stringHeader = (String)headImpl.getHeader(HeaderSet.TYPE);
3889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (stringHeader != null) {
3899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.TYPE);
3909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                try {
3919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    value = stringHeader.getBytes("ISO8859_1");
3929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } catch (UnsupportedEncodingException e) {
3933998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    throw e;
3949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                length = value.length + 4;
3979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
3989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
3999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
4009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
4019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(0x00);
4029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
4039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.TYPE, null);
4049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
4069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Length Header
4089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            intHeader = (Long)headImpl.getHeader(HeaderSet.LENGTH);
4099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (intHeader != null) {
4109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.LENGTH);
4112e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                value = ObexHelper.convertToByteArray(intHeader.longValue());
4129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
4139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
4149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.LENGTH, null);
4159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
4179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Time ISO Header
4199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_ISO_8601);
4209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (dateHeader != null) {
4219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                /*
4239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * The ISO Header should take the form YYYYMMDDTHHMMSSZ.  The
4249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * 'Z' will only be included if it is a UTC time.
4259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 */
4269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                buffer = new StringBuffer();
4279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                int temp = dateHeader.get(Calendar.YEAR);
4289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                for (int i = temp; i < 1000; i = i * 10) {
4299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    buffer.append("0");
4309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                buffer.append(temp);
4329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                temp = dateHeader.get(Calendar.MONTH);
4339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (temp < 10) {
4349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    buffer.append("0");
4359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                buffer.append(temp);
4379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                temp = dateHeader.get(Calendar.DAY_OF_MONTH);
4389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (temp < 10) {
4399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    buffer.append("0");
4409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                buffer.append(temp);
4429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                buffer.append("T");
4439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                temp = dateHeader.get(Calendar.HOUR_OF_DAY);
4449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (temp < 10) {
4459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    buffer.append("0");
4469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                buffer.append(temp);
4489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                temp = dateHeader.get(Calendar.MINUTE);
4499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (temp < 10) {
4509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    buffer.append("0");
4519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                buffer.append(temp);
4539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                temp = dateHeader.get(Calendar.SECOND);
4549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (temp < 10) {
4559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    buffer.append("0");
4569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                buffer.append(temp);
4589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (dateHeader.getTimeZone().getID().equals("UTC")) {
4609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    buffer.append("Z");
4619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                try {
4649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    value = buffer.toString().getBytes("ISO8859_1");
4659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } catch (UnsupportedEncodingException e) {
4663998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    throw e;
4679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                length = value.length + 3;
4709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
4719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
4729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(HeaderSet.TIME_ISO_8601);
4739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
4749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
4759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
4769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.TIME_ISO_8601, null);
4779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
4799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Time 4 Byte Header
4819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_4_BYTE);
4829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (dateHeader != null) {
4839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(HeaderSet.TIME_4_BYTE);
4849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                /*
4869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * Need to call getTime() twice.  The first call will return
4879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * a java.util.Date object.  The second call returns the number
4889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * of milliseconds since January 1, 1970.  We need to convert
4899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * it to seconds since the TIME_4_BYTE expects the number of
4909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * seconds since January 1, 1970.
4919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 */
4922e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                value = ObexHelper.convertToByteArray(dateHeader.getTime().getTime() / 1000L);
4939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
4949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
4959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.TIME_4_BYTE, null);
4969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
4989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Description Header
5009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            stringHeader = (String)headImpl.getHeader(HeaderSet.DESCRIPTION);
5019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (stringHeader != null) {
5029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.DESCRIPTION);
5032e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                value = ObexHelper.convertToUnicodeByteArray(stringHeader);
5049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                length = value.length + 3;
5059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
5069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
5079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
5089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
5099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
5109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.DESCRIPTION, null);
5119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
5129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Target Header
5159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            value = (byte[])headImpl.getHeader(HeaderSet.TARGET);
5169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (value != null) {
5179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.TARGET);
5189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                length = value.length + 3;
5199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
5209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
5219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
5229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
5239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
5249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.TARGET, null);
5259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
5269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // HTTP Header
5299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            value = (byte[])headImpl.getHeader(HeaderSet.HTTP);
5309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (value != null) {
5319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.HTTP);
5329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                length = value.length + 3;
5339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
5349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
5359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
5369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
5379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
5389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.HTTP, null);
5399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
5409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Who Header
5439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            value = (byte[])headImpl.getHeader(HeaderSet.WHO);
5449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (value != null) {
5459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.WHO);
5469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                length = value.length + 3;
5479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
5489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
5499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
5509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
5519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
5529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.WHO, null);
5539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
5549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Connection ID Header
5579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            value = (byte[])headImpl.getHeader(HeaderSet.APPLICATION_PARAMETER);
5589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (value != null) {
5599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.APPLICATION_PARAMETER);
5609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                length = value.length + 3;
5619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
5629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
5639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
5649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
5659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
5669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.APPLICATION_PARAMETER, null);
5679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
5689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Object Class Header
5719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            value = (byte[])headImpl.getHeader(HeaderSet.OBJECT_CLASS);
5729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (value != null) {
5739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write((byte)HeaderSet.OBJECT_CLASS);
5749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                length = value.length + 3;
5759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
5769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
5779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
5789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(value);
5799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
5809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    headImpl.setHeader(HeaderSet.OBJECT_CLASS, null);
5819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
5829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Check User Defined Headers
5859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            for (int i = 0; i < 16; i++) {
5869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                //Unicode String Header
5889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                stringHeader = (String)headImpl.getHeader(i + 0x30);
5899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (stringHeader != null) {
5909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    out.write((byte)i + 0x30);
5912e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                    value = ObexHelper.convertToUnicodeByteArray(stringHeader);
5929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    length = value.length + 3;
5939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    lengthArray[0] = (byte)(255 & (length >> 8));
5949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    lengthArray[1] = (byte)(255 & length);
5959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    out.write(lengthArray);
5969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    out.write(value);
5979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    if (nullOut) {
5989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        headImpl.setHeader(i + 0x30, null);
5999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
6009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
6019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                // Byte Sequence Header
6039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                value = (byte[])headImpl.getHeader(i + 0x70);
6049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (value != null) {
6059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    out.write((byte)i + 0x70);
6069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    length = value.length + 3;
6079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    lengthArray[0] = (byte)(255 & (length >> 8));
6089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    lengthArray[1] = (byte)(255 & length);
6099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    out.write(lengthArray);
6109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    out.write(value);
6119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    if (nullOut) {
6129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        headImpl.setHeader(i + 0x70, null);
6139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
6149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
6159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                // Byte Header
6179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                byteHeader = (Byte)headImpl.getHeader(i + 0xB0);
6189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (byteHeader != null) {
6199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    out.write((byte)i + 0xB0);
6209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    out.write(byteHeader.byteValue());
6219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    if (nullOut) {
6229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        headImpl.setHeader(i + 0xB0, null);
6239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
6249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
6259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                // Integer header
6279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                intHeader = (Long)headImpl.getHeader(i + 0xF0);
6289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (intHeader != null) {
6299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    out.write((byte)i + 0xF0);
6302e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                    out.write(ObexHelper.convertToByteArray(intHeader.longValue()));
6319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    if (nullOut) {
6329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        headImpl.setHeader(i + 0xF0, null);
6339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
6349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
6359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
6369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Add the authentication challenge header
6383998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            if (headImpl.mAuthChall != null) {
6393998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                out.write((byte)HeaderSet.AUTH_CHALLENGE);
6403998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                length = headImpl.mAuthChall.length + 3;
6419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
6429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
6439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
6443998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                out.write(headImpl.mAuthChall);
6459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
6463998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    headImpl.mAuthChall = null;
6479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
6489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
6499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            // Add the authentication response header
6513998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            if (headImpl.mAuthResp != null) {
6523998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                out.write((byte)HeaderSet.AUTH_RESPONSE);
6533998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                length = headImpl.mAuthResp.length + 3;
6549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[0] = (byte)(255 & (length >> 8));
6559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lengthArray[1] = (byte)(255 & length);
6569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.write(lengthArray);
6573998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                out.write(headImpl.mAuthResp);
6589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (nullOut) {
6593998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    headImpl.mAuthResp = null;
6609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
6619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
6629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } catch (IOException e) {
6649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } finally {
6659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            result = out.toByteArray();
6669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            try {
6679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                out.close();
6689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            } catch (Exception ex) {
6699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
6709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
6719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return result;
6739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
6759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
67705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Determines where the maximum divide is between headers. This method is
6789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * used by put and get operations to separate headers to a size that meets
6799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * the max packet size allowed.
6809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param headerArray the headers to separate
6819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param start the starting index to search
6829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param maxSize the maximum size of a packet
6839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the index of the end of the header block to send or -1 if the
68405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         header could not be divided because the header is too large
6859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
6869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static int findHeaderEnd(byte[] headerArray, int start, int maxSize) {
6879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int fullLength = 0;
6899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int lastLength = -1;
6909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int index = start;
6919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int length = 0;
6929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        while ((fullLength < maxSize) && (index < headerArray.length)) {
6949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            int headerID = (headerArray[index] < 0 ? headerArray[index] + 256 : headerArray[index]);
6959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            lastLength = fullLength;
6969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            switch (headerID & (0xC0)) {
6989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                case 0x00:
7009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // Fall through
7019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                case 0x40:
7029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    index++;
7049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    length = (headerArray[index] < 0 ? headerArray[index] + 256
7059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            : headerArray[index]);
7069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    length = length << 8;
7079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    index++;
7089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    length += (headerArray[index] < 0 ? headerArray[index] + 256
7099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            : headerArray[index]);
7109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    length -= 3;
7119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    index++;
7129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    index += length;
7139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    fullLength += length + 3;
7149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    break;
7159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                case 0x80:
7179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    index++;
7199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    index++;
7209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    fullLength += 2;
7219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    break;
7229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                case 0xC0:
7249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    index += 5;
7269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    fullLength += 5;
7279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    break;
7289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
7309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        /*
7349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Determine if this is the last header or not
7359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         */
7369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (lastLength == 0) {
7379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            /*
7389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             * Since this is the last header, check to see if the size of this
7399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             * header is less then maxSize.  If it is, return the length of the
7409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             * header, otherwise return -1.  The length of the header is
7419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             * returned since it would be the start of the next header
7429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             */
7439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (fullLength < maxSize) {
7449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                return headerArray.length;
7459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            } else {
7469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                return -1;
7479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
7489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
7499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return lastLength + start;
7509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
7529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
7549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Converts the byte array to a long.
7559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param b the byte array to convert to a long
7569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the byte array as a long
7579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
7589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static long convertToLong(byte[] b) {
7599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        long result = 0;
7609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        long value = 0;
7619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        long power = 0;
7629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        for (int i = (b.length - 1); i >= 0; i--) {
7649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            value = b[i];
7659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (value < 0) {
7669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                value += 256;
7679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
7689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            result = result | (value << power);
7709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            power += 8;
7719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return result;
7749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
7759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
77705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Converts the long to a 4 byte array. The long must be non negative.
7789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param l the long to convert
7799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return a byte array that is the same as the long
7809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
7819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static byte[] convertToByteArray(long l) {
7829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] b = new byte[4];
7839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        b[0] = (byte)(255 & (l >> 24));
7859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        b[1] = (byte)(255 & (l >> 16));
7869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        b[2] = (byte)(255 & (l >> 8));
7879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        b[3] = (byte)(255 & l);
7889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return b;
7909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
7919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
79305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Converts the String to a UNICODE byte array. It will also add the ending
7949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * null characters to the end of the string.
7959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param s the string to convert
7969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the unicode byte array of the string
7979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
7989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static byte[] convertToUnicodeByteArray(String s) {
7999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (s == null) {
8009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return null;
8019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        char c[] = s.toCharArray();
8049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] result = new byte[(c.length * 2) + 2];
8059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        for (int i = 0; i < c.length; i++) {
8069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            result[(i * 2)] = (byte)(c[i] >> 8);
8079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            result[((i * 2) + 1)] = (byte)c[i];
8089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // Add the UNICODE null character
8119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        result[result.length - 2] = 0;
8129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        result[result.length - 1] = 0;
8139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return result;
8159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
8169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
81805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Retrieves the value from the byte array for the tag value specified. The
8199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * array should be of the form Tag - Length - Value triplet.
8209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param tag the tag to retrieve from the byte array
8219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param triplet the byte sequence containing the tag length value form
8229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the value of the specified tag
8239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
8249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static byte[] getTagValue(byte tag, byte[] triplet) {
8259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int index = findTag(tag, triplet);
8279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (index == -1) {
8289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return null;
8299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        index++;
8329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int length = triplet[index] & 0xFF;
8339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] result = new byte[length];
8359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        index++;
8369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        System.arraycopy(triplet, index, result, 0, length);
8379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return result;
8399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
8409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
8429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Finds the index that starts the tag value pair in the byte array provide.
8439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param tag the tag to look for
8449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param value the byte array to search
8459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the starting index of the tag or -1 if the tag could not be found
8469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
8479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static int findTag(byte tag, byte[] value) {
8489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int length = 0;
8499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (value == null) {
8519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return -1;
8529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int index = 0;
8559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        while ((index < value.length) && (value[index] != tag)) {
8579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            length = value[index + 1] & 0xFF;
8589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            index += length + 2;
8599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (index >= value.length) {
8629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return -1;
8639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return index;
8669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
8679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
8699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Converts the byte array provided to a unicode string.
8709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param b the byte array to convert to a string
8719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param includesNull determine if the byte string provided contains the
87205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        UNICODE null character at the end or not; if it does, it will be
87305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        removed
8749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return a Unicode string
87505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @throws IllegalArgumentException if the byte array has an odd length
8769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
8779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static String convertToUnicode(byte[] b, boolean includesNull) {
8789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (b == null) {
8799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return null;
8809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int arrayLength = b.length;
8829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (!((arrayLength % 2) == 0)) {
8839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            throw new IllegalArgumentException("Byte array not of a valid form");
8849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        arrayLength = (arrayLength >> 1);
8869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (includesNull) {
8879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            arrayLength -= 1;
8889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        char[] c = new char[arrayLength];
8919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        for (int i = 0; i < arrayLength; i++) {
8929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            int upper = b[2 * i];
8939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            int lower = b[(2 * i) + 1];
8949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (upper < 0) {
8959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                upper += 256;
8969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
8979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (lower < 0) {
8989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                lower += 256;
8999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
9009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            c[i] = (char)((upper << 8) | lower);
9029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
9039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return new String(c);
9059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
9069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
90805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Compute the MD5 hash of the byte array provided. Does not accumulate
90905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * input.
9109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param in the byte array to hash
9119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the MD5 hash of the byte array
9129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
9132e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly    public static byte[] computeMd5Hash(byte[] in) {
9142e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly        Md5MessageDigest md5 = new Md5MessageDigest();
9152e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly        return md5.digest(in);
9169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
9179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
9199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Computes an authentication challenge header.
92005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @param nonce the challenge that will be provided to the peer; the
92105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        challenge must be 16 bytes long
9229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param realm a short description that describes what password to use
9239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param access if <code>true</code> then full access will be granted if
92405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        successful; if <code>false</code> then read only access will be
92505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        granted if successful
9269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param userID if <code>true</code>, a user ID is required in the reply;
92705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        if <code>false</code>, no user ID is required
92805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @throws IllegalArgumentException if the challenge is not 16 bytes long;
92905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         if the realm can not be encoded in less then 255 bytes
9302e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if the encoding scheme ISO 8859-1 is not supported
9319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
9329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public static byte[] computeAuthenticationChallenge(byte[] nonce, String realm, boolean access,
9339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            boolean userID) throws IOException {
9349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] authChall = null;
9359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (nonce.length != 16) {
9379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            throw new IllegalArgumentException("Nonce must be 16 bytes long");
9389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
9399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        /*
9419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * The authentication challenge is a byte sequence of the following form
9429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 0: 0x00 - the tag for the challenge
9439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 1: 0x10 - the length of the challenge; must be 16
9449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 2-17: the authentication challenge
9459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 18: 0x01 - the options tag; this is optional in the spec, but
9469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         *                 we are going to include it in every message
9479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 19: 0x01 - length of the options; must be 1
9489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 20: the value of the options; bit 0 is set if user ID is
9499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         *          required; bit 1 is set if access mode is read only
9509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 21: 0x02 - the tag for authentication realm; only included if
9519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         *                 an authentication realm is specified
9529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 22: the length of the authentication realm; only included if
9539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         *          the authentication realm is specified
9549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 23: the encoding scheme of the authentication realm; we will use
9559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         *          the ISO 8859-1 encoding scheme since it is part of the KVM
9569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * byte 24 & up: the realm if one is specified.
9579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         */
9589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (realm == null) {
9599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            authChall = new byte[21];
9609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
9619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (realm.length() >= 255) {
9629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                throw new IllegalArgumentException("Realm must be less then 255 bytes");
9639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
9649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            authChall = new byte[24 + realm.length()];
9659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            authChall[21] = 0x02;
9669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            authChall[22] = (byte)(realm.length() + 1);
9679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            authChall[23] = 0x01; // ISO 8859-1 Encoding
9689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            System.arraycopy(realm.getBytes("ISO8859_1"), 0, authChall, 24, realm.length());
9699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
9709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // Include the nonce field in the header
9729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        authChall[0] = 0x00;
9739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        authChall[1] = 0x10;
9749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        System.arraycopy(nonce, 0, authChall, 2, 16);
9759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // Include the options header
9779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        authChall[18] = 0x01;
9789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        authChall[19] = 0x01;
9799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        authChall[20] = 0x00;
9809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (!access) {
9829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            authChall[20] = (byte)(authChall[20] | 0x02);
9839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
9849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (userID) {
9859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            authChall[20] = (byte)(authChall[20] | 0x01);
9869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
9879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return authChall;
9899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
9909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly}
991