blob: f56e57f79ac70986cb8a70ac43927cfff8bc8fe8 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1999 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.jndi.ldap;
27
28import java.io.UnsupportedEncodingException;
29
30/**
31 * A BER decoder. Contains methods to parse a BER buffer.
32 *
33 * @author Jagane Sundar
34 * @author Vincent Ryan
35 */
36public final class BerDecoder extends Ber {
37
38 private int origOffset; // The start point in buf to decode
39
40 /**
41 * Creates a BER decoder that reads bytes from the specified buffer.
42 */
43 public BerDecoder(byte buf[], int offset, int bufsize) {
44
45 this.buf = buf;
46 this.bufsize = bufsize;
47 this.origOffset = offset;
48
49 reset();
50 }
51
52 /**
53 * Resets this decode to start parsing from the initial offset
54 * (ie., same state as after calling the constructor).
55 */
56 public void reset() {
57 offset = origOffset;
58 }
59
60 /**
61 * Returns the current parse position.
62 * It points to the byte that will be parsed next.
63 * Useful for parsing sequences.
64 */
65 public int getParsePosition() {
66 return offset;
67 }
68
69 /**
70 * Parses a possibly variable length field.
71 */
72 public int parseLength() throws DecodeException {
73
74 int lengthbyte = parseByte();
75
76 if ((lengthbyte & 0x80) == 0x80) {
77
78 lengthbyte &= 0x7f;
79
80 if (lengthbyte == 0) {
81 throw new DecodeException(
82 "Indefinite length not supported");
83 }
84
85 if (lengthbyte > 4) {
86 throw new DecodeException("encoding too long");
87 }
88
89 if (bufsize - offset < lengthbyte) {
90 throw new DecodeException("Insufficient data");
91 }
92
93 int retval = 0;
94
95 for( int i = 0; i < lengthbyte; i++) {
96 retval = (retval << 8) + (buf[offset++] & 0xff);
97 }
98 return retval;
99 } else {
100 return lengthbyte;
101 }
102 }
103
104 /**
105 * Parses the next sequence in this BER buffer.
106 * @param rlen An array for returning size of the sequence in bytes. If null,
107 * the size is not returned.
108 * @return The sequence's tag.
109 */
110 public int parseSeq(int rlen[]) throws DecodeException {
111
112 int seq = parseByte();
113 int len = parseLength();
114 if (rlen != null) {
115 rlen[0] = len;
116 }
117 return seq;
118 }
119
120 /**
121 * Used to skip bytes. Usually used when trying to recover from parse error.
122 * Don't need to be public right now?
123 * @param i The number of bytes to skip
124 */
125 void seek(int i) throws DecodeException {
126 if (offset + i > bufsize || offset + i < 0) {
127 throw new DecodeException("array index out of bounds");
128 }
129 offset += i;
130 }
131
132 /**
133 * Parses the next byte in this BER buffer.
134 * @return The byte parsed.
135 */
136 public int parseByte() throws DecodeException {
137 if (bufsize - offset < 1) {
138 throw new DecodeException("Insufficient data");
139 }
140 return buf[offset++] & 0xff;
141 }
142
143
144 /**
145 * Returns the next byte in this BER buffer without consuming it.
146 * @return The next byte.
147 */
148 public int peekByte() throws DecodeException {
149 if (bufsize - offset < 1) {
150 throw new DecodeException("Insufficient data");
151 }
152 return buf[offset] & 0xff;
153 }
154
155 /**
156 * Parses an ASN_BOOLEAN tagged integer from this BER buffer.
157 * @return true if the tagged integer is 0; false otherwise.
158 */
159 public boolean parseBoolean() throws DecodeException {
160 return ((parseIntWithTag(ASN_BOOLEAN) == 0x00) ? false : true);
161 }
162
163 /**
164 * Parses an ASN_ENUMERATED tagged integer from this BER buffer.
165 * @return The tag of enumeration.
166 */
167 public int parseEnumeration() throws DecodeException {
168 return parseIntWithTag(ASN_ENUMERATED);
169 }
170
171 /**
172 * Parses an ASN_INTEGER tagged integer from this BER buffer.
173 * @return The value of the integer.
174 */
175 public int parseInt() throws DecodeException {
176 return parseIntWithTag(ASN_INTEGER);
177 }
178
179 /**
180 * Parses an integer that's preceded by a tag.
181 *<blockquote><pre>
182 * BER integer ::= tag length byte {byte}*
183 *</pre></blockquote>
184 */
185 private int parseIntWithTag(int tag) throws DecodeException {
186
187
188 if (parseByte() != tag) {
189 throw new DecodeException("Encountered ASN.1 tag " +
190 Integer.toString(buf[offset - 1] & 0xff) +
191 " (expected tag " + Integer.toString(tag) + ")");
192 }
193
194 int len = parseLength();
195
196 if (len > 4) {
197 throw new DecodeException("INTEGER too long");
198 } else if (len > bufsize - offset) {
199 throw new DecodeException("Insufficient data");
200 }
201
202 byte fb = buf[offset++];
203 int value = 0;
204
205 value = fb & 0x7F;
206 for( int i = 1 /* first byte already read */ ; i < len; i++) {
207 value <<= 8;
208 value |= (buf[offset++] & 0xff);
209 }
210
211 if ((fb & 0x80) == 0x80) {
212 value = -value;
213 }
214
215 return value;
216 }
217
218 /**
219 * Parses a string.
220 */
221 public String parseString(boolean decodeUTF8) throws DecodeException {
222 return parseStringWithTag(ASN_SIMPLE_STRING, decodeUTF8, null);
223 }
224
225 /**
226 * Parses a string of a given tag from this BER buffer.
227 *<blockquote><pre>
228 *BER simple string ::= tag length {byte}*
229 *</pre></blockquote>
230 * @param rlen An array for holding the relative parsed offset; if null
231 * offset not set.
232 * @param decodeUTF8 If true, use UTF-8 when decoding the string; otherwise
233 * use ISO-Latin-1 (8859_1). Use true for LDAPv3; false for LDAPv2.
234 * @param tag The tag that precedes the string.
235 * @return The non-null parsed string.
236 */
237 public String parseStringWithTag(int tag, boolean decodeUTF8, int rlen[])
238 throws DecodeException {
239
240 int st;
241 int origOffset = offset;
242
243 if ((st = parseByte()) != tag) {
244 throw new DecodeException("Encountered ASN.1 tag " +
245 Integer.toString((byte)st) + " (expected tag " + tag + ")");
246 }
247
248 int len = parseLength();
249
250 if (len > bufsize - offset) {
251 throw new DecodeException("Insufficient data");
252 }
253
254 String retstr;
255 if (len == 0) {
256 retstr = "";
257 } else {
258 byte[] buf2 = new byte[len];
259
260 System.arraycopy(buf, offset, buf2, 0, len);
261 if (decodeUTF8) {
262 try {
263 retstr = new String(buf2, "UTF8");
264 } catch (UnsupportedEncodingException e) {
265 throw new DecodeException("UTF8 not available on platform");
266 }
267 } else {
268 try {
269 retstr = new String(buf2, "8859_1");
270 } catch (UnsupportedEncodingException e) {
271 throw new DecodeException("8859_1 not available on platform");
272 }
273 }
274 offset += len;
275 }
276
277 if (rlen != null) {
278 rlen[0] = offset - origOffset;
279 }
280
281 return retstr;
282 }
283
284 /**
285 * Parses an octet string of a given type(tag) from this BER buffer.
286 * <blockquote><pre>
287 * BER Binary Data of type "tag" ::= tag length {byte}*
288 *</pre></blockquote>
289 *
290 * @param tag The tag to look for.
291 * @param rlen An array for returning the relative parsed position. If null,
292 * the relative parsed position is not returned.
293 * @return A non-null array containing the octet string.
294 * @throws DecodeException If the next byte in the BER buffer is not
295 * <tt>tag</tt>, or if length specified in the BER buffer exceeds the
296 * number of bytes left in the buffer.
297 */
298 public byte[] parseOctetString(int tag, int rlen[]) throws DecodeException {
299
300 int origOffset = offset;
301 int st;
302 if ((st = parseByte()) != tag) {
303
304 throw new DecodeException("Encountered ASN.1 tag " +
305 Integer.toString(st) +
306 " (expected tag " + Integer.toString(tag) + ")");
307 }
308
309 int len = parseLength();
310
311 if (len > bufsize - offset) {
312 throw new DecodeException("Insufficient data");
313 }
314
315 byte retarr[] = new byte[len];
316 if (len > 0) {
317 System.arraycopy(buf, offset, retarr, 0, len);
318 offset += len;
319 }
320
321 if (rlen != null) {
322 rlen[0] = offset - origOffset;
323 }
324
325 return retarr;
326 }
327
328 /**
329 * Returns the number of unparsed bytes in this BER buffer.
330 */
331 public int bytesLeft() {
332 return bufsize - offset;
333 }
334}