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 *    http://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 */
020package org.apache.directory.shared.asn1.ber;
021
022
023import java.nio.ByteBuffer;
024
025import org.apache.directory.shared.asn1.ber.grammar.Grammar;
026import org.apache.directory.shared.asn1.ber.grammar.States;
027import org.apache.directory.shared.asn1.ber.tlv.TLV;
028import org.apache.directory.shared.asn1.ber.tlv.TLVStateEnum;
029
030
031/**
032 * This class is the abstract container used to store the current state of a PDU
033 * being decoded. It also stores the grammars used to decode the PDU, and all
034 * the informations needed to decode a PDU.
035 *
036 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
037 */
038public abstract class AbstractContainer implements Asn1Container
039{
040    /** All the possible grammars */
041    protected Grammar<?> grammar;
042
043    /** Store a stack of the current states used when switching grammars */
044    protected int[] stateStack;
045
046    /** The current state of the decoding */
047    private TLVStateEnum state;
048
049    /** The current transition */
050    private Enum<?> transition;
051
052    /** The current TLV */
053    private TLV tlv;
054
055    /** The parent TLV */
056    private TLV parentTLV;
057
058    /** The grammar end transition flag */
059    private boolean grammarEndAllowed;
060
061    /** A counter for the decoded bytes */
062    protected int decodeBytes;
063
064    /** The maximum allowed size for a PDU. Default to MAX int value */
065    private int maxPDUSize = Integer.MAX_VALUE;
066
067    /** The incremental id used to tag TLVs */
068    private int id = 0;
069
070    /** The Stream being decoded */
071    private ByteBuffer stream;
072
073    /** A flag telling if the Value should be accumulated before being decoded
074     * for constructed types */
075    private boolean isGathering = false;
076
077    /**
078     * Creates a new instance of AbstractContainer with a starting state.
079     *
080     */
081    protected AbstractContainer()
082    {
083        state = TLVStateEnum.TAG_STATE_START;
084    }
085
086
087    /**
088     * Creates a new instance of AbstractContainer with a starting state.
089     *
090     * @param stream the buffer containing the data to decode
091     */
092    protected AbstractContainer( ByteBuffer stream )
093    {
094        state = TLVStateEnum.TAG_STATE_START;
095        this.stream = stream;
096    }
097
098
099    /**
100     * Get the current grammar
101     *
102     * @return Returns the grammar used to decode a LdapMessage.
103     */
104    public Grammar<?> getGrammar()
105    {
106        return grammar;
107    }
108
109
110    /**
111     * Get the current grammar state
112     *
113     * @return Returns the current grammar state
114     */
115    public TLVStateEnum getState()
116    {
117        return state;
118    }
119
120
121    /**
122     * Set the new current state
123     *
124     * @param state The new state
125     */
126    public void setState( TLVStateEnum state )
127    {
128        this.state = state;
129    }
130
131
132    /**
133     * Check that we can have a end state after this transition
134     *
135     * @return true if this can be the last transition
136     */
137    public boolean isGrammarEndAllowed()
138    {
139        return grammarEndAllowed;
140    }
141
142
143    /**
144     * Set the flag to allow a end transition
145     *
146     * @param grammarEndAllowed true or false, depending on the next transition
147     * being an end or not.
148     */
149    public void setGrammarEndAllowed( boolean grammarEndAllowed )
150    {
151        this.grammarEndAllowed = grammarEndAllowed;
152    }
153
154
155    /**
156     * Get the transition
157     *
158     * @return Returns the transition from the previous state to the new state
159     */
160    public Enum<?> getTransition()
161    {
162        return transition;
163    }
164
165
166    /**
167     * Update the transition from a state to another
168     *
169     * @param transition The transition to set
170     */
171    public void setTransition( Enum<?> transition )
172    {
173        this.transition = transition;
174    }
175
176
177    /**
178     * Set the current TLV
179     *
180     * @param currentTLV The current TLV
181     */
182    public void setCurrentTLV( TLV currentTLV )
183    {
184        this.tlv = currentTLV;
185    }
186
187
188    /**
189     * Get the current TLV
190     *
191     * @return Returns the current TLV being decoded
192     */
193    public TLV getCurrentTLV()
194    {
195        return this.tlv;
196    }
197
198
199    /**
200     * Get the parent TLV;
201     *
202     * @return Returns the parent TLV, if any.
203     */
204    public TLV getParentTLV()
205    {
206        return parentTLV;
207    }
208
209
210    /**
211     * Set the parent TLV.
212     *
213     * @param parentTLV The parent TLV to set.
214     */
215    public void setParentTLV( TLV parentTLV )
216    {
217        this.parentTLV = parentTLV;
218    }
219
220
221    /**
222     * Clean the container for the next usage.
223     */
224    public void clean()
225    {
226        tlv = null;
227        parentTLV = null;
228        transition = ( ( States ) transition ).getStartState();
229        state = TLVStateEnum.TAG_STATE_START;
230    }
231
232
233    /**
234     * Return a new ID and increment the counter
235     * @return A new TLV id.
236     */
237    public int getNewTlvId()
238    {
239        return id++;
240    }
241
242
243    /**
244     * @return The TLV Id
245     */
246    public int getTlvId()
247    {
248        return tlv.getId();
249    }
250
251
252    /**
253     * @return The number of decoded bytes for this message. This is used
254     * to control the PDU size and avoid PDU exceeding the maximum allowed
255     * size to break the server.
256     */
257    public int getDecodeBytes()
258    {
259        return decodeBytes;
260    }
261
262
263    /**
264     * Increment the decodedBytes by the latest received buffer's size.
265     * @param nb The buffer size.
266     */
267    public void incrementDecodeBytes( int nb )
268    {
269        decodeBytes += nb;
270    }
271
272
273    /**
274     * @return The maximum PDU size.
275     */
276    public int getMaxPDUSize()
277    {
278        return maxPDUSize;
279    }
280
281
282    /**
283     * Set the maximum PDU size.
284     * @param maxPDUSize The maximum PDU size (if negative or null, will be
285     * replaced by the max integer value)
286     */
287    public void setMaxPDUSize( int maxPDUSize )
288    {
289        if ( maxPDUSize > 0 )
290        {
291            this.maxPDUSize = maxPDUSize;
292        }
293        else
294        {
295            this.maxPDUSize = Integer.MAX_VALUE;
296        }
297    }
298
299
300    /**
301     * {@inheritDoc}
302     */
303    public ByteBuffer getStream()
304    {
305        return stream;
306    }
307
308
309    /**
310     * {@inheritDoc}
311     */
312    public void setStream( ByteBuffer stream )
313    {
314        this.stream = stream;
315    }
316
317
318    /**
319     * {@inheritDoc}
320     */
321    public void rewind()
322    {
323
324        int start = stream.position() - 1 - tlv.getLengthNbBytes();
325        stream.position( start );
326    }
327
328
329    /**
330     * {@inheritDoc}
331     */
332    public void updateParent()
333    {
334        TLV parentTlv = tlv.getParent();
335
336        while ( ( parentTlv != null ) && ( parentTlv.getExpectedLength() == 0 ) )
337        {
338            parentTlv = parentTlv.getParent();
339        }
340
341        this.parentTLV = parentTlv;
342    }
343
344
345    /**
346     * {@inheritDoc}
347     */
348    public boolean isGathering()
349    {
350        return isGathering;
351    }
352
353
354    /**
355     * {@inheritDoc}
356     */
357    public void setGathering( boolean isGathering )
358    {
359        this.isGathering = isGathering;
360    }
361
362}