1b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampackage org.bouncycastle.util.encoders;
2b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
3b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.io.IOException;
4b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.io.OutputStream;
5b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
6b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampublic class HexEncoder
7b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    implements Encoder
8b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam{
9b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    protected final byte[] encodingTable =
10b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
11b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
12b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'
13b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        };
14b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
15b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /*
16b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * set up the decoding table.
17b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
18b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    protected final byte[] decodingTable = new byte[128];
19b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
20b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    protected void initialiseDecodingTable()
21b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
2270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        for (int i = 0; i < decodingTable.length; i++)
2370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        {
2470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            decodingTable[i] = (byte)0xff;
2570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
2670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
27b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        for (int i = 0; i < encodingTable.length; i++)
28b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
29b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            decodingTable[encodingTable[i]] = (byte)i;
30b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
31b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
32b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        decodingTable['A'] = decodingTable['a'];
33b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        decodingTable['B'] = decodingTable['b'];
34b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        decodingTable['C'] = decodingTable['c'];
35b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        decodingTable['D'] = decodingTable['d'];
36b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        decodingTable['E'] = decodingTable['e'];
37b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        decodingTable['F'] = decodingTable['f'];
38b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
39b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
40b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public HexEncoder()
41b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
42b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        initialiseDecodingTable();
43b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
44b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
45b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
46b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * encode the input data producing a Hex output stream.
47b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
48b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return the number of bytes produced.
49b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
50b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public int encode(
51b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]                data,
52b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int                    off,
53b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int                    length,
54b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        OutputStream    out)
55b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
56b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
57b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        for (int i = off; i < (off + length); i++)
58b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
59b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            int    v = data[i] & 0xff;
60b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
61b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            out.write(encodingTable[(v >>> 4)]);
62b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            out.write(encodingTable[v & 0xf]);
63b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
64b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
65b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return length * 2;
66b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
67b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
6870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    private static boolean ignore(
69b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        char    c)
70b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
7170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        return c == '\n' || c =='\r' || c == '\t' || c == ' ';
72b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
7370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
74b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
75b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * decode the Hex encoded byte data writing it to the given output stream,
76b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * whitespace characters will be ignored.
77b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
78b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return the number of bytes produced.
79b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
80b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public int decode(
81b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]          data,
82b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int             off,
83b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int             length,
84b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        OutputStream    out)
85b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
86b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
87b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte    b1, b2;
88b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int     outLen = 0;
89b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
90b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int     end = off + length;
91b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
92b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        while (end > off)
93b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
94b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            if (!ignore((char)data[end - 1]))
95b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
96b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                break;
97b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
98b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
99b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            end--;
100b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
101b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
102b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int i = off;
103b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        while (i < end)
104b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
105b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            while (i < end && ignore((char)data[i]))
106b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
107b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                i++;
108b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
109b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
110b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            b1 = decodingTable[data[i++]];
111b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
112b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            while (i < end && ignore((char)data[i]))
113b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
114b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                i++;
115b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
116b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
117b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            b2 = decodingTable[data[i++]];
118b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
11970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            if ((b1 | b2) < 0)
12070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            {
12170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                throw new IOException("invalid characters encountered in Hex data");
12270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            }
12370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
124b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            out.write((b1 << 4) | b2);
125b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
126b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            outLen++;
127b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
128b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
129b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return outLen;
130b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
131b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
132b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
133b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * decode the Hex encoded String data writing it to the given output stream,
134b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * whitespace characters will be ignored.
135b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
136b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return the number of bytes produced.
137b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
138b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public int decode(
139b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String          data,
140b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        OutputStream    out)
141b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
142b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
143b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte    b1, b2;
144b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int     length = 0;
145b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
146b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int     end = data.length();
147b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
148b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        while (end > 0)
149b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
150b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            if (!ignore(data.charAt(end - 1)))
151b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
152b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                break;
153b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
154b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
155b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            end--;
156b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
157b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
158b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int i = 0;
159b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        while (i < end)
160b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
161b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            while (i < end && ignore(data.charAt(i)))
162b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
163b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                i++;
164b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
165b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
166b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            b1 = decodingTable[data.charAt(i++)];
167b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
168b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            while (i < end && ignore(data.charAt(i)))
169b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
170b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                i++;
171b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
172b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
173b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            b2 = decodingTable[data.charAt(i++)];
174b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
17570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            if ((b1 | b2) < 0)
17670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            {
17770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                throw new IOException("invalid characters encountered in Hex string");
17870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            }
17970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
180b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            out.write((b1 << 4) | b2);
181b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
182b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            length++;
183b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
184b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
185b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return length;
186b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
187b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam}
188