001: /*
002: * Copyright 1999 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.jndi.ldap;
027:
028: import java.io.UnsupportedEncodingException;
029:
030: /**
031: * A BER decoder. Contains methods to parse a BER buffer.
032: *
033: * @author Jagane Sundar
034: * @author Vincent Ryan
035: */
036: public final class BerDecoder extends Ber {
037:
038: private int origOffset; // The start point in buf to decode
039:
040: /**
041: * Creates a BER decoder that reads bytes from the specified buffer.
042: */
043: public BerDecoder(byte buf[], int offset, int bufsize) {
044:
045: this .buf = buf;
046: this .bufsize = bufsize;
047: this .origOffset = offset;
048:
049: reset();
050: }
051:
052: /**
053: * Resets this decode to start parsing from the initial offset
054: * (ie., same state as after calling the constructor).
055: */
056: public void reset() {
057: offset = origOffset;
058: }
059:
060: /**
061: * Returns the current parse position.
062: * It points to the byte that will be parsed next.
063: * Useful for parsing sequences.
064: */
065: public int getParsePosition() {
066: return offset;
067: }
068:
069: /**
070: * Parses a possibly variable length field.
071: */
072: public int parseLength() throws DecodeException {
073:
074: int lengthbyte = parseByte();
075:
076: if ((lengthbyte & 0x80) == 0x80) {
077:
078: lengthbyte &= 0x7f;
079:
080: if (lengthbyte == 0) {
081: throw new DecodeException(
082: "Indefinite length not supported");
083: }
084:
085: if (lengthbyte > 4) {
086: throw new DecodeException("encoding too long");
087: }
088:
089: if (bufsize - offset < lengthbyte) {
090: throw new DecodeException("Insufficient data");
091: }
092:
093: int retval = 0;
094:
095: for (int i = 0; i < lengthbyte; i++) {
096: retval = (retval << 8) + (buf[offset++] & 0xff);
097: }
098: return retval;
099: } 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: * Returns the next byte in this BER buffer without consuming it.
145: * @return The next byte.
146: */
147: public int peekByte() throws DecodeException {
148: if (bufsize - offset < 1) {
149: throw new DecodeException("Insufficient data");
150: }
151: return buf[offset] & 0xff;
152: }
153:
154: /**
155: * Parses an ASN_BOOLEAN tagged integer from this BER buffer.
156: * @return true if the tagged integer is 0; false otherwise.
157: */
158: public boolean parseBoolean() throws DecodeException {
159: return ((parseIntWithTag(ASN_BOOLEAN) == 0x00) ? false : true);
160: }
161:
162: /**
163: * Parses an ASN_ENUMERATED tagged integer from this BER buffer.
164: * @return The tag of enumeration.
165: */
166: public int parseEnumeration() throws DecodeException {
167: return parseIntWithTag(ASN_ENUMERATED);
168: }
169:
170: /**
171: * Parses an ASN_INTEGER tagged integer from this BER buffer.
172: * @return The value of the integer.
173: */
174: public int parseInt() throws DecodeException {
175: return parseIntWithTag(ASN_INTEGER);
176: }
177:
178: /**
179: * Parses an integer that's preceded by a tag.
180: *<blockquote><pre>
181: * BER integer ::= tag length byte {byte}*
182: *</pre></blockquote>
183: */
184: private int parseIntWithTag(int tag) throws DecodeException {
185:
186: if (parseByte() != tag) {
187: throw new DecodeException("Encountered ASN.1 tag "
188: + Integer.toString(buf[offset - 1] & 0xff)
189: + " (expected tag " + Integer.toString(tag) + ")");
190: }
191:
192: int len = parseLength();
193:
194: if (len > 4) {
195: throw new DecodeException("INTEGER too long");
196: } else if (len > bufsize - offset) {
197: throw new DecodeException("Insufficient data");
198: }
199:
200: byte fb = buf[offset++];
201: int value = 0;
202:
203: value = fb & 0x7F;
204: for (int i = 1 /* first byte already read */; i < len; i++) {
205: value <<= 8;
206: value |= (buf[offset++] & 0xff);
207: }
208:
209: if ((fb & 0x80) == 0x80) {
210: value = -value;
211: }
212:
213: return value;
214: }
215:
216: /**
217: * Parses a string.
218: */
219: public String parseString(boolean decodeUTF8)
220: throws DecodeException {
221: return parseStringWithTag(ASN_SIMPLE_STRING, decodeUTF8, null);
222: }
223:
224: /**
225: * Parses a string of a given tag from this BER buffer.
226: *<blockquote><pre>
227: *BER simple string ::= tag length {byte}*
228: *</pre></blockquote>
229: * @param rlen An array for holding the relative parsed offset; if null
230: * offset not set.
231: * @param decodeUTF8 If true, use UTF-8 when decoding the string; otherwise
232: * use ISO-Latin-1 (8859_1). Use true for LDAPv3; false for LDAPv2.
233: * @param tag The tag that precedes the string.
234: * @return The non-null parsed string.
235: */
236: public String parseStringWithTag(int tag, boolean decodeUTF8,
237: int rlen[]) throws DecodeException {
238:
239: int st;
240: int origOffset = offset;
241:
242: if ((st = parseByte()) != tag) {
243: throw new DecodeException("Encountered ASN.1 tag "
244: + Integer.toString((byte) st) + " (expected tag "
245: + 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(
266: "UTF8 not available on platform");
267: }
268: } else {
269: try {
270: retstr = new String(buf2, "8859_1");
271: } catch (UnsupportedEncodingException e) {
272: throw new DecodeException(
273: "8859_1 not available on platform");
274: }
275: }
276: offset += len;
277: }
278:
279: if (rlen != null) {
280: rlen[0] = offset - origOffset;
281: }
282:
283: return retstr;
284: }
285:
286: /**
287: * Parses an octet string of a given type(tag) from this BER buffer.
288: * <blockquote><pre>
289: * BER Binary Data of type "tag" ::= tag length {byte}*
290: *</pre></blockquote>
291: *
292: * @param tag The tag to look for.
293: * @param rlen An array for returning the relative parsed position. If null,
294: * the relative parsed position is not returned.
295: * @return A non-null array containing the octet string.
296: * @throws DecodeException If the next byte in the BER buffer is not
297: * <tt>tag</tt>, or if length specified in the BER buffer exceeds the
298: * number of bytes left in the buffer.
299: */
300: public byte[] parseOctetString(int tag, int rlen[])
301: throws DecodeException {
302:
303: int origOffset = offset;
304: int st;
305: if ((st = parseByte()) != tag) {
306:
307: throw new DecodeException("Encountered ASN.1 tag "
308: + Integer.toString(st) + " (expected tag "
309: + Integer.toString(tag) + ")");
310: }
311:
312: int len = parseLength();
313:
314: if (len > bufsize - offset) {
315: throw new DecodeException("Insufficient data");
316: }
317:
318: byte retarr[] = new byte[len];
319: if (len > 0) {
320: System.arraycopy(buf, offset, retarr, 0, len);
321: offset += len;
322: }
323:
324: if (rlen != null) {
325: rlen[0] = offset - origOffset;
326: }
327:
328: return retarr;
329: }
330:
331: /**
332: * Returns the number of unparsed bytes in this BER buffer.
333: */
334: public int bytesLeft() {
335: return bufsize - offset;
336: }
337: }
|