Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/com/sun/jmx/snmp/BerDecoder.java
38924 views
/*1* Copyright (c) 1997, 2007, 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*/242526package com.sun.jmx.snmp;2728293031/**32* The <CODE>BerDecoder</CODE> class is used for decoding33* BER-encoded data.34*35* A <CODE>BerDecoder</CODE> needs to be set up with the byte string containing36* the encoding. It maintains a current position in the byte string.37*38* Methods allows to fetch integer, string, OID, etc., from the current39* position. After a fetch the current position is moved forward.40*41* A fetch throws a <CODE>BerException</CODE> if the encoding is not of the42* expected type.43*44* <p><b>This API is a Sun Microsystems internal API and is subject45* to change without notice.</b></p>46*47* @since 1.548*/4950public class BerDecoder {5152/**53* Constructs a new decoder and attaches it to the specified byte string.54*55* @param b The byte string containing the encoded data.56*/5758public BerDecoder(byte b[]) {59bytes = b ;60reset() ;61}6263public void reset() {64next = 0 ;65stackTop = 0 ;66}6768/**69* Fetch an integer.70*71* @return The decoded integer.72*73* @exception BerException Current position does not point to an integer.74*/7576public int fetchInteger() throws BerException {77return fetchInteger(IntegerTag) ;78}798081/**82* Fetch an integer with the specified tag.83*84* @param tag The expected tag.85*86* @return The decoded integer.87*88* @exception BerException Current position does not point to an integer89* or the tag is not the expected one.90*/9192public int fetchInteger(int tag) throws BerException {93int result = 0 ;94final int backup = next ;95try {96if (fetchTag() != tag) {97throw new BerException() ;98}99result = fetchIntegerValue() ;100}101catch(BerException e) {102next = backup ;103throw e ;104}105106return result ;107}108109110111/**112* Fetch an integer and return a long value.113*114* @return The decoded integer.115*116* @exception BerException Current position does not point to an integer.117*/118119public long fetchIntegerAsLong() throws BerException {120return fetchIntegerAsLong(IntegerTag) ;121}122123124/**125* Fetch an integer with the specified tag and return a long value.126*127* @param tag The expected tag.128*129* @return The decoded integer.130*131* @exception BerException Current position does not point to an integer132* or the tag is not the expected one.133*/134135public long fetchIntegerAsLong(int tag) throws BerException {136long result = 0 ;137final int backup = next ;138try {139if (fetchTag() != tag) {140throw new BerException() ;141}142result = fetchIntegerValueAsLong() ;143}144catch(BerException e) {145next = backup ;146throw e ;147}148149return result ;150}151152153154/**155* Fetch an octet string.156*157* @return The decoded string.158*159* @exception BerException Current position does not point to an octet string.160*/161162public byte[] fetchOctetString() throws BerException {163return fetchOctetString(OctetStringTag) ;164}165166167/**168* Fetch an octet string with a specified tag.169*170* @param tag The expected tag.171*172* @return The decoded string.173*174* @exception BerException Current position does not point to an octet string175* or the tag is not the expected one.176*/177178public byte[] fetchOctetString(int tag) throws BerException {179byte[] result = null ;180final int backup = next ;181try {182if (fetchTag() != tag) {183throw new BerException() ;184}185result = fetchStringValue() ;186}187catch(BerException e) {188next = backup ;189throw e ;190}191192return result ;193}194195196/**197* Fetch an object identifier.198*199* @return The decoded object identifier as an array of long.200*/201202public long[] fetchOid() throws BerException {203return fetchOid(OidTag) ;204}205206207/**208* Fetch an object identifier with a specified tag.209*210* @param tag The expected tag.211*212* @return The decoded object identifier as an array of long.213*214* @exception BerException Current position does not point to an oid215* or the tag is not the expected one.216*/217218public long[] fetchOid(int tag) throws BerException {219long[] result = null ;220final int backup = next ;221try {222if (fetchTag() != tag) {223throw new BerException() ;224}225result = fetchOidValue() ;226}227catch(BerException e) {228next = backup ;229throw e ;230}231232return result ;233}234235236/**237* Fetch a <CODE>NULL</CODE> value.238*239* @exception BerException Current position does not point to <CODE>NULL</CODE> value.240*/241242public void fetchNull() throws BerException {243fetchNull(NullTag) ;244}245246247/**248* Fetch a <CODE>NULL</CODE> value with a specified tag.249*250* @param tag The expected tag.251*252* @exception BerException Current position does not point to253* <CODE>NULL</CODE> value or the tag is not the expected one.254*/255256public void fetchNull(int tag) throws BerException {257final int backup = next ;258try {259if (fetchTag() != tag) {260throw new BerException() ;261}262final int length = fetchLength();263if (length != 0) throw new BerException();264}265catch(BerException e) {266next = backup ;267throw e ;268}269}270271272273/**274* Fetch an <CODE>ANY</CODE> value. In fact, this method does not decode anything275* it simply returns the next TLV as an array of bytes.276*277* @return The TLV as a byte array.278*279* @exception BerException The next TLV is really badly encoded...280*/281282public byte[] fetchAny() throws BerException {283byte[] result = null ;284final int backup = next ;285try {286final int tag = fetchTag() ;287final int contentLength = fetchLength() ;288if (contentLength < 0) throw new BerException() ;289final int tlvLength = next + contentLength - backup ;290if (contentLength > (bytes.length - next))291throw new IndexOutOfBoundsException("Decoded length exceeds buffer");292final byte[] data = new byte[tlvLength] ;293java.lang.System.arraycopy(bytes,backup,data,0,tlvLength);294// for (int i = 0 ; i < tlvLength ; i++) {295// data[i] = bytes[backup + i] ;296// }297next = next + contentLength ;298result = data;299}300catch(IndexOutOfBoundsException e) {301next = backup ;302throw new BerException() ;303}304// catch(Error e) {305// debug("fetchAny: Error decoding BER: " + e);306// throw e;307// }308309return result ;310}311312313/**314* Fetch an <CODE>ANY</CODE> value with a specific tag.315*316* @param tag The expected tag.317*318* @return The TLV as a byte array.319*320* @exception BerException The next TLV is really badly encoded...321*/322323public byte[] fetchAny(int tag) throws BerException {324if (getTag() != tag) {325throw new BerException() ;326}327return fetchAny() ;328}329330331332/**333* Fetch a sequence header.334* The decoder computes the end position of the sequence and push it335* on its stack.336*337* @exception BerException Current position does not point to a sequence header.338*/339340public void openSequence() throws BerException {341openSequence(SequenceTag) ;342}343344345/**346* Fetch a sequence header with a specific tag.347*348* @param tag The expected tag.349*350* @exception BerException Current position does not point to a sequence header351* or the tag is not the expected one.352*/353354public void openSequence(int tag) throws BerException {355final int backup = next ;356try {357if (fetchTag() != tag) {358throw new BerException() ;359}360final int l = fetchLength() ;361if (l < 0) throw new BerException();362if (l > (bytes.length - next)) throw new BerException();363stackBuf[stackTop++] = next + l ;364}365catch(BerException e) {366next = backup ;367throw e ;368}369}370371372/**373* Close a sequence.374* The decode pull the stack and verifies that the current position375* matches with the calculated end of the sequence. If not it throws376* an exception.377*378* @exception BerException The sequence is not expected to finish here.379*/380381public void closeSequence() throws BerException {382if (stackBuf[stackTop - 1] == next) {383stackTop-- ;384}385else {386throw new BerException() ;387}388}389390391/**392* Return <CODE>true</CODE> if the end of the current sequence is not reached.393* When this method returns <CODE>false</CODE>, <CODE>closeSequence</CODE> can (and must) be394* invoked.395*396* @return <CODE>true</CODE> if there is still some data in the sequence.397*/398399public boolean cannotCloseSequence() {400return (next < stackBuf[stackTop - 1]) ;401}402403404/**405* Get the tag of the data at the current position.406* Current position is unchanged.407*408* @return The next tag.409*/410411public int getTag() throws BerException {412int result = 0 ;413final int backup = next ;414try {415result = fetchTag() ;416}417finally {418next = backup ;419}420421return result ;422}423424425426public String toString() {427final StringBuffer result = new StringBuffer(bytes.length * 2) ;428for (int i = 0 ; i < bytes.length ; i++) {429final int b = (bytes[i] > 0) ? bytes[i] : bytes[i] + 256 ;430if (i == next) {431result.append("(") ;432}433result.append(Character.forDigit(b / 16, 16)) ;434result.append(Character.forDigit(b % 16, 16)) ;435if (i == next) {436result.append(")") ;437}438}439if (bytes.length == next) {440result.append("()") ;441}442443return new String(result) ;444}445446447//448// Some standard tags449//450public final static int BooleanTag = 1 ;451public final static int IntegerTag = 2 ;452public final static int OctetStringTag = 4 ;453public final static int NullTag = 5 ;454public final static int OidTag = 6 ;455public final static int SequenceTag = 0x30 ;456457458459460////////////////////////// PRIVATE ///////////////////////////////461462463464/**465* Fetch a tag and move the current position forward.466*467* @return The tag468*/469470private final int fetchTag() throws BerException {471int result = 0 ;472final int backup = next ;473474try {475final byte b0 = bytes[next++] ;476result = (b0 >= 0) ? b0 : b0 + 256 ;477if ((result & 31) == 31) {478while ((bytes[next] & 128) != 0) {479result = result << 7 ;480result = result | (bytes[next++] & 127);481}482}483}484catch(IndexOutOfBoundsException e) {485next = backup ;486throw new BerException() ;487}488489return result ;490}491492493/**494* Fetch a length and move the current position forward.495*496* @return The length497*/498499private final int fetchLength() throws BerException {500int result = 0 ;501final int backup = next ;502503try {504final byte b0 = bytes[next++] ;505if (b0 >= 0) {506result = b0 ;507}508else {509for (int c = 128 + b0 ; c > 0 ; c--) {510final byte bX = bytes[next++] ;511result = result << 8 ;512result = result | ((bX >= 0) ? bX : bX+256) ;513}514}515}516catch(IndexOutOfBoundsException e) {517next = backup ;518throw new BerException() ;519}520521return result ;522}523524525/**526* Fetch an integer value and move the current position forward.527*528* @return The integer529*/530531private int fetchIntegerValue() throws BerException {532int result = 0 ;533final int backup = next ;534535try {536final int length = fetchLength() ;537if (length <= 0) throw new BerException() ;538if (length > (bytes.length - next)) throw539new IndexOutOfBoundsException("Decoded length exceeds buffer");540final int end = next + length ;541result = bytes[next++] ;542while (next < end) {543final byte b = bytes[next++] ;544if (b < 0) {545result = (result << 8) | (256 + b) ;546}547else {548result = (result << 8) | b ;549}550}551}552catch(BerException e) {553next = backup ;554throw e ;555}556catch(IndexOutOfBoundsException e) {557next = backup ;558throw new BerException() ;559}560catch(ArithmeticException e) {561next = backup ;562throw new BerException() ;563}564return result ;565}566567568/**569* Fetch an integer value and return a long value.570* FIX ME: someday we could have only on fetchIntegerValue() which always571* returns a long value.572*573* @return The integer574*/575576private final long fetchIntegerValueAsLong() throws BerException {577long result = 0 ;578final int backup = next ;579580try {581final int length = fetchLength() ;582if (length <= 0) throw new BerException() ;583if (length > (bytes.length - next)) throw584new IndexOutOfBoundsException("Decoded length exceeds buffer");585586final int end = next + length ;587result = bytes[next++] ;588while (next < end) {589final byte b = bytes[next++] ;590if (b < 0) {591result = (result << 8) | (256 + b) ;592}593else {594result = (result << 8) | b ;595}596}597}598catch(BerException e) {599next = backup ;600throw e ;601}602catch(IndexOutOfBoundsException e) {603next = backup ;604throw new BerException() ;605}606catch(ArithmeticException e) {607next = backup ;608throw new BerException() ;609}610return result ;611}612613614/**615* Fetch a byte string and move the current position forward.616*617* @return The byte string618*/619620private byte[] fetchStringValue() throws BerException {621byte[] result = null ;622final int backup = next ;623624try {625final int length = fetchLength() ;626if (length < 0) throw new BerException() ;627if (length > (bytes.length - next))628throw new IndexOutOfBoundsException("Decoded length exceeds buffer");629final byte data[] = new byte[length] ;630java.lang.System.arraycopy(bytes,next,data,0,length);631next += length;632// int i = 0 ;633// while (i < length) {634// result[i++] = bytes[next++] ;635// }636result = data;637}638catch(BerException e) {639next = backup ;640throw e ;641}642catch(IndexOutOfBoundsException e) {643next = backup ;644throw new BerException() ;645}646catch(ArithmeticException e) {647next = backup ;648throw new BerException() ;649}650// catch(Error e) {651// debug("fetchStringValue: Error decoding BER: " + e);652// throw e;653// }654655return result ;656}657658659660/**661* Fetch an oid and move the current position forward.662*663* @return The oid664*/665666private final long[] fetchOidValue() throws BerException {667long[] result = null ;668final int backup = next ;669670try {671final int length = fetchLength() ;672if (length <= 0) throw new BerException() ;673if (length > (bytes.length - next))674throw new IndexOutOfBoundsException("Decoded length exceeds buffer");675// Count how many bytes have their 8th bit to 0676// -> this gives the number of components in the oid677int subidCount = 2 ;678for (int i = 1 ; i < length ; i++) {679if ((bytes[next + i] & 0x80) == 0) {680subidCount++ ;681}682}683final int datalen = subidCount;684final long[] data = new long[datalen];685final byte b0 = bytes[next++] ;686687// bugId 4641746688// The 8th bit of the first byte should always be set to 0689if (b0 < 0) throw new BerException();690691// bugId 4641746692// The first sub Id cannot be greater than 2693final long lb0 = b0 / 40 ;694if (lb0 > 2) throw new BerException();695696final long lb1 = b0 % 40;697data[0] = lb0 ;698data[1] = lb1 ;699int i = 2 ;700while (i < datalen) {701long subid = 0 ;702byte b = bytes[next++] ;703while ((b & 0x80) != 0) {704subid = (subid << 7) | (b & 0x7f) ;705// bugId 4654674706if (subid < 0) throw new BerException();707b = bytes[next++] ;708}709subid = (subid << 7) | b ;710// bugId 4654674711if (subid < 0) throw new BerException();712data[i++] = subid ;713}714result = data;715}716catch(BerException e) {717next = backup ;718throw e ;719}720catch(IndexOutOfBoundsException e) {721next = backup ;722throw new BerException() ;723}724// catch(Error e) {725// debug("fetchOidValue: Error decoding BER: " + e);726// throw e;727// }728729return result ;730}731732// private static final void debug(String str) {733// System.out.println(str);734// }735736//737// This is the byte array containing the encoding.738//739private final byte bytes[];740741//742// This is the current location. It is the next byte743// to be decoded. It's an index in bytes[].744//745private int next = 0 ;746747//748// This is the stack where end of sequences are kept.749// A value is computed and pushed in it each time openSequence()750// is invoked.751// A value is pulled and checked each time closeSequence() is called.752//753private final int stackBuf[] = new int[200] ;754private int stackTop = 0 ;755756}757758759