1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * ident	"%Z%%M%	%I%	%E% SMI"
24 *
25 * Copyright (c) 1999-2000 by Sun Microsystems, Inc.
26 * All rights reserved.
27 */
28
29/**
30 * Copyright 1996 Active Software Inc.
31 */
32
33package sunsoft.jws.visual.rt.encoding;
34
35import java.io.*;
36
37// Referenced classes of package sunsoft.jws.visual.rt.encoding:
38//            CEStreamExhausted, CRC16
39
40public class UCDecoder
41{
42
43    protected int bytesPerAtom()
44    {
45        return 2;
46    }
47
48    protected int bytesPerLine()
49    {
50        return 48;
51    }
52
53    protected void decodeAtom(InputStream inStream,
54			      OutputStream outStream, int l)
55	throws IOException
56    {
57        byte a = -1;
58        byte b = -1;
59        byte c = -1;
60        byte tmp[] = new byte[3];
61        int i = inStream.read(tmp);
62        if (i != 3)
63            throw new CEStreamExhausted();
64        for (i = 0; i < 64 && (a == -1 || b == -1 || c == -1); i++)
65	    {
66		if (tmp[0] == map_array[i])
67		    a = (byte)i;
68		if (tmp[1] == map_array[i])
69		    b = (byte)i;
70		if (tmp[2] == map_array[i])
71		    c = (byte)i;
72	    }
73
74        byte high_byte = (byte)(((a & 0x38) << 2) + (b & 0x1f));
75        byte low_byte = (byte)(((a & 0x7) << 5) + (c & 0x1f));
76        int p1 = 0;
77        int p2 = 0;
78        for (i = 1; i < 256; i *= 2)
79	    {
80		if ((high_byte & i) != 0)
81		    p1++;
82		if ((low_byte & i) != 0)
83		    p2++;
84	    }
85
86        int np1 = (b & 0x20) / 32;
87        int np2 = (c & 0x20) / 32;
88        if ((p1 & 0x1) != np1)
89            throw new IOException("UCDecoder: High byte parity error.");
90        if ((p2 & 0x1) != np2)
91            throw new IOException("UCDecoder: Low byte parity error.");
92        outStream.write(high_byte);
93        crc.update(high_byte);
94        if (l == 2)
95	    {
96		outStream.write(low_byte);
97		crc.update(low_byte);
98	    }
99    }
100
101    protected void decodeBufferPrefix(InputStream inStream,
102				      OutputStream outStream)
103    {
104        sequence = 0;
105    }
106
107    protected int decodeLinePrefix(InputStream inStream,
108				   OutputStream outStream)
109	throws IOException
110    {
111        crc.value = 0;
112        do
113	    {
114		int c = inStream.read(tmp, 0, 1);
115		if (c == -1)
116		    throw new CEStreamExhausted();
117	    }
118        while (tmp[0] != 42);
119        lineAndSeq.reset();
120        decodeAtom(inStream, lineAndSeq, 2);
121        byte xtmp[] = lineAndSeq.toByteArray();
122        int nLen = xtmp[0] & 0xff;
123        int nSeq = xtmp[1] & 0xff;
124        if (nSeq != sequence)
125	    {
126		throw new IOException("UCDecoder: Out of sequence line.");
127	    }
128        else
129	    {
130		sequence = sequence + 1 & 0xff;
131		return nLen;
132	    }
133    }
134
135    protected void decodeLineSuffix(InputStream inStream,
136				    OutputStream outStream)
137	throws IOException
138    {
139        int lineCRC = crc.value;
140        lineAndSeq.reset();
141        decodeAtom(inStream, lineAndSeq, 2);
142        byte tmp[] = lineAndSeq.toByteArray();
143        int readCRC = (tmp[0] << 8 & 0xff00) + (tmp[1] & 0xff);
144        if (readCRC != lineCRC)
145            throw new IOException("UCDecoder: CRC check failed.");
146        else
147            return;
148    }
149
150    public void decodeBuffer(InputStream aStream, OutputStream bStream)
151	throws IOException
152    {
153        int totalBytes = 0;
154        decodeBufferPrefix(aStream, bStream);
155        try
156	    {
157		do
158		    {
159			int length = decodeLinePrefix(aStream, bStream);
160			int i;
161			for (i = 0; i + bytesPerAtom() < length;
162			     i += bytesPerAtom())
163			    {
164				decodeAtom(aStream, bStream, bytesPerAtom());
165				totalBytes += bytesPerAtom();
166			    }
167
168			if (i + bytesPerAtom() == length)
169			    {
170				decodeAtom(aStream, bStream, bytesPerAtom());
171				totalBytes += bytesPerAtom();
172			    }
173			else
174			    {
175				decodeAtom(aStream, bStream, length - i);
176				totalBytes += length - i;
177			    }
178			decodeLineSuffix(aStream, bStream);
179		    }
180		while (true);
181	    }
182        catch (CEStreamExhausted ex)
183	    {
184		decodeBufferSuffix(aStream, bStream);
185	    }
186    }
187
188    public byte[] decodeBuffer(String inputString)
189	throws IOException
190    {
191        byte inputBuffer[] = new byte[inputString.length()];
192        inputString.getBytes(0, inputString.length(), inputBuffer, 0);
193        ByteArrayInputStream inStream =
194	    new ByteArrayInputStream(inputBuffer);
195        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
196        decodeBuffer(inStream, outStream);
197        return outStream.toByteArray();
198    }
199
200    protected void decodeBufferSuffix(InputStream inputstream,
201				      OutputStream outputstream)
202	throws IOException
203    {
204    }
205
206    public UCDecoder()
207    {
208        super();
209        tmp = new byte[2];
210        crc = new CRC16();
211        lineAndSeq = new ByteArrayOutputStream(2);
212    }
213
214    private static final byte map_array[] = {
215        48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
216        65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
217        75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
218        85, 86, 87, 88, 89, 90, 97, 98, 99, 100,
219        101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
220        111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
221        121, 122, 40, 41
222    };
223    private int sequence;
224    private byte tmp[];
225    CRC16 crc;
226    private ByteArrayOutputStream lineAndSeq;
227
228}
229