Path: blob/master/src/java.naming/share/classes/com/sun/jndi/ldap/BerEncoder.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 encoder.31*32* @author Jagane Sundar33* @author Scott Seligman34* @author Vincent Ryan35*/36public final class BerEncoder extends Ber {3738private int curSeqIndex;39private int seqOffset[];40private static final int INITIAL_SEQUENCES = 16;41private static final int DEFAULT_BUFSIZE = 1024;4243// When buf is full, expand its size by the following factor.44private static final int BUF_GROWTH_FACTOR = 8;4546/**47* Creates a BER buffer for encoding.48*/49public BerEncoder() {50this(DEFAULT_BUFSIZE);51}5253/**54* Creates a BER buffer of a specified size for encoding.55* Specify the initial bufsize. Buffer will be expanded as needed.56* @param bufsize The number of bytes for the buffer.57*/58public BerEncoder(int bufsize) {59buf = new byte[bufsize];60this.bufsize = bufsize;61offset = 0;6263seqOffset = new int[INITIAL_SEQUENCES];64curSeqIndex = 0;65}6667/**68* Resets encoder to state when newly constructed. Zeros out69* internal data structures.70*/71public void reset() {72while (offset > 0) {73buf[--offset] = 0;74}75while (curSeqIndex > 0) {76seqOffset[--curSeqIndex] = 0;77}78}7980// ------------------ Accessor methods ------------8182/**83* Gets the number of encoded bytes in this BER buffer.84*/85public int getDataLen() {86return offset;87}8889/**90* Gets the buffer that contains the BER encoding. Throws an91* exception if unmatched beginSeq() and endSeq() pairs were92* encountered. Not entire buffer contains encoded bytes.93* Use getDataLen() to determine number of encoded bytes.94* Use getBuffer(true) to get rid of excess bytes in array.95* @throws IllegalStateException If buffer contains unbalanced sequence.96*/97public byte[] getBuf() {98if (curSeqIndex != 0) {99throw new IllegalStateException("BER encode error: Unbalanced SEQUENCEs.");100}101return buf; // shared buffer, be careful to use this method.102}103104/**105* Gets the buffer that contains the BER encoding, trimming unused bytes.106*107* @throws IllegalStateException If buffer contains unbalanced sequence.108*/109public byte[] getTrimmedBuf() {110int len = getDataLen();111byte[] trimBuf = new byte[len];112113System.arraycopy(getBuf(), 0, trimBuf, 0, len);114return trimBuf;115}116117// -------------- encoding methods -------------118119/**120* Begin encoding a sequence with a tag.121*/122public void beginSeq(int tag) {123124// Double the size of the SEQUENCE array if it overflows125if (curSeqIndex >= seqOffset.length) {126int[] seqOffsetTmp = new int[seqOffset.length * 2];127128for (int i = 0; i < seqOffset.length; i++) {129seqOffsetTmp[i] = seqOffset[i];130}131seqOffset = seqOffsetTmp;132}133134encodeByte(tag);135seqOffset[curSeqIndex] = offset;136137// Save space for sequence length.138// %%% Currently we save enough space for sequences up to 64k.139// For larger sequences we'll need to shift the data to the right140// in endSeq(). If we could instead pad the length field with141// zeros, it would be a big win.142ensureFreeBytes(3);143offset += 3;144145curSeqIndex++;146}147148/**149* Terminate a BER sequence.150*/151public void endSeq() throws EncodeException {152curSeqIndex--;153if (curSeqIndex < 0) {154throw new IllegalStateException("BER encode error: Unbalanced SEQUENCEs.");155}156157int start = seqOffset[curSeqIndex] + 3; // index beyond length field158int len = offset - start;159160if (len <= 0x7f) {161shiftSeqData(start, len, -2);162buf[seqOffset[curSeqIndex]] = (byte) len;163} else if (len <= 0xff) {164shiftSeqData(start, len, -1);165buf[seqOffset[curSeqIndex]] = (byte) 0x81;166buf[seqOffset[curSeqIndex] + 1] = (byte) len;167} else if (len <= 0xffff) {168buf[seqOffset[curSeqIndex]] = (byte) 0x82;169buf[seqOffset[curSeqIndex] + 1] = (byte) (len >> 8);170buf[seqOffset[curSeqIndex] + 2] = (byte) len;171} else if (len <= 0xffffff) {172shiftSeqData(start, len, 1);173buf[seqOffset[curSeqIndex]] = (byte) 0x83;174buf[seqOffset[curSeqIndex] + 1] = (byte) (len >> 16);175buf[seqOffset[curSeqIndex] + 2] = (byte) (len >> 8);176buf[seqOffset[curSeqIndex] + 3] = (byte) len;177} else {178throw new EncodeException("SEQUENCE too long");179}180}181182/**183* Shifts contents of buf in the range [start,start+len) a specified amount.184* Positive shift value means shift to the right.185*/186private void shiftSeqData(int start, int len, int shift) {187if (shift > 0) {188ensureFreeBytes(shift);189}190System.arraycopy(buf, start, buf, start + shift, len);191offset += shift;192}193194/**195* Encode a single byte.196*/197public void encodeByte(int b) {198ensureFreeBytes(1);199buf[offset++] = (byte) b;200}201202/*203private void deleteByte() {204offset--;205}206*/207208209/*210* Encodes an int.211*<blockquote><pre>212* BER integer ::= 0x02 berlength byte {byte}*213*</pre></blockquote>214*/215public void encodeInt(int i) {216encodeInt(i, 0x02);217}218219/**220* Encodes an int and a tag.221*<blockquote><pre>222* BER integer w tag ::= tag berlength byte {byte}*223*</pre></blockquote>224*/225public void encodeInt(int i, int tag) {226int mask = 0xff800000;227int intsize = 4;228229while( (((i & mask) == 0) || ((i & mask) == mask)) && (intsize > 1) ) {230intsize--;231i <<= 8;232}233234encodeInt(i, tag, intsize);235}236237//238// encodes an int using numbytes for the actual encoding.239//240private void encodeInt(int i, int tag, int intsize) {241242//243// integer ::= 0x02 asnlength byte {byte}*244//245246if (intsize > 4) {247throw new IllegalArgumentException("BER encode error: INTEGER too long.");248}249250ensureFreeBytes(2 + intsize);251252buf[offset++] = (byte) tag;253buf[offset++] = (byte) intsize;254255int mask = 0xff000000;256257while (intsize-- > 0) {258buf[offset++] = (byte) ((i & mask) >> 24);259i <<= 8;260}261}262263/**264* Encodes a boolean.265*<blockquote><pre>266* BER boolean ::= 0x01 0x01 {0xff|0x00}267*</pre></blockquote>268*/269public void encodeBoolean(boolean b) {270encodeBoolean(b, ASN_BOOLEAN);271}272273274/**275* Encodes a boolean and a tag276*<blockquote><pre>277* BER boolean w TAG ::= tag 0x01 {0xff|0x00}278*</pre></blockquote>279*/280public void encodeBoolean(boolean b, int tag) {281ensureFreeBytes(3);282283buf[offset++] = (byte) tag;284buf[offset++] = 0x01;285buf[offset++] = b ? (byte) 0xff : (byte) 0x00;286}287288/**289* Encodes a string.290*<blockquote><pre>291* BER string ::= 0x04 strlen byte1 byte2...292*</pre></blockquote>293* The string is converted into bytes using UTF-8 or ISO-Latin-1.294*/295public void encodeString(String str, boolean encodeUTF8)296throws EncodeException {297encodeString(str, ASN_OCTET_STR, encodeUTF8);298}299300/**301* Encodes a string and a tag.302*<blockquote><pre>303* BER string w TAG ::= tag strlen byte1 byte2...304*</pre></blockquote>305*/306public void encodeString(String str, int tag, boolean encodeUTF8)307throws EncodeException {308309encodeByte(tag);310311int i = 0;312int count;313byte[] bytes = null;314315if (str == null) {316count = 0;317} else if (encodeUTF8) {318try {319bytes = str.getBytes("UTF8");320count = bytes.length;321} catch (UnsupportedEncodingException e) {322throw new EncodeException("UTF8 not available on platform");323}324} else {325try {326bytes = str.getBytes("8859_1");327count = bytes.length;328} catch (UnsupportedEncodingException e) {329throw new EncodeException("8859_1 not available on platform");330}331}332333encodeLength(count);334335ensureFreeBytes(count);336while (i < count) {337buf[offset++] = bytes[i++];338}339}340341/**342* Encodes a portion of an octet string and a tag.343*/344public void encodeOctetString(byte tb[], int tag, int tboffset, int length)345throws EncodeException {346347encodeByte(tag);348encodeLength(length);349350if (length > 0) {351ensureFreeBytes(length);352System.arraycopy(tb, tboffset, buf, offset, length);353offset += length;354}355}356357/**358* Encodes an octet string and a tag.359*/360public void encodeOctetString(byte tb[], int tag) throws EncodeException {361encodeOctetString(tb, tag, 0, tb.length);362}363364private void encodeLength(int len) throws EncodeException {365ensureFreeBytes(4); // worst case366367if (len < 128) {368buf[offset++] = (byte) len;369} else if (len <= 0xff) {370buf[offset++] = (byte) 0x81;371buf[offset++] = (byte) len;372} else if (len <= 0xffff) {373buf[offset++] = (byte) 0x82;374buf[offset++] = (byte) (len >> 8);375buf[offset++] = (byte) (len & 0xff);376} else if (len <= 0xffffff) {377buf[offset++] = (byte) 0x83;378buf[offset++] = (byte) (len >> 16);379buf[offset++] = (byte) (len >> 8);380buf[offset++] = (byte) (len & 0xff);381} else {382throw new EncodeException("string too long");383}384}385386/**387* Encodes an array of strings.388*/389public void encodeStringArray(String strs[], boolean encodeUTF8)390throws EncodeException {391if (strs == null)392return;393for (int i = 0; i < strs.length; i++) {394encodeString(strs[i], encodeUTF8);395}396}397/*398private void encodeNull() {399400//401// NULL ::= 0x05 0x00402//403encodeByte(0x05);404encodeByte(0x00);405}406*/407408/**409* Ensures that there are at least "len" unused bytes in "buf".410* When more space is needed "buf" is expanded by a factor of411* BUF_GROWTH_FACTOR, then "len" bytes are added if "buf" still412* isn't large enough.413*/414private void ensureFreeBytes(int len) {415if (bufsize - offset < len) {416int newsize = bufsize * BUF_GROWTH_FACTOR;417if (newsize - offset < len) {418newsize += len;419}420byte newbuf[] = new byte[newsize];421// Only copy bytes in the range [0, offset)422System.arraycopy(buf, 0, newbuf, 0, offset);423424buf = newbuf;425bufsize = newsize;426}427}428}429430431