001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020 021package org.apache.directory.api.asn1.util; 022 023/** 024 * A buffer used to store an encoding PDU. It's auto-extended, and 025 * filled by the end. 026 * 027 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 028 */ 029public class Asn1Buffer2 030{ 031 /** The buffer default size */ 032 private static final int DEFAULT_SIZE = 1024; 033 034 /** The current position in the buffer */ 035 private int pos = 0; 036 037 /** The current size */ 038 private int size = DEFAULT_SIZE; 039 040 /** The internal buffer storage */ 041 private class InternalBuffer 042 { 043 /** A buffer to store the encoded PDU */ 044 private byte[] buffer = new byte[DEFAULT_SIZE]; 045 046 /** The next buffer, if any */ 047 private InternalBuffer next; 048 } 049 050 /** The current internal buffer */ 051 private InternalBuffer currentBuffer; 052 053 054 /** 055 * Create a new instance of Asn1Buffer2 056 */ 057 public Asn1Buffer2() 058 { 059 currentBuffer = new InternalBuffer(); 060 } 061 062 063 /** 064 * @return The current position in the buffer 065 */ 066 public int getPos() 067 { 068 return pos; 069 } 070 071 072 /** 073 * Store a byte at the current position in the buffer 074 * 075 * @param b The byte to store 076 */ 077 public void put( byte b ) 078 { 079 if ( pos == size ) 080 { 081 // The buffer needs to be reallocated, its too small 082 extend(); 083 } 084 085 currentBuffer.buffer[size - pos - 1] = b; 086 pos++; 087 } 088 089 090 /** 091 * Store some bytes at the current position in the buffer 092 * 093 * @param bytes The bytes to store 094 */ 095 public void put( byte[] bytes ) 096 { 097 int dataLength = bytes.length; 098 099 while ( true ) 100 { 101 int room = size - pos; 102 103 if ( dataLength > room ) 104 { 105 // First fulfill the current buffer 106 System.arraycopy( 107 bytes, 108 dataLength - room, 109 currentBuffer, 110 0, 111 room ); 112 113 dataLength -= room; 114 pos += room; 115 116 extend(); 117 } 118 else 119 { 120 // Last bytes are copied in the current buffer 121 System.arraycopy( 122 bytes, 123 0, 124 currentBuffer, 125 room - dataLength, 126 dataLength ); 127 128 pos += dataLength; 129 130 break; 131 } 132 } 133 } 134 135 136 /** 137 * Extend the buffer 138 */ 139 private void extend() 140 { 141 InternalBuffer newCurrentBuffer = new InternalBuffer(); 142 143 newCurrentBuffer.next = currentBuffer; 144 currentBuffer = newCurrentBuffer; 145 size += DEFAULT_SIZE; 146 } 147 148 149 /** 150 * @return The stored encoded PDU. 151 */ 152 public byte[] getBytes() 153 { 154 byte[] result = new byte[pos]; 155 156 InternalBuffer bufferPtr = currentBuffer; 157 int currentPos = 0; 158 int dataPos = size - pos; 159 int dataLength = DEFAULT_SIZE - dataPos; 160 161 while ( bufferPtr.next != null ) 162 { 163 System.arraycopy( 164 bufferPtr, 165 dataPos, 166 result, 167 currentPos, 168 dataLength ); 169 170 currentPos += dataLength; 171 dataPos = 0; 172 dataLength = DEFAULT_SIZE; 173 } 174 175 return result; 176 } 177 178 179 /** 180 * @return The buffer size (ie the maximum number of bytes that can be 181 * added to this buffer before it gets extended). 182 */ 183 public int getSize() 184 { 185 return size; 186 } 187 188 189 /** 190 * Clear the position, emptying the buffer. If it has grown, reallocate it 191 * to its initial size. 192 */ 193 public void clear() 194 { 195 pos = 0; 196 size = DEFAULT_SIZE; 197 198 // Un-reference the extended buffer. They will be garbage collected. 199 while ( currentBuffer.next != null ) 200 { 201 currentBuffer = currentBuffer.next; 202 } 203 } 204 205 206 /** 207 * {@inheritDoc} 208 */ 209 @Override 210 public String toString() 211 { 212 StringBuilder sb = new StringBuilder(); 213 sb.append( "[" ).append( size ).append( ", " ).append( pos ).append( "] )" ); 214 215 InternalBuffer bufferPtr = currentBuffer; 216 217 while ( bufferPtr.next != null ) 218 { 219 sb.append( "\n " ).append( Asn1StringUtils.dumpBytes( bufferPtr.buffer ) ); 220 } 221 222 return sb.toString(); 223 } 224}