View Javadoc
1   /*
2    *   Licensed to the Apache Software Foundation (ASF) under one
3    *   or more contributor license agreements.  See the NOTICE file
4    *   distributed with this work for additional information
5    *   regarding copyright ownership.  The ASF licenses this file
6    *   to you under the Apache License, Version 2.0 (the
7    *   "License"); you may not use this file except in compliance
8    *   with the License.  You may obtain a copy of the License at
9    *
10   *     https://www.apache.org/licenses/LICENSE-2.0
11   *
12   *   Unless required by applicable law or agreed to in writing,
13   *   software distributed under the License is distributed on an
14   *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *   KIND, either express or implied.  See the License for the
16   *   specific language governing permissions and limitations
17   *   under the License.
18   *
19   */
20  
21  package org.apache.directory.api.asn1.util;
22  
23  /**
24   * A buffer used to store an encoding PDU. It's auto-extended, and
25   * filled by the end.
26   *
27   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
28   */
29  public class Asn1Buffer2
30  {
31      /** The buffer default size */
32      private static final int DEFAULT_SIZE = 1024;
33  
34      /** The current position in the buffer */
35      private int pos = 0;
36  
37      /** The current size */
38      private int size = DEFAULT_SIZE;
39  
40      /** The internal buffer storage */
41      private class InternalBuffer
42      {
43          /** A buffer to store the encoded PDU */
44          private byte[] buffer = new byte[DEFAULT_SIZE];
45  
46          /** The next buffer, if any */
47          private InternalBuffer next;
48      }
49  
50      /** The current internal buffer */
51      private InternalBuffer currentBuffer;
52  
53  
54      /**
55       * Create a new instance of Asn1Buffer2
56       */
57      public Asn1Buffer2()
58      {
59          currentBuffer = new InternalBuffer();
60      }
61  
62  
63      /**
64       * @return The current position in the buffer
65       */
66      public int getPos()
67      {
68          return pos;
69      }
70  
71  
72      /**
73       * Store a byte at the current position in the buffer
74       *
75       * @param b The byte to store
76       */
77      public void put( byte b )
78      {
79          if ( pos == size )
80          {
81              // The buffer needs to be reallocated, its too small
82              extend();
83          }
84  
85          currentBuffer.buffer[size - pos - 1] = b;
86          pos++;
87      }
88  
89  
90      /**
91       * Store some bytes at the current position in the buffer
92       *
93       * @param bytes The bytes to store
94       */
95      public void put( byte[] bytes )
96      {
97          int dataLength = bytes.length;
98  
99          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 }