Path: blob/master/src/java.naming/share/classes/com/sun/jndi/ldap/BerDecoder.java
41161 views
/*1* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.jndi.ldap;2627import java.io.UnsupportedEncodingException;2829/**30* A BER decoder. Contains methods to parse a BER buffer.31*32* @author Jagane Sundar33* @author Vincent Ryan34*/35public final class BerDecoder extends Ber {3637private int origOffset; // The start point in buf to decode3839/**40* Creates a BER decoder that reads bytes from the specified buffer.41*/42public BerDecoder(byte buf[], int offset, int bufsize) {4344this.buf = buf; // shared buffer, be careful to use this class45this.bufsize = bufsize;46this.origOffset = offset;4748reset();49}5051/**52* Resets this decode to start parsing from the initial offset53* (ie., same state as after calling the constructor).54*/55public void reset() {56offset = origOffset;57}5859/**60* Returns the current parse position.61* It points to the byte that will be parsed next.62* Useful for parsing sequences.63*/64public int getParsePosition() {65return offset;66}6768/**69* Parses a possibly variable length field.70*/71public int parseLength() throws DecodeException {7273int lengthbyte = parseByte();7475if ((lengthbyte & 0x80) == 0x80) {7677lengthbyte &= 0x7f;7879if (lengthbyte == 0) {80throw new DecodeException(81"Indefinite length not supported");82}8384if (lengthbyte > 4) {85throw new DecodeException("encoding too long");86}8788if (bufsize - offset < lengthbyte) {89throw new DecodeException("Insufficient data");90}9192int retval = 0;9394for( int i = 0; i < lengthbyte; i++) {95retval = (retval << 8) + (buf[offset++] & 0xff);96}97if (retval < 0) {98throw new DecodeException("Invalid length bytes");99}100return retval;101} else {102return lengthbyte;103}104}105106/**107* Parses the next sequence in this BER buffer.108* @param rlen An array for returning size of the sequence in bytes. If null,109* the size is not returned.110* @return The sequence's tag.111*/112public int parseSeq(int rlen[]) throws DecodeException {113114int seq = parseByte();115int len = parseLength();116if (rlen != null) {117rlen[0] = len;118}119return seq;120}121122/**123* Used to skip bytes. Usually used when trying to recover from parse error.124* Don't need to be public right now?125* @param i The number of bytes to skip126*/127void seek(int i) throws DecodeException {128if (offset + i > bufsize || offset + i < 0) {129throw new DecodeException("array index out of bounds");130}131offset += i;132}133134/**135* Parses the next byte in this BER buffer.136* @return The byte parsed.137*/138public int parseByte() throws DecodeException {139if (bufsize - offset < 1) {140throw new DecodeException("Insufficient data");141}142return buf[offset++] & 0xff;143}144145146/**147* Returns the next byte in this BER buffer without consuming it.148* @return The next byte.149*/150public int peekByte() throws DecodeException {151if (bufsize - offset < 1) {152throw new DecodeException("Insufficient data");153}154return buf[offset] & 0xff;155}156157/**158* Parses an ASN_BOOLEAN tagged integer from this BER buffer.159* @return true if the tagged integer is 0; false otherwise.160*/161public boolean parseBoolean() throws DecodeException {162return ((parseIntWithTag(ASN_BOOLEAN) == 0x00) ? false : true);163}164165/**166* Parses an ASN_ENUMERATED tagged integer from this BER buffer.167* @return The tag of enumeration.168*/169public int parseEnumeration() throws DecodeException {170return parseIntWithTag(ASN_ENUMERATED);171}172173/**174* Parses an ASN_INTEGER tagged integer from this BER buffer.175* @return The value of the integer.176*/177public int parseInt() throws DecodeException {178return parseIntWithTag(ASN_INTEGER);179}180181/**182* Parses an integer that's preceded by a tag.183*<blockquote><pre>184* BER integer ::= tag length byte {byte}*185*</pre></blockquote>186*/187private int parseIntWithTag(int tag) throws DecodeException {188if (parseByte() != tag) {189// Ber could have been reset;190String s;191if (offset > 0) {192s = Integer.toString(buf[offset - 1] & 0xff);193} else {194s = "Empty tag";195}196throw new DecodeException("Encountered ASN.1 tag " +197s + " (expected tag " + Integer.toString(tag) + ")");198}199200int len = parseLength();201202if (len > 4) {203throw new DecodeException("INTEGER too long");204} else if (len > bufsize - offset) {205throw new DecodeException("Insufficient data");206}207208byte fb = buf[offset++];209int value = 0;210211value = fb & 0x7F;212for( int i = 1 /* first byte already read */ ; i < len; i++) {213value <<= 8;214value |= (buf[offset++] & 0xff);215}216217if ((fb & 0x80) == 0x80) {218value = -value;219}220221return value;222}223224/**225* Parses a string.226*/227public String parseString(boolean decodeUTF8) throws DecodeException {228return parseStringWithTag(ASN_SIMPLE_STRING, decodeUTF8, null);229}230231/**232* Parses a string of a given tag from this BER buffer.233*<blockquote><pre>234*BER simple string ::= tag length {byte}*235*</pre></blockquote>236* @param rlen An array for holding the relative parsed offset; if null237* offset not set.238* @param decodeUTF8 If true, use UTF-8 when decoding the string; otherwise239* use ISO-Latin-1 (8859_1). Use true for LDAPv3; false for LDAPv2.240* @param tag The tag that precedes the string.241* @return The non-null parsed string.242*/243public String parseStringWithTag(int tag, boolean decodeUTF8, int rlen[])244throws DecodeException {245246int st;247int origOffset = offset;248249if ((st = parseByte()) != tag) {250throw new DecodeException("Encountered ASN.1 tag " +251Integer.toString((byte)st) + " (expected tag " + tag + ")");252}253254int len = parseLength();255256if (len > bufsize - offset) {257throw new DecodeException("Insufficient data");258}259260String retstr;261if (len == 0) {262retstr = "";263} else {264byte[] buf2 = new byte[len];265266System.arraycopy(buf, offset, buf2, 0, len);267if (decodeUTF8) {268try {269retstr = new String(buf2, "UTF8");270} catch (UnsupportedEncodingException e) {271throw new DecodeException("UTF8 not available on platform");272}273} else {274try {275retstr = new String(buf2, "8859_1");276} catch (UnsupportedEncodingException e) {277throw new DecodeException("8859_1 not available on platform");278}279}280offset += len;281}282283if (rlen != null) {284rlen[0] = offset - origOffset;285}286287return retstr;288}289290/**291* Parses an octet string of a given type(tag) from this BER buffer.292* <blockquote><pre>293* BER Binary Data of type "tag" ::= tag length {byte}*294*</pre></blockquote>295*296* @param tag The tag to look for.297* @param rlen An array for returning the relative parsed position. If null,298* the relative parsed position is not returned.299* @return A non-null array containing the octet string.300* @throws DecodeException If the next byte in the BER buffer is not301* {@code tag}, or if length specified in the BER buffer exceeds the302* number of bytes left in the buffer.303*/304public byte[] parseOctetString(int tag, int rlen[]) throws DecodeException {305306int origOffset = offset;307int st;308if ((st = parseByte()) != tag) {309310throw new DecodeException("Encountered ASN.1 tag " +311Integer.toString(st) +312" (expected tag " + Integer.toString(tag) + ")");313}314315int len = parseLength();316317if (len > bufsize - offset) {318throw new DecodeException("Insufficient data");319}320321byte retarr[] = new byte[len];322if (len > 0) {323System.arraycopy(buf, offset, retarr, 0, len);324offset += len;325}326327if (rlen != null) {328rlen[0] = offset - origOffset;329}330331return retarr;332}333334/**335* Returns the number of unparsed bytes in this BER buffer.336*/337public int bytesLeft() {338return bufsize - offset;339}340}341342343