directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From akaras...@apache.org
Subject svn commit: rev 9318 - in incubator/directory/snickers/trunk/ber: src/java/org/apache/snickers/asn src/java/org/apache/snickers/ber src/java/org/apache/snickers/ber/util src/test src/test/org src/test/org/apache src/test/org/apache/snickers src/test/org/apache/snickers/ber xdocs
Date Tue, 09 Mar 2004 23:48:21 GMT
Author: akarasulu
Date: Tue Mar  9 15:48:20 2004
New Revision: 9318

Added:
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/..BERDecoderUtils.java
      - copied, changed from rev 7031, incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERDecoderUtils.java
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/..Primitive.java   (contents, props changed)
      - copied, changed from rev 7030, incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/Primative.java
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/..TLV.java   (contents, props changed)
      - copied, changed from rev 7030, incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/TLV.java
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERDecoder.java   (contents, props changed)
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERDecoderCallback.java   (contents, props changed)
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERDecoderCallbackAdapter.java   (contents, props changed)
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERDecoderState.java   (contents, props changed)
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERDecoderTest.java   (contents, props changed)
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERUtils.java   (contents, props changed)
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/IntStack.java   (contents, props changed)
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/Tuple.java   (contents, props changed)
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/package.html
   incubator/directory/snickers/trunk/ber/src/test/
   incubator/directory/snickers/trunk/ber/src/test/org/
   incubator/directory/snickers/trunk/ber/src/test/org/apache/
   incubator/directory/snickers/trunk/ber/src/test/org/apache/snickers/
   incubator/directory/snickers/trunk/ber/src/test/org/apache/snickers/ber/
   incubator/directory/snickers/trunk/ber/src/test/org/apache/snickers/ber/BERUtilsTest.java   (contents, props changed)
   incubator/directory/snickers/trunk/ber/src/test/org/apache/snickers/ber/IntStackTest.java   (contents, props changed)
   incubator/directory/snickers/trunk/ber/src/test/org/apache/snickers/ber/ObjectVersePrimitiveTest.java   (contents, props changed)
   incubator/directory/snickers/trunk/ber/src/test/org/apache/snickers/ber/OneByteTagTests.java   (contents, props changed)
   incubator/directory/snickers/trunk/ber/xdocs/decoder-design.xml
Removed:
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERDecoderUtils.java
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/Primative.java
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/TLV.java
Modified:
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/ASNFactory.java
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/BasicHandler.java
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/BitString.java
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/TLVHandler.java
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BerUtils.java   (contents, props changed)
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/TypeClass.java   (contents, props changed)
   incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/util/TLVParsingUtility.java
   incubator/directory/snickers/trunk/ber/xdocs/design.xml
Log:
Created what is the first try of a stateful ber decoder.  So far the decoder
really does not work yet but several aspects are ready to go.  Need to test
it over the course of the next few days.  Also moved some of Wes' classes to
the asn directory for now to avoid name conflicts - will be reincorporating
this stuff as soon as I get a chance.


Modified: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/ASNFactory.java
==============================================================================
--- incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/ASNFactory.java	(original)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/ASNFactory.java	Tue Mar  9 15:48:20 2004
@@ -49,7 +49,6 @@
 */
 package org.apache.snickers.asn;
 
-import org.apache.snickers.ber.BERDecoder;
 
 /**
  * This factory is responsible for retreiving the proper
@@ -64,7 +63,7 @@
 public class ASNFactory {
 
     /** Singleton instance of our BERDecoder */
-    private static final BERDecoder berDecoder = new BERDecoder();
+    private static final BERDecoderUtils berDecoder = new BERDecoderUtils();
     
 	/**
 	 * Basic constructor for ASNFactory 

Modified: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/BasicHandler.java
==============================================================================
--- incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/BasicHandler.java	(original)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/BasicHandler.java	Tue Mar  9 15:48:20 2004
@@ -51,7 +51,6 @@
 package org.apache.snickers.asn;
 
 import org.apache.commons.codec.DecoderException;
-import org.apache.snickers.ber.TLV;
 import org.apache.snickers.ber.TypeClass;
 
 /**

Modified: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/BitString.java
==============================================================================
--- incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/BitString.java	(original)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/BitString.java	Tue Mar  9 15:48:20 2004
@@ -48,10 +48,11 @@
 
 */
 
-package org.apache.snickers.asn;
+package org.apache.snickers.asn ;
+
+
+import java.util.BitSet ;
 
-import java.util.BitSet;
-import org.apache.commons.codec.binary.Binary;
 
 /**
  * @author Wes McKean

Modified: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/TLVHandler.java
==============================================================================
--- incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/TLVHandler.java	(original)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/asn/TLVHandler.java	Tue Mar  9 15:48:20 2004
@@ -51,7 +51,6 @@
 
 
 import org.apache.commons.codec.DecoderException;
-import org.apache.snickers.ber.TLV;
 import org.apache.snickers.ber.TypeClass;
 
 

Copied: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/..BERDecoderUtils.java (from rev 7031, incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERDecoderUtils.java)
==============================================================================
--- incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERDecoderUtils.java	(original)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/..BERDecoderUtils.java	Tue Mar  9 15:48:20 2004
@@ -1,57 +1,22 @@
 /*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.snickers.asn;
 
- ============================================================================
-                   The Apache Software License, Version 1.1
- ============================================================================
 
- Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
-
- Redistribution and use in source and binary forms, with or without modifica-
- tion, are permitted provided that the following conditions are met:
-
- 1. Redistributions of  source code must  retain the above copyright  notice,
-    this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright notice,
-    this list of conditions and the following disclaimer in the documentation
-    and/or other materials provided with the distribution.
-
- 3. The end-user documentation included with the redistribution, if any, must
-    include  the following  acknowledgment:  "This product includes  software
-    developed  by the  Apache Software Foundation  (http://www.apache.org/)."
-    Alternately, this  acknowledgment may  appear in the software itself,  if
-    and wherever such third-party acknowledgments normally appear.
-
- 4. The names "Eve Directory Server", "Apache Directory Project", "Apache Eve" 
-    and "Apache Software Foundation"  must not be used to endorse or promote
-    products derived  from this  software without  prior written
-    permission. For written permission, please contact apache@apache.org.
-
- 5. Products  derived from this software may not  be called "Apache", nor may
-    "Apache" appear  in their name,  without prior written permission  of the
-    Apache Software Foundation.
-
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
- APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
- INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
- DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
- OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
- ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
- (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- This software  consists of voluntary contributions made  by many individuals
- on  behalf of the Apache Software  Foundation. For more  information on the
- Apache Software Foundation, please see <http://www.apache.org/>.
-
-*/
-
-package org.apache.snickers.ber;
-
-import org.apache.snickers.asn.ASNDecoder;
-import org.apache.snickers.asn.BitString;
 
 /**
  * Implements the basic BER decoder used by the ASN

Copied: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/..Primitive.java (from rev 7030, incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/Primative.java)
==============================================================================
--- incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/Primative.java	(original)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/..Primitive.java	Tue Mar  9 15:48:20 2004
@@ -48,7 +48,7 @@
 
 */
 
-package org.apache.snickers.ber;
+package org.apache.snickers.asn;
 
 /**
  * Tag values for primitives

Copied: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/..TLV.java (from rev 7030, incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/TLV.java)
==============================================================================
--- incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/TLV.java	(original)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/..TLV.java	Tue Mar  9 15:48:20 2004
@@ -47,12 +47,14 @@
  Apache Software Foundation, please see <http://www.apache.org/>.
 
 */
-package org.apache.snickers.ber;
+package org.apache.snickers.asn;
 
 import java.util.ArrayList;
 import java.util.Collection;
 
 import org.apache.commons.codec.binary.Binary;
+import org.apache.snickers.ber.BERUtils;
+import org.apache.snickers.ber.TypeClass;
 
 /**
  * Basic TLV structure consisting of:
@@ -206,7 +208,7 @@
      * @return the type class
      */
     public TypeClass getTypeClass() {
-        return BerUtils.getTypeClass( tag );
+        return BERUtils.getTypeClass( tag );
     }
 
     /**
@@ -229,7 +231,7 @@
     * @return true if the value is a primative, else false.
     */
    public boolean isPrimative() {
-       return BerUtils.isPrimitive( tag );
+       return BERUtils.isPrimitive( tag );
    }
    
    /**

Added: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERDecoder.java
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERDecoder.java	Tue Mar  9 15:48:20 2004
@@ -0,0 +1,531 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.snickers.ber ;
+
+
+import java.util.Stack ;
+
+import java.nio.ByteBuffer ;
+
+import org.apache.commons.codec.binary.Binary ;
+import org.apache.commons.codec.DecoderException ;
+import org.apache.commons.codec.stateful.DecoderMonitor ;
+import org.apache.commons.codec.stateful.DecoderCallback ;
+import org.apache.commons.codec.stateful.StatefulDecoder ;
+import org.apache.commons.codec.stateful.DecoderMonitorAdapter ;
+import org.apache.commons.collections.primitives.ArrayByteList ;
+
+
+/**
+ * Low level BER encoded bytes to Tag Value Length (TLV) tuple decoder.  
+ * This decoder is a low level event based parser which operates in a fashion 
+ * similar to the way SAX works except the elements of concern are the tag, 
+ * length, and value entities.
+ * <p>
+ * Instance variables and a Stack is used to track the state of the decoder 
+ * between decode calls.  The stack maintains the nesting of TLV tuples.  Rather
+ * than creating new TLV tuple instances every time a single tuple is reused for
+ * primitive types and new tlv tuples are cloned for constructed types.  The 
+ * tuple fed to the callback must therefore be used very carefully - its values
+ * must be copied to prevent their loss when primitive TLV tuples are returned.
+ * </p>
+ * <p>
+ * Note that all tuples are not created equal.  Constructed TLVs nesting others
+ * will have null value members.  Only TLV tuples of primitive types or the 
+ * leaf TLV tuples of the TLV tuple tree will only contain non null values.  
+ * Therefore the nature of a TLV tuple should be investigated by callbacks 
+ * before attempting to interpret their values.
+ * </p> 
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class BERDecoder implements StatefulDecoder
+{
+    /** used to mark indices as undefined */ 
+    public static final int UNDEFINED = -1 ;
+    /** used to mark lengths and indices and indefinate */
+    public static final int INDEFINATE = -2 ;
+    
+    public static final BERDecoderCallback DEFAULT_CALLBACK = 
+        new BERDecoderCallbackAdapter() ;
+    public static final DecoderMonitor DEFAULT_MONITOR =
+        new DecoderMonitorAdapter() ;
+    
+    /** this decoder's callback */
+    private BERDecoderCallback cb = DEFAULT_CALLBACK ;
+    /** the monitor used by this decoder */
+    private DecoderMonitor monitor = DEFAULT_MONITOR ;
+    
+    /** the single TLV tuple used by this decoder */
+    private final Tuple tlv = new Tuple() ;
+
+    /** a byte buffer used to collect the arriving tag octets */ 
+    private final ArrayByteList tagBuffer = new ArrayByteList( 10 ) ;
+    /** a byte buffer used to collect the arriving legth octets */ 
+    private final ArrayByteList lengthBuffer = new ArrayByteList( 10 ) ;
+
+    /** stack of nested/constructed TLV tuples */
+    private final Stack tlvStack = new Stack() ;
+
+    /** the length of the length data */
+    private int lengthOfLength = 0 ;
+    
+    /** the state of this decoder */
+    private BERDecoderState state = BERDecoderState.getStartState() ;
+    
+    
+    // ------------------------------------------------------------------------
+    // StatefulDecoder Methods
+    // ------------------------------------------------------------------------
+
+    
+    /**
+     * Expects a ByteBuffer containing BER encoded data.
+     * 
+     * @see org.apache.commons.codec.stateful.StatefulDecoder#decode(
+     * java.lang.Object)
+     * @throws ClassCastException if the encoded argument is not a ByteBuffer
+     * @throws IllegalArgumentException if the buffer is null or empty
+     */
+    public void decode( Object encoded ) throws DecoderException
+    {
+        ByteBuffer buf = ( ByteBuffer ) encoded ;
+        
+        /* --------------------------------------------------------------------
+           Handle any unusual input by informing the monitor. 
+           ------------------------------------------------------------------ */
+        
+        if ( buf == null && monitor != null )
+        {
+            String msg = "ignoring null argument to decode()" ;
+            monitor.warning( this, new IllegalArgumentException( msg ) ) ;
+        }
+
+        if ( buf.remaining() > 0 && monitor != null )
+        {
+            String msg = "ignoring empty buffer" ;
+            monitor.warning( this, new IllegalArgumentException( msg ) ) ;
+        }
+        
+        /*
+         * This loop is used instead of costly recursion.  This requires each
+         * of the statewise decode methods to process bytes from the buffer.  If
+         * they can process enough to switch state they do and return 
+         * immediately.  This loop makes sure the next processing state is 
+         * handled if there is more data for that state.
+         */
+        while ( buf.hasRemaining() )
+        {    
+            switch( state.getValue() )
+            {
+                case( BERDecoderState.TAG_VAL ):
+                    decodeTag( buf ) ;
+                case( BERDecoderState.LENGTH_VAL ):
+                    decodeLength( buf ) ;
+                case( BERDecoderState.VALUE_VAL ):
+                    decodeValue( buf ) ;
+            }
+        }
+    }
+    
+
+    /* (non-Javadoc)
+     * @see org.apache.commons.codec.stateful.StatefulDecoder#setCallback(
+     * org.apache.commons.codec.stateful.DecoderCallback)
+     */
+    public void setCallback( DecoderCallback cb )
+    {
+        this.cb = ( BERDecoderCallback ) cb ;
+    }
+    
+
+    /* (non-Javadoc)
+     * @see org.apache.commons.codec.stateful.StatefulDecoder#setDecoderMonitor(
+     * org.apache.commons.codec.stateful.DecoderMonitor)
+     */
+    public void setDecoderMonitor( DecoderMonitor monitor )
+    {
+        this.monitor = monitor ;
+    }
+    
+    
+    // ------------------------------------------------------------------------
+    // State Based Decode Methods
+    // ------------------------------------------------------------------------
+    
+    
+    /**
+     * Extracts the TLV's tag portion from the buffer.
+     * 
+     * @param buf the byte byffer containing BER encoded data 
+     */
+    private void decodeTag( ByteBuffer buf ) throws DecoderException
+    {
+        for ( tlv.index = 0; buf.hasRemaining(); tlv.index++ )
+        {
+            byte octet = buf.get() ;
+            tagBuffer.add( octet ) ;
+            
+            if ( tagBuffer.size() == 1 )
+            {
+                int id = BERUtils.SHORT_TAG_MASK & octet ;
+                tlv.isPrimitive = BERUtils.isPrimitive( octet ) ; 
+                tlv.typeClass = BERUtils.getTypeClass( octet ) ;
+                
+                // continue to collect more octets if this is the long Tag form
+                if ( id == BERUtils.SHORT_TAG_MASK )
+                {
+                    continue ;
+                }
+                
+                // its the short form so we get the id, switch state & return
+                tlv.id = id ;
+                tagBuffer.clear() ;
+                state = state.getNext( tlv.isPrimitive ) ;
+                cb.tagDecoded( tlv ) ;
+                return ;
+            }
+            
+            /*
+             * From here on we're dealing with the long form of the tag.  The
+             * terminating octet for the long form uses a raised most 
+             * significant bit to flag the end of the train of octets for the 
+             * tag id.
+             */ 
+            if ( ( octet & Binary.BIT_7 ) == Binary.BIT_7 )
+            {
+                tlv.id = BERUtils.getTagId( tagBuffer ) ;
+                tagBuffer.clear() ;
+                state = state.getNext( tlv.isPrimitive ) ;
+                cb.tagDecoded( tlv ) ;
+                return ;
+            }
+        }
+    }
+    
+    
+    /**
+     * Extracts the length portion from the buffer.
+     * 
+     * @param buf the byte byffer containing BER encoded data 
+     */
+    private void decodeLength( ByteBuffer buf ) throws DecoderException
+    {
+        for ( ; buf.hasRemaining(); tlv.index++ )
+        {
+            byte octet = buf.get() ;
+            lengthBuffer.add( octet ) ;
+            
+            if ( lengthBuffer.size() == 1 )
+            {
+                lengthOfLength = octet & BERUtils.LONG_TAG_MASK ;
+                
+                // handle the short form of the length here
+                if ( ( octet & Binary.BIT_7 ) == 0 ) 
+                {
+                    lengthOfLength = 0 ;
+                    tlv.length = octet ;
+                    tlv.valueIndex = UNDEFINED ;
+
+                    if ( tlv.isPrimitive )
+                    {
+                        state = BERDecoderState.VALUE ;
+                        tlv.value = new byte[tlv.length] ;
+                    }
+                    else 
+                    {
+                        tlvStack.push( tlv.clone() ) ;
+                        tlv.clear() ;
+                        state = BERDecoderState.TAG ;
+                    }
+                    
+                    return ;
+                }
+                // the indefinate form of the length
+                else if ( lengthOfLength == 0 )
+                {
+                    lengthOfLength = INDEFINATE ;
+                    tlv.index = INDEFINATE ;
+                    tlv.valueIndex = UNDEFINED ;
+                    tlvStack.push( tlv.clone() ) ;
+                    tlv.clear() ;
+                    state = BERDecoderState.TAG ;
+                    return ;
+                }
+            }
+
+            /*
+             * if we have collected all the octets needed for computing the long
+             * form length so we need to calculate the length push it and return
+             */
+            if ( lengthBuffer.size() == lengthOfLength + 1 )
+            {
+                lengthOfLength = 0 ;
+                tlv.length = BERUtils.getLength( lengthBuffer ) ;
+                tlv.valueIndex = UNDEFINED ;
+                
+                if ( tlv.isPrimitive )
+                {
+                    state = BERDecoderState.VALUE ;
+                    tlv.value = new byte[tlv.length] ;
+                }
+                else
+                {
+                    tlvStack.push( tlv.clone() ) ;
+                    tlv.clear() ;
+                    state = BERDecoderState.TAG ;
+                }
+            }
+        }
+    }
+    
+    
+    /**
+     * Extracts the value portion from the buffer for a primitive type.
+     * 
+     * @param buf the byte byffer containing BER encoded data 
+     */
+    private void decodeValue( ByteBuffer buf ) throws DecoderException
+    {
+        byte[] value = ( byte [] ) tlv.value ;
+        int offset = UNDEFINED ;
+        int needToRead = UNDEFINED ;
+
+        if ( ! tlv.isPrimitive )
+        {
+            IllegalStateException e = new IllegalStateException( 
+                    "should only be working with primitive tlv" ) ;
+            
+            if ( monitor == null )
+            {    
+                throw e ;
+            }
+            else
+            {
+                monitor.fatalError( this, e ) ;
+            }
+            
+            return ;
+        }
+        
+        if ( buf == null )
+        {
+            IllegalArgumentException e = new IllegalArgumentException(
+                    "got null buffer" ) ;
+            
+            if ( monitor == null )
+            {    
+                throw e ;
+            }
+            else
+            {
+                monitor.warning( this, e ) ;
+            }
+            
+            return ;
+        }
+        
+        if ( ! buf.hasRemaining() )
+        {
+            IllegalArgumentException e = new IllegalArgumentException(
+                    "got an empty buffer" ) ;
+            
+            if ( monitor == null )
+            {    
+                throw e ;
+            }
+            else
+            {
+                monitor.warning( this, e ) ;
+            }
+            
+            return ;
+        }
+        
+        /*
+         * Start decoding the value now:
+         */
+        
+        if ( tlv.valueIndex == UNDEFINED )
+        {
+            needToRead = tlv.length ;
+            offset = 0 ;
+        }
+        else
+        {
+            needToRead = tlv.length - tlv.valueIndex - 1 ;
+            offset = tlv.valueIndex ;
+        }
+        
+        if ( buf.remaining() >= needToRead )
+        {
+            buf.get( value, offset, needToRead ) ;
+            tlv.valueIndex = tlv.length ;
+            
+            /*
+             * Check for a INDEFINATE length TLV when tlv is primitive with 
+             * zero length and a type class of UNIVERSAL which is reserved
+             * for use by encoding rules.
+             */
+            if ( tlv.typeClass == TypeClass.UNIVERSAL &&
+                 tlv.length == 0 )
+            {
+                String msg = "expected indefinate length TLV on the stack" ;
+
+                if ( tlvStack.isEmpty() )
+                {
+                    IllegalStateException e = new IllegalStateException(
+                             msg + " but the stack is empty" ) ;
+                    
+                    if ( monitor == null )
+                    {
+                        throw e ;
+                    }
+                    else
+                    {
+                        monitor.fatalError( this, e ) ;
+                    }
+                    
+                    return ;
+                }
+
+                Tuple top = ( Tuple ) tlvStack.peek() ;
+                if ( top.length != INDEFINATE )
+                {
+                    IllegalStateException e = new IllegalStateException(
+                             msg + " but TLV on top has a definate length" ) ;
+                    
+                    if ( monitor == null )
+                    {
+                        throw e ;
+                    }
+                    else
+                    {
+                        monitor.fatalError( this, e ) ;
+                    }
+                    
+                    return ;
+                }
+                
+                tlvStack.pop() ;
+                cb.decodeOccurred( this, top ) ;
+            }
+            else
+            {
+                cb.decodeOccurred( this, tlv ) ;
+            }
+            
+            tlv.clear() ;
+
+            if ( tlvStack.isEmpty() )
+            {
+                state = BERDecoderState.TAG ;
+                return ;
+            }
+
+            /*
+             * This is where we update all nested tlv indices and their 
+             * valueIndices.  Also we pop the stack and fire and event if we 
+             * have completed the value of a nested tlv.
+             */
+            for ( int ii = 0; ii < tlvStack.size(); ii++ )
+            {
+                Tuple t = ( Tuple ) tlvStack.get( ii ) ;
+                
+                if ( t.length != INDEFINATE )
+                {    
+                    t.index += tlv.length ;
+                    t.valueIndex += tlv.length ;
+                }
+            }
+            
+            do
+            {
+                Tuple top = ( Tuple ) tlvStack.peek() ;
+                
+                if ( top.valueIndex >= top.length )
+                {
+                    tlvStack.pop() ;
+                    cb.decodeOccurred( this, top ) ;
+                }
+                else
+                {
+                    break ;
+                }
+            } while( tlvStack.size() > 0 ) ;
+
+            state = BERDecoderState.TAG ;
+        }
+        else
+        {
+            int remaining = buf.remaining() ;
+            buf.get( value, offset, remaining ) ;
+            tlv.valueIndex += remaining ;
+        }
+    }
+    
+    
+    // ------------------------------------------------------------------------
+    // Methods used for testing
+    // ------------------------------------------------------------------------
+    
+    
+    /**
+     * Gets the current state of this BERDecoder.  Used only for debugging and 
+     * testing.
+     * 
+     * @return the state enum
+     */
+    BERDecoderState getState()
+    {
+        return state ;
+    }
+    
+    
+    /**
+     * Gets a cloned copy of the current tuple.  Used only for debugging and 
+     * testing.
+     * 
+     * @return a clone of the current tlv 
+     */
+    Tuple getCurrentTuple()
+    {
+        return ( Tuple ) tlv.clone() ;
+    }
+    
+    
+    /**
+     * Gets a deep copy of the constructed tuple stack.  Used only for debugging
+     * and testing.
+     * 
+     * @return a deep copy of the tuple stack
+     */
+    Stack getTupleStack()
+    {
+        Stack stack = new Stack() ;
+        
+        for ( int ii = 0; ii < tlvStack.size(); ii++ )
+        {
+            Tuple t = ( Tuple ) tlvStack.get( ii ) ;
+            stack.add( t.clone() ) ;
+        }
+        
+        return stack ;
+    }
+}

Added: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERDecoderCallback.java
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERDecoderCallback.java	Tue Mar  9 15:48:20 2004
@@ -0,0 +1,58 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.snickers.ber ;
+
+
+import org.apache.commons.codec.stateful.DecoderCallback ;
+
+
+/**
+ * A specialized decoder callback that handles specific BER events.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev$
+ */
+public interface BERDecoderCallback extends DecoderCallback
+{
+    /**
+     * A tag was decoded.  The following tag properties of the TLV tuple are 
+     * valid at this point:
+     * <ul>
+     * <li>id</li>
+     * <li>isPrimitive</li>
+     * <li>typeClass</li>
+     * </ul>
+     * 
+     * @param tlv the TLV tuple
+     */
+    void tagDecoded( Tuple tlv ) ;
+    
+    /**
+     * A tag was decoded.  The following tag properties of the TLV tuple are 
+     * valid at this point:
+     * <ul>
+     * <li>id</li>
+     * <li>isPrimitive</li>
+     * <li>typeClass</li>
+     * <li>length</li>
+     * </ul>
+     * 
+     * @param tlv the TLV tuple
+     */
+    void lengthDecoded( Tuple tlv ) ;
+}

Added: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERDecoderCallbackAdapter.java
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERDecoderCallbackAdapter.java	Tue Mar  9 15:48:20 2004
@@ -0,0 +1,57 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.snickers.ber ;
+
+
+import org.apache.commons.codec.stateful.StatefulDecoder ;
+
+
+/**
+ * A do nothing callback adapter.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class BERDecoderCallbackAdapter implements BERDecoderCallback
+{
+    /* (non-Javadoc)
+     * @see org.apache.snickers.ber.BERDecoderCallback#tagDecoded(
+     * org.apache.snickers.ber.Tuple)
+     */
+    public void tagDecoded( Tuple tlv )
+    {
+    }
+
+    
+    /* (non-Javadoc)
+     * @see org.apache.snickers.ber.BERDecoderCallback#lengthDecoded(
+     * org.apache.snickers.ber.Tuple)
+     */
+    public void lengthDecoded( Tuple tlv )
+    {
+    }
+
+    
+    /* (non-Javadoc)
+     * @see org.apache.commons.codec.stateful.DecoderCallback#decodeOccurred(
+     * org.apache.commons.codec.stateful.StatefulDecoder, java.lang.Object)
+     */
+    public void decodeOccurred( StatefulDecoder decoder, Object decoded )
+    {
+    }
+}

Added: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERDecoderState.java
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERDecoderState.java	Tue Mar  9 15:48:20 2004
@@ -0,0 +1,255 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.snickers.ber ;
+
+
+import java.util.Map ;
+import java.util.List ;
+
+import org.apache.commons.lang.enum.EnumUtils ;
+import org.apache.commons.lang.enum.ValuedEnum ;
+
+
+/**
+ * A type safe enumeration representing the state of a BERDecoder.  This can 
+ * take one of the following three values: 
+ * 
+ * <ul>
+ *   <li>
+ *      TAG - state where the decoder is reading and composing the tag
+ *   </li>
+ *   <li>
+ *      LENGTH - state where the decoder is reading and composing the length
+ *   </li>
+ *   <li>
+ *      VALUE - state where the decoder is reading and composing the value
+ *   </li>
+ * </ul>
+ * 
+ * @author <a href="mailto:directory-dev@incubator.apache.org">
+ *      Apache Directory Project</a>
+ * @version $Rev$
+ */
+public final class BERDecoderState extends ValuedEnum
+{
+    /** value for the TAG state */
+    public static final int TAG_VAL = 0 ;
+    /** value for the LENGTH state */
+    public static final int LENGTH_VAL = 1 ;
+    /** value for the VALUE state */
+    public static final int VALUE_VAL = 2 ;
+
+    /** enum for the TAG state */
+    public static final BERDecoderState TAG = 
+        new BERDecoderState( "TAG", TAG_VAL ) ;
+    /** enum for the LENGTH state */
+    public static final BERDecoderState LENGTH = 
+        new BERDecoderState( "LEGTH", LENGTH_VAL ) ;
+    /** enum for the VALUE state */
+    public static final BERDecoderState VALUE = 
+        new BERDecoderState( "VALUE", VALUE_VAL ) ;
+
+    
+    /**
+     * Private constructor so no other instances can be created other than the
+     * public static constants in this class.
+     *
+     * @param name a string name for the enumeration value.
+     * @param value the integer value of the enumeration.
+     */
+    private BERDecoderState( final String name, final int value )
+    {
+        super( name, value ) ;
+    }
+    
+    
+    /**
+     * Gets the next state after this BERDecoderState based on the nature of the
+     * present TLV being processed.
+     * 
+     * @param isPrimitive true if the current TLV is primitive,  false if it is
+     *      constructed
+     * @return the type safe enum for the next state to transit to
+     */
+    public final BERDecoderState getNext( boolean isPrimitive )
+    {
+        switch( getValue() )
+        {
+            case( VALUE_VAL ):
+                return TAG ;
+            case( TAG_VAL ):
+                return LENGTH ;
+            case( LENGTH_VAL ):
+                if ( isPrimitive )
+                {
+                    return VALUE ;
+                }
+                else
+                {    
+                    return TAG ;
+                }
+            default:
+                throw new IllegalStateException() ;
+        }
+    }
+    
+
+    /**
+     * Determines if this present state is the processing end state for a TLV 
+     * based on the nature of the current TLV tuple as either a primitive TLV 
+     * or a constructed one.  The VALUE state is considered a terminal 
+     * processing state for all TLV tuples.  The LENGTH state is considered a 
+     * terminal processing state for constructed TLV tuples.
+     * 
+     * @param isPrimitive true if the current TLV is primitive,  false if it is
+     *      constructed
+     * @return true if the next state is the last processing state
+     */
+    public final boolean isEndState( boolean isPrimitive )
+    {
+        switch( getValue() )
+        {
+            case( VALUE_VAL ):
+                return true ;
+            case( TAG_VAL ):
+                return false ;
+            case( LENGTH_VAL ):
+                if ( isPrimitive )
+                {
+                    return false ;
+                }
+                else
+                {    
+                    return true ;
+                }
+            default:
+                throw new IllegalStateException() ;
+        }
+    }
+    
+    
+    /**
+     * Gets the start state.
+     * 
+     * @return the start state 
+     */
+    public final static BERDecoderState getStartState()
+    {
+        return TAG ;
+    }
+    
+    
+    /**
+     * Gets the enum type for the state regardless of case.
+     * 
+     * @param stateName the name of the state
+     * @return the BERDecoderState enum for the state name 
+     */
+    public final static BERDecoderState getTypeClass( String stateName )
+    {
+        /*
+         * First try and see if a quick reference lookup will resolve the
+         * name since this is the fastest way to test.  Most of the time when
+         * class names are used they are references to the actual string of 
+         * the state object anyway. 
+         */
+        
+        if ( stateName == TAG.getName() )
+        {
+            return TAG ;
+        }
+        
+        if ( stateName == LENGTH.getName() )
+        {
+            return LENGTH ;
+        }
+        
+        if ( stateName == VALUE.getName() )
+        {
+            return VALUE ;
+        }
+        
+        /*
+         * As a last resort see if we can match the string to an existing
+         * state.  We really should not have to resort to this but its there
+         * anyway. 
+         */
+        
+        if ( stateName.equalsIgnoreCase( BERDecoderState.TAG.getName() ) )
+        {
+            return BERDecoderState.TAG ;
+        }
+        
+        if ( stateName.equalsIgnoreCase( BERDecoderState.LENGTH.getName() ) )
+        {
+            return BERDecoderState.LENGTH ;
+        }
+        
+        if ( stateName.equalsIgnoreCase( BERDecoderState.VALUE.getName() ) )
+        {
+            return BERDecoderState.VALUE ;
+        }
+        
+        throw new IllegalArgumentException( "Unknown decoder state"
+            + stateName ) ;
+    }
+    
+    
+    /**
+     * Gets a List of the enumerations for the decoder states.
+     * 
+     * @return the List of enumerations possible for decoder states
+     */
+    public final static List list()
+    {
+        return EnumUtils.getEnumList( BERDecoderState.class ) ;
+    }
+    
+    
+    /**
+     * Gets the Map of decoder state objects by name using the BERDecoderState 
+     * class.
+     * 
+     * @return the Map by name of the BERDecoderState
+     */
+    public final static Map map()
+    {
+        return EnumUtils.getEnumMap( BERDecoderState.class ) ;
+    }
+
+
+    /**
+     * Gets the state of the decoder using a state value.
+     * 
+     * @param value the value of the state
+     * @return the BERDecoderState for the decoder state value
+     */
+    public final static BERDecoderState getTypeClass( int value )
+    {
+        switch ( value )
+        {
+            case( TAG_VAL ):
+                return TAG ;
+            case( LENGTH_VAL ):
+                return LENGTH ;
+            case( VALUE_VAL ):
+                return VALUE ;
+            default:
+                throw new IllegalStateException( "Should not be here!" ) ;
+        }
+    }
+}

Added: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERDecoderTest.java
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERDecoderTest.java	Tue Mar  9 15:48:20 2004
@@ -0,0 +1,224 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.snickers.ber ;
+
+
+import java.nio.ByteBuffer ;
+import java.util.ArrayList ;
+
+import org.apache.commons.codec.binary.Binary ;
+import org.apache.commons.codec.DecoderException ;
+import org.apache.commons.codec.stateful.DecoderMonitor ;
+import org.apache.commons.codec.stateful.DecoderCallback ;
+import org.apache.commons.codec.stateful.StatefulDecoder ;
+
+import org.apache.commons.lang.exception.ExceptionUtils ;
+
+import junit.framework.TestCase ;
+
+
+/**
+ * Tests the BER decoder.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev$
+ */
+public abstract class BERDecoderTest extends TestCase 
+    implements BERDecoderCallback, DecoderMonitor
+{
+    protected ArrayList tlvList = new ArrayList() ;
+    protected BERDecoder decoder = null ;
+    
+
+    /**
+     * Arguments should be concrete junit testcase classes.
+     * 
+     * @param args concrete junit testcase classes.
+     */
+    public static void main( String[] args )
+    {
+        try 
+        {
+            for ( int ii = 0; ii < args.length; ii++ )
+            {    
+                junit.textui.TestRunner.run( Class.forName( args[ii] ) ) ;
+            }
+        }
+        catch ( ClassNotFoundException e )
+        {
+            e.printStackTrace() ;
+        }
+    }
+
+    
+    /*
+     * @see TestCase#setUp()
+     */
+    protected void setUp() throws Exception
+    {
+        super.setUp() ;
+        decoder = new BERDecoder() ;
+        decoder.setCallback( this ) ;
+    }
+
+    
+    /*
+     * @see TestCase#tearDown()
+     */
+    protected void tearDown() throws Exception
+    {
+        super.tearDown() ;
+        tlvList.clear() ;
+        decoder = null ;
+    }
+
+    
+    /**
+     * Constructor for BERDecoderTest.
+     * @param arg0
+     */
+    public BERDecoderTest( String arg0 )
+    {
+        super( arg0 ) ;
+    }
+    
+    
+    /**
+     * BER decodes a string of 0's and 1's.
+     * 
+     * @param bitString a string of ascii 0's and 1's
+     * @return a copy of the decoded tuple or the partially decoded current tlv
+     * @throws DecoderException if there are errors while decoding.
+     */
+    public Tuple decode( String bitString ) throws DecoderException
+    {
+        byte [] bites = Binary.fromAscii( bitString.getBytes() ) ;
+        ByteBuffer buf = ByteBuffer.wrap( bites ) ;
+        int lastSize = tlvList.size() ;
+        decoder.decode( buf.flip() ) ;
+        
+        if ( tlvList.isEmpty() || tlvList.size() == lastSize )
+        {
+            return decoder.getCurrentTuple() ;
+        }
+        
+        return ( Tuple ) tlvList.get( tlvList.size() - 1 ) ;
+    }
+
+    
+    /* (non-Javadoc)
+     * @see org.apache.snickers.ber.BERDecoderCallback#tagDecoded(
+     * org.apache.snickers.ber.Tuple)
+     */
+    public void tagDecoded( Tuple tlv )
+    {
+        assertEquals( decoder.getCurrentTuple(), tlv ) ;
+        assertEquals( BERDecoderState.TAG, decoder.getState() ) ;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.snickers.ber.BERDecoderCallback#lengthDecoded(
+     * org.apache.snickers.ber.Tuple)
+     */
+    public void lengthDecoded( Tuple tlv )
+    {
+        assertEquals( decoder.getCurrentTuple(), tlv ) ;
+        assertEquals( BERDecoderState.LENGTH, decoder.getState() ) ;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.commons.codec.stateful.DecoderCallback#decodeOccurred(
+     * org.apache.commons.codec.stateful.StatefulDecoder, java.lang.Object)
+     */
+    public void decodeOccurred( StatefulDecoder decoder, Object decoded )
+    {
+        Tuple t = ( Tuple ) decoded ;
+        tlvList.add( t.clone() ) ;
+        assertEquals( BERDecoderState.VALUE, this.decoder.getState() ) ;
+    }
+    
+    
+    /* (non-Javadoc)
+     * @see org.apache.commons.codec.stateful.DecoderMonitor#callbackOccured(
+     * org.apache.commons.codec.stateful.StatefulDecoder, 
+     * org.apache.commons.codec.stateful.DecoderCallback, java.lang.Object)
+     */
+    public void callbackOccured( StatefulDecoder decoder, DecoderCallback cb,
+								 Object decoded )
+    {
+        assertEquals( this, cb ) ;
+        assertEquals( this.decoder, decoder ) ;
+        assertEquals( this.decoder.getCurrentTuple(), decoded ) ;
+    }
+
+    
+    /* (non-Javadoc)
+     * @see org.apache.commons.codec.stateful.DecoderMonitor#callbackSet(
+     * org.apache.commons.codec.stateful.StatefulDecoder, 
+     * org.apache.commons.codec.stateful.DecoderCallback, 
+     * org.apache.commons.codec.stateful.DecoderCallback)
+     */
+    public void callbackSet( StatefulDecoder decoder, DecoderCallback oldcb,
+							 DecoderCallback newcb )
+    {
+        assertEquals( this, newcb ) ;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.commons.codec.stateful.DecoderMonitor#error(
+     * org.apache.commons.codec.stateful.StatefulDecoder, java.lang.Exception)
+     */
+    public void error( StatefulDecoder decoder, Exception exception )
+    {
+        fail( ExceptionUtils.getFullStackTrace( exception ) ) ;
+    }
+
+    
+    /* (non-Javadoc)
+     * @see org.apache.commons.codec.stateful.DecoderMonitor#fatalError(
+     * org.apache.commons.codec.stateful.StatefulDecoder, java.lang.Exception)
+     */
+    public void fatalError( StatefulDecoder decoder, Exception exception )
+    {
+        fail( ExceptionUtils.getFullStackTrace( exception ) ) ;
+    }
+
+    
+    /* (non-Javadoc)
+     * @see org.apache.commons.codec.stateful.DecoderMonitor#monitorSet(
+     * org.apache.commons.codec.stateful.StatefulDecoder, 
+     * org.apache.commons.codec.stateful.DecoderMonitor)
+     */
+    public void monitorSet( StatefulDecoder decoder, DecoderMonitor oldmon )
+    {
+        assertEquals( this, oldmon ) ;
+    }
+
+    
+    /* (non-Javadoc)
+     * @see org.apache.commons.codec.stateful.DecoderMonitor#warning(
+     * org.apache.commons.codec.stateful.StatefulDecoder, java.lang.Exception)
+     */
+    public void warning( StatefulDecoder decoder, Exception exception )
+    {
+        fail( ExceptionUtils.getFullStackTrace( exception ) ) ;
+    }
+}

Added: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERUtils.java
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BERUtils.java	Tue Mar  9 15:48:20 2004
@@ -0,0 +1,223 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.snickers.ber ;
+
+
+import org.apache.commons.codec.binary.Binary ;
+import org.apache.commons.codec.DecoderException ;
+import org.apache.commons.collections.primitives.ArrayByteList ;
+
+import org.apache.commons.lang.NotImplementedException ;
+
+
+/**
+ * Basic Encoding Rule (BER) utility functions.
+ *
+ * @author <a href="mailto:akarasulu@apache.org">Alex Karasulu</a>
+ * @author $Author: akarasulu $
+ * @version $Rev$
+ */
+public final class BERUtils
+{
+    /** mask for the tag value of a short tag value format in a single octet */
+    public static final int SHORT_TAG_MASK = Binary.BIT_0 | Binary.BIT_1 | 
+        Binary.BIT_2 | Binary.BIT_3 | Binary.BIT_4 ;
+    /** mask for the tag value of long tag value format in more than 1 octet */
+    public static final int LONG_TAG_MASK = Binary.BIT_0 | Binary.BIT_1 |
+        Binary.BIT_2 | Binary.BIT_3 | Binary.BIT_4 | Binary.BIT_5 | 
+        Binary.BIT_6 ;
+    
+    
+    /**
+     * Gets the ASN.1 type's class using a TLV tag.
+     * 
+     * @param octet the first octet of the TLV
+     * @return the TypeClass enumeration for the ASN.1 type's class
+     */
+    public final static TypeClass getTypeClass( byte octet )
+    {
+        return TypeClass.getTypeClass( octet ) ;
+    }
+
+
+    /**
+     * Gets the ASN.1 type's class using a TLV tag.
+     * 
+     * @param octet the first octet of the TLV
+     * @return the TypeClass enumeration for the ASN.1 type's class
+     */
+    public final static TypeClass getTypeClass( int octet )
+    {
+        return TypeClass.getTypeClass( ( byte ) octet ) ;
+    }
+    
+
+    /**
+     * Checks to see if the TLV is constructed.
+     * 
+     * @param octet the first octet of the TLV
+     * @return true if this TLV contains more TLVs, false if it's a simple type
+     */
+    public final static boolean isConstructed( byte octet )
+    {
+        return ( octet & Binary.BIT_5 ) == Binary.BIT_5 ;
+    }
+    
+    
+    /**
+     * Checks to see if the TLV is constructed.
+     * 
+     * @param octet the first octet of the TLV
+     * @return true if this TLV contains more TLVs, false if it's a simple type
+     */
+    public final static boolean isConstructed( int octet )
+    {
+        return ( octet & Binary.BIT_5 ) == Binary.BIT_5 ;
+    }
+
+
+    /**
+     * Checks to see if the TLV is a primitive.
+     * 
+     * @param octet the first octet of the TLV
+     * @return true if this TLV is a simple type, false if it contains TLVs
+     */
+    public final static boolean isPrimitive( byte octet )
+    {
+        return ( octet & Binary.BIT_5 ) == 0 ;
+    }
+    
+    
+    /**
+     * Checks to see if the TLV is a primitive.
+     * 
+     * @param octet the first octet of the TLV
+     * @return true if this TLV is a simple type, false if it contains TLVs
+     */
+    public final static boolean isPrimitive( int octet )
+    {
+        return ( octet & Binary.BIT_5 ) == 0 ;
+    }
+
+    
+    /**
+     * Gets the tag id of a TLV from the tag octets.
+     * 
+     * @param octets the set of octets needed to determine the tag value 
+     *      (a.k.a identifier octets)
+     * @return the tag id
+     * @throws DecoderException if the id cannot be determined due to
+     *      type limitations of this method's return type. 
+     */
+    public final static int getTagId( byte[] octets )
+        throws DecoderException
+    {
+        if ( octets.length > 6 )
+        {
+            /*
+             * If this exception is ever thrown which is highly unlikely, then
+             * we need to switch to another data type to return because after
+             * 5 bytes the int can no longer hold the number.
+             */
+            throw new DecoderException( "Tag number is too large." ) ;
+        }
+        
+        int id = octets[0] & SHORT_TAG_MASK ;
+        
+        // if bits are not all 1's then return the value which is less than 31
+        if ( id != SHORT_TAG_MASK && octets.length == 1 )
+        {
+            return id ;
+        }
+        
+        // clear the id now
+        id = 0 ;
+
+        // calculate tag value w/ long tag format
+        for( int ii = 1 ; ii < octets.length; ii++ )
+        {    
+            int shift = ( ii - 1 ) * 7 ;
+            if ( shift > 0 )
+            {    
+                id |= ( octets[ii] & LONG_TAG_MASK ) << shift ;
+            }
+            else
+            {
+                id |= ( octets[ii] & LONG_TAG_MASK ) ;
+            }
+        }
+        
+        return id ;
+    }
+
+
+    /**
+     * Gets the tag id of a TLV from the tag octets.
+     * 
+     * @param octets the set of octets needed to determine the tag value 
+     *      (a.k.a identifier octets)
+     * @return the tag id
+     * @throws DecoderException if the id cannot be determined due to
+     *      type limitations of this method's return type. 
+     */
+    public final static int getTagId( ArrayByteList octets )
+        throws DecoderException
+    {
+        if ( octets.size() > 6 )
+        {
+            /*
+             * If this exception is ever thrown which is highly unlikely, then
+             * we need to switch to another data type to return because after
+             * 5 bytes the int can no longer hold the number.
+             */
+            throw new DecoderException( "Tag number is too large." ) ;
+        }
+        
+        int id = octets.get( 0 ) & SHORT_TAG_MASK ;
+        
+        // if bits are not all 1's then return the value which is less than 31
+        if ( id != SHORT_TAG_MASK && octets.size() == 1 )
+        {
+            return id ;
+        }
+        
+        // clear the id now
+        id = 0 ;
+
+        // calculate tag value w/ long tag format
+        for( int ii = 1 ; ii < octets.size(); ii++ )
+        {    
+            int shift = ( ii - 1 ) * 7 ;
+            if ( shift > 0 )
+            {    
+                id |= ( octets.get( ii ) & LONG_TAG_MASK ) << shift ;
+            }
+            else
+            {
+                id |= ( octets.get( ii ) & LONG_TAG_MASK ) ;
+            }
+        }
+        
+        return id ;
+    }
+
+    
+    public static int getLength( ArrayByteList octets )
+    {
+        throw new NotImplementedException( "STUB" ) ;
+    }
+}

Modified: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BerUtils.java
==============================================================================
--- incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BerUtils.java	(original)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/BerUtils.java	Tue Mar  9 15:48:20 2004
@@ -1,344 +1,223 @@
 /*
-
- ============================================================================
-                   The Apache Software License, Version 1.1
- ============================================================================
-
- Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
-
- Redistribution and use in source and binary forms, with or without modifica-
- tion, are permitted provided that the following conditions are met:
-
- 1. Redistributions of  source code must  retain the above copyright  notice,
-    this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright notice,
-    this list of conditions and the following disclaimer in the documentation
-    and/or other materials provided with the distribution.
-
- 3. The end-user documentation included with the redistribution, if any, must
-    include  the following  acknowledgment:  "This product includes  software
-    developed  by the  Apache Software Foundation  (http://www.apache.org/)."
-    Alternately, this  acknowledgment may  appear in the software itself,  if
-    and wherever such third-party acknowledgments normally appear.
-
- 4. The names "Eve Directory Server", "Apache Directory Project", "Apache Eve" 
-    and "Apache Software Foundation"  must not be used to endorse or promote
-    products derived  from this  software without  prior written
-    permission. For written permission, please contact apache@apache.org.
-
- 5. Products  derived from this software may not  be called "Apache", nor may
-    "Apache" appear  in their name,  without prior written permission  of the
-    Apache Software Foundation.
-
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
- APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
- INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
- DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
- OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
- ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
- (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- This software  consists of voluntary contributions made  by many individuals
- on  behalf of the Apache Software  Foundation. For more  information on the
- Apache Software Foundation, please see <http://www.apache.org/>.
-
-*/
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
 package org.apache.snickers.ber ;
 
 
-import java.nio.ByteBuffer;
-
-import org.apache.commons.codec.binary.*;
+import org.apache.commons.codec.binary.Binary ;
 import org.apache.commons.codec.DecoderException ;
+import org.apache.commons.collections.primitives.ArrayByteList ;
+
+import org.apache.commons.lang.NotImplementedException ;
 
 
 /**
  * Basic Encoding Rule (BER) utility functions.
  *
  * @author <a href="mailto:akarasulu@apache.org">Alex Karasulu</a>
- * @author $Author$
+ * @author $Author: akarasulu $
  * @version $Rev$
  */
-public final class BerUtils
+public final class BERUtils
 {
-    /** mask for the tag value of short tag value format in a single octet */
-    public static final int SHORT_TAG_MASK = 31 ;
+    /** mask for the tag value of a short tag value format in a single octet */
+    public static final int SHORT_TAG_MASK = Binary.BIT_0 | Binary.BIT_1 | 
+        Binary.BIT_2 | Binary.BIT_3 | Binary.BIT_4 ;
     /** mask for the tag value of long tag value format in more than 1 octet */
-    public static final int LONG_TAG_MASK = 127 ;
+    public static final int LONG_TAG_MASK = Binary.BIT_0 | Binary.BIT_1 |
+        Binary.BIT_2 | Binary.BIT_3 | Binary.BIT_4 | Binary.BIT_5 | 
+        Binary.BIT_6 ;
     
     
     /**
      * Gets the ASN.1 type's class using a TLV tag.
      * 
-     * @param a_octet the first octet of the TLV
+     * @param octet the first octet of the TLV
      * @return the TypeClass enumeration for the ASN.1 type's class
      */
-    public final static TypeClass getTypeClass( byte a_octet )
+    public final static TypeClass getTypeClass( byte octet )
     {
-        return TypeClass.getTypeClass( a_octet ) ;
+        return TypeClass.getTypeClass( octet ) ;
     }
 
 
     /**
      * Gets the ASN.1 type's class using a TLV tag.
      * 
-     * @param a_octet the first octet of the TLV
+     * @param octet the first octet of the TLV
      * @return the TypeClass enumeration for the ASN.1 type's class
      */
-    public final static TypeClass getTypeClass( int a_octet )
+    public final static TypeClass getTypeClass( int octet )
     {
-        return TypeClass.getTypeClass( ( byte ) a_octet ) ;
+        return TypeClass.getTypeClass( ( byte ) octet ) ;
     }
     
 
     /**
      * Checks to see if the TLV is constructed.
      * 
-     * @param a_octet the first octet of the TLV
+     * @param octet the first octet of the TLV
      * @return true if this TLV contains more TLVs, false if it's a simple type
      */
-    public final static boolean isConstructed( byte a_octet )
+    public final static boolean isConstructed( byte octet )
     {
-        return ( a_octet & Binary.BIT_5 ) == Binary.BIT_5 ;
+        return ( octet & Binary.BIT_5 ) == Binary.BIT_5 ;
     }
     
     
     /**
      * Checks to see if the TLV is constructed.
      * 
-     * @param a_octet the first octet of the TLV
+     * @param octet the first octet of the TLV
      * @return true if this TLV contains more TLVs, false if it's a simple type
      */
-    public final static boolean isConstructed( int a_octet )
+    public final static boolean isConstructed( int octet )
     {
-        return ( a_octet & Binary.BIT_5 ) == Binary.BIT_5 ;
+        return ( octet & Binary.BIT_5 ) == Binary.BIT_5 ;
     }
 
 
     /**
      * Checks to see if the TLV is a primitive.
      * 
-     * @param a_octet the first octet of the TLV
+     * @param octet the first octet of the TLV
      * @return true if this TLV is a simple type, false if it contains TLVs
      */
-    public final static boolean isPrimitive( byte a_octet )
+    public final static boolean isPrimitive( byte octet )
     {
-        return ( a_octet & Binary.BIT_5 ) == 0 ;
+        return ( octet & Binary.BIT_5 ) == 0 ;
     }
     
     
     /**
      * Checks to see if the TLV is a primitive.
      * 
-     * @param a_octet the first octet of the TLV
+     * @param octet the first octet of the TLV
      * @return true if this TLV is a simple type, false if it contains TLVs
      */
-    public final static boolean isPrimitive( int a_octet )
+    public final static boolean isPrimitive( int octet )
     {
-        return ( a_octet & Binary.BIT_5 ) == 0 ;
+        return ( octet & Binary.BIT_5 ) == 0 ;
     }
 
     
     /**
-     * Given a buffer this method returns the index of the last identifier 
-     * octet (tag part of TLV).  If the short format is used then the returned 
-     * index is the given index parameter.  If the long format is used, the 
-     * returned index will be offset by one or more.  The returned index is 
-     * an octet of the identifier.
+     * Gets the tag id of a TLV from the tag octets.
      * 
-     * @param a_buf a buffer of TLVs
-     * @return the index containing the last octet of the TLV's Tag/Identifier
-     */
-    public final static int getIdentifierEndIndex( byte[] a_buf )
-    {
-        return getIdentifierEndIndex( a_buf, 0 ) ;
-    }
-    
-
-    /**
-     * Given a buffer and some TLV start index in it, this method returns the
-     * index of the last identifier octet (tag part of TLV).  If the short 
-     * format is used then the returned index is the given index parameter.
-     * If the long format is used, the returned index will be offset by one 
-     * or more.  The returned index is an octet of the identifier.
-     * 
-     * @param a_buf a buffer of TLVs
-     * @param a_idx the start position of a TLV
-     * @return the index containing the last octet of the TLV's Tag/Identifier
+     * @param octets the set of octets needed to determine the tag value 
+     *      (a.k.a identifier octets)
+     * @return the tag id
+     * @throws DecoderException if the id cannot be determined due to
+     *      type limitations of this method's return type. 
      */
-    public final static int getIdentifierEndIndex( byte[] a_buf, int a_idx )
+    public final static int getTagId( byte[] octets )
+        throws DecoderException
     {
-        int l_end = a_idx ;
-
-        // get the last five bits only zero out others
-        int l_value = a_buf[a_idx] & SHORT_TAG_MASK ;
-        
-        // if bits are not all 1's then identifier is short return the index
-        if ( l_value != SHORT_TAG_MASK )
+        if ( octets.length > 6 )
         {
-            return a_idx ;
+            /*
+             * If this exception is ever thrown which is highly unlikely, then
+             * we need to switch to another data type to return because after
+             * 5 bytes the int can no longer hold the number.
+             */
+            throw new DecoderException( "Tag number is too large." ) ;
         }
         
-        l_end++ ;
-        for ( ; l_end < a_buf.length; l_end++ )
-        {
-            if ( ( a_buf[l_end] & Binary.BIT_7 ) == 0 )
-            {
-                return l_end ;
-            }
-        }
+        int id = octets[0] & SHORT_TAG_MASK ;
         
-        throw new IllegalStateException( "Should never get here!" ) ;
-    }
-    
-
-    /**
-     * Given a buffer this method returns the index of the last identifier 
-     * octet (tag part of TLV).  If the short format is used then the returned 
-     * index is the given index parameter.  If the long format is used, the 
-     * returned index will be offset by one or more.  The returned index is 
-     * an octet of the identifier.
-     * 
-     * @param a_buf a buffer of TLVs
-     * @return the index containing the last octet of the TLV's Tag/Identifier
-     */
-    public final static int getIdentifierEndIndex( ByteBuffer a_buf )
-    {
-        return getIdentifierEndIndex( a_buf, 0 ) ;
-    }
-    
-
-    /**
-     * Given a buffer and some TLV start index in it, this method returns the
-     * index of the last identifier octet (tag part of TLV).  If the short 
-     * format is used then the returned index is the given index parameter.
-     * If the long format is used, the returned index will be offset by one 
-     * or more.  The returned index is an octet of the identifier.
-     * 
-     * @param a_buf a buffer of TLVs
-     * @param a_idx the start position of a TLV
-     * @return the index containing the last octet of the TLV's Tag/Identifier
-     */
-    public final static int getIdentifierEndIndex( ByteBuffer a_buf, int a_idx )
-    {
-        int l_end = a_idx ;
-
-        // get the last five bits only zero out others
-        int l_value = a_buf.get( a_idx ) & SHORT_TAG_MASK ;
-        
-        // if bits are not all 1's then identifier is short return the index
-        if ( l_value != SHORT_TAG_MASK )
+        // if bits are not all 1's then return the value which is less than 31
+        if ( id != SHORT_TAG_MASK && octets.length == 1 )
         {
-            return a_idx ;
+            return id ;
         }
         
-        l_end++ ;
-        for ( ; l_end < a_buf.limit(); l_end++ )
-        {
-            if ( ( a_buf.get( l_end ) & Binary.BIT_7 ) == 0 )
+        // clear the id now
+        id = 0 ;
+
+        // calculate tag value w/ long tag format
+        for( int ii = 1 ; ii < octets.length; ii++ )
+        {    
+            int shift = ( ii - 1 ) * 7 ;
+            if ( shift > 0 )
+            {    
+                id |= ( octets[ii] & LONG_TAG_MASK ) << shift ;
+            }
+            else
             {
-                return l_end ;
+                id |= ( octets[ii] & LONG_TAG_MASK ) ;
             }
         }
         
-        throw new IllegalStateException( "Should never get here!" ) ;
+        return id ;
     }
-    
+
 
     /**
-     * Gets the tag value of a TLV whether the short or long value encoding
-     * format is used.
+     * Gets the tag id of a TLV from the tag octets.
      * 
-     * @param a_octets the set of octets needed to determine the tag value 
+     * @param octets the set of octets needed to determine the tag value 
      *      (a.k.a identifier octets)
-     * @return the value of the tag
-     * @throws DecoderException if the value cannot be determined due to
+     * @return the tag id
+     * @throws DecoderException if the id cannot be determined due to
      *      type limitations of this method's return type. 
      */
-    public final static int getTagValue( byte[] a_octets )
+    public final static int getTagId( ArrayByteList octets )
         throws DecoderException
     {
-        // get the last five bits only zero out others
-        int l_value = a_octets[0] & SHORT_TAG_MASK ;
-        
-        // if bits are not all 1's then return the value which is less than 31
-        if ( l_value != SHORT_TAG_MASK )
+        if ( octets.size() > 6 )
         {
-            return l_value ;
+            /*
+             * If this exception is ever thrown which is highly unlikely, then
+             * we need to switch to another data type to return because after
+             * 5 bytes the int can no longer hold the number.
+             */
+            throw new DecoderException( "Tag number is too large." ) ;
         }
         
-        // Calculate tag value w/ long tag format for 128 > values > 30
-        l_value = a_octets[1] & LONG_TAG_MASK ;
-        if ( ( a_octets[1] & Binary.BIT_7 ) == 0 )
+        int id = octets.get( 0 ) & SHORT_TAG_MASK ;
+        
+        // if bits are not all 1's then return the value which is less than 31
+        if ( id != SHORT_TAG_MASK && octets.size() == 1 )
         {
-            return l_value ;
+            return id ;
         }
         
-        // Calculate tag value w/ long tag format for 16384 > values > 127
-        l_value |= ( a_octets[2] & LONG_TAG_MASK ) << 7 ;
-        if ( ( a_octets[2] & Binary.BIT_7 ) == 0 )
-        {
-            return l_value ;
+        // clear the id now
+        id = 0 ;
+
+        // calculate tag value w/ long tag format
+        for( int ii = 1 ; ii < octets.size(); ii++ )
+        {    
+            int shift = ( ii - 1 ) * 7 ;
+            if ( shift > 0 )
+            {    
+                id |= ( octets.get( ii ) & LONG_TAG_MASK ) << shift ;
+            }
+            else
+            {
+                id |= ( octets.get( ii ) & LONG_TAG_MASK ) ;
+            }
         }
         
-        /*
-         * If this exception is ever thrown which is highly unlikely, then
-         * this method can be extended to use another 2 octets before the
-         * int return type must be changed to one that can hold the value.
-         */
-        throw new DecoderException( "Tag function only recognizes tag values of"
-                + " up to 16383.  For larger values update the BerUtils.getTag"
-                + " function." ) ;
+        return id ;
     }
 
-
-    /**
-     * Gets the tag value of a TLV whether the short or long value encoding
-     * format is used.
-     * 
-     * @param a_octets the set of octets needed to determine the tag value 
-     *      (a.k.a identifier octets)
-     * @return the value of the tag
-     * @throws DecoderException if the value cannot be determined due to
-     *      type limitations of this method's return type. 
-     */
-    public final static int getTagValue( ByteBuffer a_octets )
-        throws DecoderException
+    
+    public static int getLength( ArrayByteList octets )
     {
-        // get the last five bits only zero out others
-        int l_value = a_octets.get( 0 ) & SHORT_TAG_MASK ;
-        
-        // if bits are not all 1's then return the value which is less than 31
-        if ( l_value != SHORT_TAG_MASK )
-        {
-            return l_value ;
-        }
-        
-        // Calculate tag value w/ long tag format for 128 > values > 30
-        l_value = a_octets.get( 1 ) & LONG_TAG_MASK ;
-        if ( ( a_octets.get( 1 ) & Binary.BIT_7 ) == 0 )
-        {
-            return l_value ;
-        }
-        
-        // Calculate tag value w/ long tag format for 16384 > values > 127
-        l_value |= ( a_octets.get( 2 ) & LONG_TAG_MASK ) << 7 ;
-        if ( ( a_octets.get( 2 ) & Binary.BIT_7 ) == 0 )
-        {
-            return l_value ;
-        }
-        
-        /*
-         * If this exception is ever thrown which is highly unlikely, then
-         * this method can be extended to use another 2 octets before the
-         * int return type must be changed to one that can hold the value.
-         */
-        throw new DecoderException( "Tag function only recognizes tag values of"
-                + " up to 16383.  For larger values update the BerUtils.getTag"
-                + " function." ) ;
+        throw new NotImplementedException( "STUB" ) ;
     }
 }

Added: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/IntStack.java
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/IntStack.java	Tue Mar  9 15:48:20 2004
@@ -0,0 +1,121 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.snickers.ber ;
+
+
+import java.util.EmptyStackException ;
+
+import org.apache.commons.collections.primitives.ArrayIntList ;
+
+
+/**
+ * A primitive int based Stack.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class IntStack
+{
+    /** the underlying dynamic primitive backing store */
+    private ArrayIntList list = new ArrayIntList() ;
+    
+
+    /**
+     * Tests if this stack is empty.
+     * 
+     * @return true if and only if this stack contains no ints; false otherwise
+     */
+    public boolean empty()
+    {
+        return list.isEmpty() ;
+    }
+
+    
+    /**
+     * Looks at the int at the top of this stack without removing it from 
+     * the stack.
+     * 
+     * @return int at the top of this stack (last int in ArrayIntList)
+     * @throws EmptyStackException if this stack is empty
+     */
+    public int peek()
+    {
+        if ( list.isEmpty() )
+        {
+            throw new EmptyStackException() ;
+        }
+        
+        return list.get( list.size() - 1 ) ;
+    }
+
+    
+    /**
+     * Removes the int at the top of this stack and returns that object as the 
+     * value of this function.
+     * 
+     * @return int at the top of this stack (last int in ArrayIntList)
+     * @throws EmptyStackException if this stack is empty
+     */
+    public int pop()
+    {
+        if ( list.isEmpty() )
+        {
+            throw new EmptyStackException() ;
+        }
+        
+        return list.removeElementAt( list.size() - 1 ) ;
+    }
+
+    
+    /**
+     * Pushes an int item onto the top of this stack.
+     * 
+     * @param item the int item to push onto this stack
+     * @return the item argument for call chaining
+     */
+    public int push( int item )
+    {
+        list.add( item ) ;
+        return item ;
+    }
+    
+
+    /**
+     * Returns the 1-based position where an int is on this stack. If the int 
+     * occurs as an item in this stack, this method returns the distance from 
+     * the top of the stack of the occurrence nearest the top of the stack; the 
+     * topmost item on the stack is considered to be at distance 1. 
+     * 
+     * @param item the int to search for from the top down
+     * @return the 1-based position from the top of the stack where the int is 
+     *  located; the return value -1 indicates that the int is not on the stack
+     */
+    public int search( int item )
+    {
+        for ( int ii = list.size() - 1; ii >= 0; ii-- )
+        {
+            if ( list.get( ii ) == item )
+            {
+                return list.size() - ii ;
+            }
+        }
+        
+        
+        return -1 ;
+    }
+}

Added: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/Tuple.java
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/Tuple.java	Tue Mar  9 15:48:20 2004
@@ -0,0 +1,478 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.snickers.ber ;
+
+
+import org.apache.commons.lang.ArrayUtils ;
+import org.apache.commons.codec.binary.Binary ;
+
+
+/**
+ * Simple TLV Tuple.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class Tuple
+{
+    /** precalculated left shift of 1 by 7 places */
+    public static final int SHIFT_7 = 1 << 7 ;
+    /** precalculated left shift of 1 by 14 places */
+    public static final int SHIFT_14 = 1 << 14 ;
+    /** precalculated left shift of 1 by 21 places */
+    public static final int SHIFT_21 = 1 << 21 ;
+    /** precalculated left shift of 1 by by 28 places */
+    public static final int SHIFT_28 = 1 << 28 ;
+    
+    /** the tag id for this TLV tuple */
+    int id = 0 ;
+    /** the flag for whether or not this TLV is constructed or primitive */
+    boolean isPrimitive = true ;
+    /** the type class for this TLV */
+    TypeClass typeClass = null ;
+    /** the length for this TLV tuple */
+    int length = 0 ;
+    /** the value for this TLV tuple */
+    Object value = null ;
+    
+    /** tlv byte index */
+    int index = BERDecoder.UNDEFINED ;
+    /** tlv value index for how far into the value we have read */
+    int valueIndex = BERDecoder.UNDEFINED ;
+    
+    
+    // ------------------------------------------------------------------------
+    // C O N S T R U C T O R S
+    // ------------------------------------------------------------------------
+    
+
+    /**
+     * Empty do nothing tuple that does not really have any member propertly 
+     * initialized.
+     */
+    Tuple() 
+    { 
+    }
+    
+    
+    /**
+     * Creates a constructed application tuple with the following tag id and 
+     * with an indefinate value length.
+     * 
+     * @param id the tag id of the tlv
+     */
+    public Tuple( int id )
+    {
+        this( id, BERDecoder.INDEFINATE, TypeClass.APPLICATION, false, null ) ;
+    }
+    
+    
+    /**
+     * Creates a constructed application type tlv with a set length. 
+     * 
+     * @param id the tag id of the tlv
+     * @param length the length of the tlv
+     */
+    public Tuple( int id, int length )
+    {
+        this( id, length, TypeClass.APPLICATION, false, null ) ;
+    }
+    
+    
+    /**
+     * Creates a tuple where every member is specified.
+     * 
+     * @param id the tag id of the tlv
+     * @param length the length of the tlv
+     * @param typeClass the type class for the tlv
+     * @param isPrimitive whether or not the tlv is primitive or constructed
+     * @param value the 
+     */
+    public Tuple( int id, int length, TypeClass typeClass, boolean isPrimitive,
+                  byte[] value )
+    {
+        this.id = id ;
+        this.length = length ;
+        this.typeClass = typeClass ;
+        this.isPrimitive = isPrimitive ;
+        this.value = value ;
+    }
+    
+    
+    // ------------------------------------------------------------------------
+    // Public Accessors
+    // ------------------------------------------------------------------------
+    
+    
+    /**
+     * @return the id
+     */
+    public int getId()
+    {
+        return id ;
+    }
+    
+
+    /**
+     * @return the isPrimitive
+     */
+    public boolean isPrimitive()
+    {
+        return isPrimitive ;
+    }
+
+    
+    /**
+     * @return the length
+     */
+    public int getLength()
+    {
+        return length ;
+    }
+
+    
+    /**
+     * @return the typeClass
+     */
+    public TypeClass getTypeClass()
+    {
+        return typeClass ;
+    }
+
+    
+    /**
+     * @return the value
+     */
+    public Object getValue()
+    {
+        return value ;
+    }
+    
+    
+    // ------------------------------------------------------------------------
+    // Utility methods and Object overrides
+    // ------------------------------------------------------------------------
+    
+    
+    /**
+     * Clears the values of this tuple.
+     */
+    public void clear()
+    {
+        this.id = 0 ;
+        this.index = 0 ;
+        this.isPrimitive = true ;
+        this.length = BERDecoder.UNDEFINED ;
+        this.typeClass = null ;
+        this.value = null ;
+        this.valueIndex = BERDecoder.UNDEFINED ;
+    }
+
+    
+    /*
+     * (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals( Object o )
+    {
+        if ( o instanceof Tuple )
+        {
+            Tuple t = ( Tuple ) o ;
+            
+            if ( t.id != id )
+            {
+                return false ;
+            }
+            
+            if ( t.index != index )
+            {
+                return false ;
+            }
+            
+            if ( t.isPrimitive != isPrimitive )
+            {
+                return false ;
+            }
+            
+            if ( t.length != length )
+            {
+                return false ;
+            }
+            
+            if ( t.typeClass != typeClass )
+            {
+                return false ;
+            }
+            
+            if ( ArrayUtils.isEquals( t.value, value ) )
+            {
+                return false ;
+            }
+            
+            if ( t.valueIndex != valueIndex )
+            {
+                return false ;
+            }
+        }
+        
+        return false ;
+    }
+    
+
+    /*
+     * (non-Javadoc)
+     * @see java.lang.Object#clone()
+     */
+    public Object clone()
+    {
+        Tuple t = new Tuple() ;
+        t.id = id ;
+        t.isPrimitive = isPrimitive ;
+        t.typeClass = typeClass ;
+        t.length = length ;
+        t.value = value ;
+        t.index = index ;
+        t.valueIndex = valueIndex ;
+        
+        return t ;
+    }
+    
+    
+    // ------------------------------------------------------------------------
+    // Tuple encoding operations
+    // ------------------------------------------------------------------------
+    
+    
+    /**
+     * If this is a primitive TLV then it is encoded fully.  If it is not then
+     * only the TL part of the tuple is encoded leaving the value to be encoded
+     * by the set of child TLVs.
+     * 
+     * @return partial encoded image if constructed or complete TLV if primitive
+     */
+    public byte[] encode()
+    {
+        byte[] octets = null ;
+        int tagLength = getTagLength() ;
+        int lengthLength = getLengthLength() ;
+        int valueLength = 0 ;
+        int total = tagLength + lengthLength ;
+
+        if ( isPrimitive )
+        {
+            valueLength = ( ( byte[] ) value ).length ;
+            total += valueLength ;
+        }
+        
+        octets = new byte[total] ;
+        setTag( octets, tagLength ) ;
+        setLength( octets, tagLength, lengthLength ) ;
+        
+        if ( isPrimitive )
+        {
+            int destPos = tagLength + lengthLength ;
+            System.arraycopy( value, 0, octets, destPos, valueLength ) ;
+        }
+        
+        return octets ;
+    }
+    
+    
+    /**
+     * Sets the tag section within the array at the start of the array.
+     * 
+     * @param octets the array of bytes to set the tag in
+     * @param tagLength the length of the tag section
+     */
+    public void setTag( byte[] octets, int tagLength )
+    {
+        octets[0] = ( byte ) typeClass.getValue() ;
+        
+        if ( ! isPrimitive )
+        {
+            octets[0] |= Binary.BIT_5 ;
+        }
+        
+        if ( tagLength == 1 )
+        {
+            octets[0] |= id ;
+            return ;
+        }
+        else
+        {
+            octets[0] |= BERUtils.SHORT_TAG_MASK ;
+        }
+        
+        if ( tagLength >= 2 )
+        {
+            int shifted = id << 25 ;
+            octets[1] = ( byte ) ( shifted >> 25 ) ;
+            
+            if ( tagLength > 2 )
+            {
+                octets[1] |= Binary.BIT_7 ;
+            }
+        }
+        else if ( tagLength >= 3 )
+        {
+            int shifted = id << 18 ;
+            octets[2] = ( byte ) ( shifted >> 25 ) ;
+            
+            if ( tagLength > 3 )
+            {
+                octets[2] |= Binary.BIT_7 ;
+            }
+        }
+        else if ( tagLength >= 4 )
+        {
+            int shifted = id << 11 ;
+            octets[3] = ( byte ) ( shifted >> 25 ) ;
+            
+            if ( tagLength > 4 )
+            {
+                octets[3] |= Binary.BIT_7 ;
+            }
+        }
+        else if ( tagLength >= 5 )
+        {
+            int shifted = id << 4 ;
+            octets[4] = ( byte ) ( shifted >> 25 ) ;
+            
+            if ( tagLength > 5 )
+            {
+                octets[4] |= Binary.BIT_7 ;
+            }
+        }
+        else if ( tagLength >= 6 )
+        {    
+            throw new IllegalArgumentException( "cannot support id's as large "
+                    + "as " + id + " unless we start using longs for the id" ) ;
+        }
+    }
+
+
+    /**
+     * Sets the length bytes.
+     * 
+     * @param octets the byte [] to set length in
+     * @param offset the offset in the array to start the length section in
+     * @param lengthOfLength the length of the length section
+     */
+    public void setLength( byte[] octets, int offset, int lengthOfLength )
+    {
+        if ( length == 1 )
+        {
+            octets[offset] |= length ;
+            return ;
+        }
+        else
+        {
+            octets[offset] |= Binary.BIT_7 | lengthOfLength ;
+        }
+        
+        if ( lengthOfLength >= 2 )
+        {
+            int shifted = length << 25 ;
+            octets[offset + 1] = ( byte ) ( shifted >> 25 ) ;
+        }
+        else if ( lengthOfLength >= 3 )
+        {
+            int shifted = length << 18 ;
+            octets[offset + 2] = ( byte ) ( shifted >> 25 ) ;
+        }
+        else if ( lengthOfLength >= 4 )
+        {
+            int shifted = length << 11 ;
+            octets[offset + 3] = ( byte ) ( shifted >> 25 ) ;
+        }
+        else if ( lengthOfLength >= 5 )
+        {
+            int shifted = length << 4 ;
+            octets[offset + 4] = ( byte ) ( shifted >> 25 ) ;
+        }
+        else if ( lengthOfLength >= 6 )
+        {    
+            throw new IllegalArgumentException( "cannot support lengths as "
+                    + "large as " + length 
+                    + " unless we start using longs for the length" ) ;
+        }
+    }
+
+
+    /**
+     * Gets the length in bytes of the tag section for this TLV tuple.
+     * 
+     * @return the length in bytes of the tag section for this TLV tuple
+     */
+    public int getTagLength()
+    {
+        if ( id < 31 )
+        {
+            return 1 ;
+        }
+        else if ( id < SHIFT_7 )
+        {
+            return 2 ;
+        }
+        
+        else if ( id < SHIFT_14 )
+        {
+            return 3 ;
+        }
+        else if ( id < SHIFT_21 )
+        {
+            return 4 ;
+        }
+        else if ( id < SHIFT_28 )
+        {
+            return 5 ;
+        }
+        
+        throw new IllegalArgumentException( "cannot support id's larger than " 
+                + id + " unless we start using longs for the id" ) ;
+    }
+    
+    
+    /**
+     * Gets the length in bytes of the length section of this TLV Tuple.
+     * 
+     * @return the length in bytes of the length section
+     */
+    public int getLengthLength()
+    {
+        if ( length < SHIFT_7 )
+        {
+            return 1 ;
+        }
+        else if ( length < SHIFT_14 )
+        {    
+            return 3 ;
+        }
+        else if ( length < SHIFT_21 )
+        {
+            return 4 ;
+        }
+        else if ( length < SHIFT_28 )
+        {
+            return 5 ;
+        }
+
+        throw new IllegalArgumentException( "cannot support lengths's as large " 
+                + "as " + id + " unless we start using longs for them" ) ;
+    }
+}

Modified: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/TypeClass.java
==============================================================================
--- incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/TypeClass.java	(original)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/TypeClass.java	Tue Mar  9 15:48:20 2004
@@ -1,66 +1,33 @@
 /*
-
- ============================================================================
-                   The Apache Software License, Version 1.1
- ============================================================================
-
- Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
-
- Redistribution and use in source and binary forms, with or without modifica-
- tion, are permitted provided that the following conditions are met:
-
- 1. Redistributions of  source code must  retain the above copyright  notice,
-    this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright notice,
-    this list of conditions and the following disclaimer in the documentation
-    and/or other materials provided with the distribution.
-
- 3. The end-user documentation included with the redistribution, if any, must
-    include  the following  acknowledgment:  "This product includes  software
-    developed  by the  Apache Software Foundation  (http://www.apache.org/)."
-    Alternately, this  acknowledgment may  appear in the software itself,  if
-    and wherever such third-party acknowledgments normally appear.
-
- 4. The names "Eve Directory Server", "Apache Directory Project", "Apache Eve" 
-    and "Apache Software Foundation"  must not be used to endorse or promote
-    products derived  from this  software without  prior written
-    permission. For written permission, please contact apache@apache.org.
-
- 5. Products  derived from this software may not  be called "Apache", nor may
-    "Apache" appear  in their name,  without prior written permission  of the
-    Apache Software Foundation.
-
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
- APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
- INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
- DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
- OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
- ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
- (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- This software  consists of voluntary contributions made  by many individuals
- on  behalf of the Apache Software  Foundation. For more  information on the
- Apache Software Foundation, please see <http://www.apache.org/>.
-
-*/
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
 package org.apache.snickers.ber ;
 
 
 import java.util.Map ;
 import java.util.List ;
 
-import org.apache.commons.codec.binary.Binary;
+import org.apache.commons.codec.binary.Binary ;
 import org.apache.commons.lang.enum.EnumUtils ;
 import org.apache.commons.lang.enum.ValuedEnum ;
 
 
 /**
  * Type safe enum for an ASN.1 type class.  This can be take one of the 
- * following three values: 
+ * following four values: 
  * <ul>
  * <li>UNIVERSAL</li>
  * <li>APPLICATION</li>
@@ -69,7 +36,7 @@
  * </ul>
  * 
  * @author <a href="mailto:akarasulu@apache.org">Alex Karasulu</a>
- * @author $Author$
+ * @author $Author: akarasulu $
  * @version $Rev$
  */
 public class TypeClass extends ValuedEnum

Added: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/package.html
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/package.html	Tue Mar  9 15:48:20 2004
@@ -0,0 +1,40 @@
+<p>
+  The decoder must be aware of it's current state.  The following states are
+  possible in between TLV tuples:
+</p>  
+<ol>
+  <li>
+    Composing Tag - The decoder starts in this mode.  This is the mode for
+    collecting bytes for the Tag of the TLV in scope.  Bytes are copied into
+    a temporary Tag byte buffer until the Tag data is complete.  Once the 
+    bytes are complete and the Tag int is generated along with a couple of other
+    values (boolean isPrimitive and TypeClassEnum), the Tag byte buffer is
+    cleared and the state switches to the composing length state.  If the Tag
+    data is incomplete and not available until the next chunk of data arrives
+    via another decode call, we remain suspended in this state collecting the 
+    tag bytes.  There are no pushes onto any of the stacks during this state.
+  </li>
+  <li>
+    Composing Length - The decoder starts reading data into a Length byte 
+    buffer until the Length data is complete whether the length data is the 
+    short, long or indeterminate form.  Once the bytes for the length are arrive
+    and the Length int is generated, the Length byte buffer is cleared.  If
+    the Tag represents a primitive type the state switches to the composing 
+    value state.  If the TLV is constructed, the tag and the length are pushed 
+    onto their respective stacks.  The state then switches to the composing Tag
+    state.  If the length data is incomplete and not available until the next 
+    chunk of data arrives via another decode call, we remain suspended in this 
+    state.
+  </li>
+  <li>
+    Composing Value - The decoder is in this mode because the TLV is 
+    primitive.  In this state only two forms of length are valid: the short
+    and long lengths.  In either case we just read the number of bytes 
+    specified for the length during the length composing state.  If the value
+    data is incomplete and not avaiable until the next chunk of data arrives
+    via another decode call we remain suspended in this state.  We transit
+    to the composing Tag state from this state when the value data arrives.
+    Before transiting to the composing Tag state the stacks are popped and
+    the TLV is delivered as a completion event to the callback.
+  </li>
+</ol>

Modified: incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/util/TLVParsingUtility.java
==============================================================================
--- incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/util/TLVParsingUtility.java	(original)
+++ incubator/directory/snickers/trunk/ber/src/java/org/apache/snickers/ber/util/TLVParsingUtility.java	Tue Mar  9 15:48:20 2004
@@ -54,6 +54,7 @@
 import java.io.FileInputStream;
 
 import org.apache.commons.codec.binary.*;
+import org.apache.snickers.asn.*;
 import org.apache.snickers.ber.*;
 
 /**
@@ -102,8 +103,8 @@
             count++;
             
             int id = tag & (Binary.BIT_4 | Binary.BIT_3 | Binary.BIT_2 | Binary.BIT_1 | Binary.BIT_0 );
-            boolean primative =  BerUtils.isPrimitive(tag);
-            TypeClass tc = BerUtils.getTypeClass(tag);
+            boolean primative =  BERUtils.isPrimitive(tag);
+            TypeClass tc = BERUtils.getTypeClass(tag);
             
             System.out.println( strIndent + ">>>>>>>>>>>>>> TLV <<<<<<<<<<<<<" );
             System.out.println( strIndent + "Tag:  " + toBits(tag) );

Added: incubator/directory/snickers/trunk/ber/src/test/org/apache/snickers/ber/BERUtilsTest.java
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/trunk/ber/src/test/org/apache/snickers/ber/BERUtilsTest.java	Tue Mar  9 15:48:20 2004
@@ -0,0 +1,229 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.snickers.ber ;
+
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Binary;
+
+import junit.framework.TestCase ;
+
+
+/**
+ * Tests the BER utility functions.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class BERUtilsTest extends TestCase
+{
+
+    public static void main(String[] args)
+    {
+        junit.textui.TestRunner.run(BERUtilsTest.class);
+    }
+
+    /*
+     * @see TestCase#setUp()
+     */
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+    }
+
+    /*
+     * @see TestCase#tearDown()
+     */
+    protected void tearDown() throws Exception
+    {
+        super.tearDown();
+    }
+
+    /**
+     * Constructor for BERUtilsTest.
+     * @param arg0
+     */
+    public BERUtilsTest(String arg0)
+    {
+        super(arg0);
+    }
+    
+    
+    public void testIsPrimitive() throws Exception
+    {
+        byte octet = Binary.BIT_5 ;
+        
+        assertFalse( BERUtils.isPrimitive( octet ) ) ;
+        assertFalse( BERUtils.isPrimitive( Binary.BIT_5 ) ) ;
+        
+        assertTrue( BERUtils.isPrimitive( 0 ) ) ;
+        assertTrue( BERUtils.isPrimitive( Binary.BIT_0 ) ) ;
+        assertTrue( BERUtils.isPrimitive( Binary.BIT_1 ) ) ;
+        assertTrue( BERUtils.isPrimitive( Binary.BIT_2 ) ) ;
+        assertTrue( BERUtils.isPrimitive( Binary.BIT_3 ) ) ;
+        assertTrue( BERUtils.isPrimitive( Binary.BIT_4 ) ) ;
+        assertTrue( BERUtils.isPrimitive( Binary.BIT_6 ) ) ;
+        assertTrue( BERUtils.isPrimitive( Binary.BIT_7 ) ) ;
+    }
+
+
+    public void testIsConstructed() throws Exception
+    {
+        byte octet = Binary.BIT_5 ;
+        
+        assertTrue( BERUtils.isConstructed( octet ) ) ;
+        assertTrue( BERUtils.isConstructed( Binary.BIT_5 ) ) ;
+        
+        assertFalse( BERUtils.isConstructed( 0 ) ) ;
+        assertFalse( BERUtils.isConstructed( Binary.BIT_0 ) ) ;
+        assertFalse( BERUtils.isConstructed( Binary.BIT_1 ) ) ;
+        assertFalse( BERUtils.isConstructed( Binary.BIT_2 ) ) ;
+        assertFalse( BERUtils.isConstructed( Binary.BIT_3 ) ) ;
+        assertFalse( BERUtils.isConstructed( Binary.BIT_4 ) ) ;
+        assertFalse( BERUtils.isConstructed( Binary.BIT_6 ) ) ;
+        assertFalse( BERUtils.isConstructed( Binary.BIT_7 ) ) ;
+    }
+    
+    
+    public void testGetTagId() throws Exception
+    {
+        byte[] octets = new byte[1] ;
+        
+        for ( int ii = 0 ; ii < 128; ii++ )
+        {
+            octets[0] = ( byte ) ii ;
+            
+            if ( ii < 31 ) 
+            {
+                assertEquals( BERUtils.getTagId( octets ), ii ) ;
+            }
+            else
+            {
+                assertTrue( BERUtils.getTagId( octets ) != ii ) ;
+            }
+        }
+        
+        octets = new byte[2] ;
+        octets[0] = 31 ;
+        octets[1] = 0 ;
+        
+        for ( int ii = 31 ; ii < 255; ii++ )
+        {
+            octets[1] = ( byte ) ii ;
+            
+            if ( ii < 128 ) 
+            {
+                assertEquals( BERUtils.getTagId( octets ), ii ) ;
+            }
+            else
+            {
+                assertTrue( BERUtils.getTagId( octets ) != ii ) ;
+            }
+        }
+        
+        octets = new byte[3] ;
+        octets[0] = 31 ;
+        octets[1] = 0 ;
+        octets[2] = 0 ;
+        
+        for ( int ii = 128 ; ii < 20000; ii++ )
+        {
+            octets[1] = ( byte ) ( ii & BERUtils.LONG_TAG_MASK ) ;
+            octets[2] = ( byte ) ( ( ii >> 7 ) & BERUtils.LONG_TAG_MASK ) ;
+            
+            if ( ii < 16384 ) 
+            {
+                assertEquals( BERUtils.getTagId( octets ), ii ) ;
+            }
+            else
+            {
+                assertTrue( BERUtils.getTagId( octets ) != ii ) ;
+            }
+        }
+
+        octets = new byte[6] ;
+        octets[0] = 31 ;
+        octets[1] = 0 ; // shift 0
+        octets[2] = 0 ; // shift 7
+        octets[3] = 0 ; // shift 14
+        octets[4] = 0 ; // shift 21
+        octets[5] = 0 ; // shift 28
+        
+        for ( int ii = 16384 ; ii < 2100000 ; ii++ )
+        {
+            octets[1] = ( byte ) ( ii & BERUtils.LONG_TAG_MASK ) ;
+            octets[2] = ( byte ) ( ( ii >> 7 ) & BERUtils.LONG_TAG_MASK ) ;
+            octets[3] = ( byte ) ( ( ii >> 14 ) & BERUtils.LONG_TAG_MASK ) ;
+            
+            if ( ii < 2097152 ) 
+            {
+                assertEquals( BERUtils.getTagId( octets ), ii ) ;
+            }
+            else
+            {
+                assertTrue( BERUtils.getTagId( octets ) != ii ) ;
+            }
+        }
+        
+        octets = new byte[7] ;
+        octets[0] = 31 ;
+        octets[1] = 1 ;
+        octets[2] = 0 ;
+        octets[3] = 0 ;
+        octets[4] = 0 ;
+        octets[5] = 0 ;   
+        octets[6] = 0 ;
+        
+        try
+        {
+            BERUtils.getTagId( octets ) ;
+            fail( "the line above should blow and exception" ) ;
+        }
+        catch( DecoderException e )
+        {
+            assertNotNull( e ) ;
+        }
+
+        /* loop takes too long but it works
+        octets = new byte[6] ;
+        octets[0] = 31 ;
+        octets[1] = 0 ;
+        octets[2] = 0 ;
+        octets[3] = 0 ;
+        octets[4] = 0 ;
+        octets[5] = 0 ;   
+        
+        for ( int ii = 2097152 ; ii < 269435456 ; ii++ )
+        {
+            octets[1] = ( byte ) ( ii & BERUtils.LONG_TAG_MASK ) ;
+            octets[2] = ( byte ) ( ( ii >> 7 ) & BERUtils.LONG_TAG_MASK ) ;
+            octets[3] = ( byte ) ( ( ii >> 14 ) & BERUtils.LONG_TAG_MASK ) ;
+            octets[4] = ( byte ) ( ( ii >> 21 ) & BERUtils.LONG_TAG_MASK ) ;
+            
+            if ( ii < 268435456 ) 
+            {
+                assertEquals( BERUtils.getTagId( octets ), ii ) ;
+            }
+            else
+            {
+                assertTrue( BERUtils.getTagId( octets ) != ii ) ;
+            }
+        }
+        */
+    }
+}

Added: incubator/directory/snickers/trunk/ber/src/test/org/apache/snickers/ber/IntStackTest.java
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/trunk/ber/src/test/org/apache/snickers/ber/IntStackTest.java	Tue Mar  9 15:48:20 2004
@@ -0,0 +1,150 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.snickers.ber ;
+
+
+import java.util.EmptyStackException;
+
+import junit.framework.TestCase ;
+
+
+/**
+ * Tests the IntStack class.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class IntStackTest extends TestCase
+{
+    IntStack stack = null ;
+    
+    
+    /**
+     * Runs the test. 
+     * 
+     * @param args nada
+     */
+    public static void main( String[] args )
+    {
+        junit.textui.TestRunner.run( IntStackTest.class ) ;
+    }
+
+    
+    /* (non-Javadoc)
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception
+    {
+        super.setUp() ;
+        stack = new IntStack() ;
+    }
+    
+    
+    /**
+     * Constructor for IntStackTest.
+     * @param arg0
+     */
+    public IntStackTest( String arg0 )
+    {
+        super( arg0 ) ;
+    }
+
+    
+    public void testEmpty()
+    {
+        assertTrue( "Newly created stacks should be empty", stack.empty() ) ;
+        stack.push( 0 ) ;
+        assertFalse( "Stack with item should not be empty", stack.empty() ) ;
+        stack.pop() ;
+        assertTrue( "Stack last int popped should be empty", stack.empty() ) ;
+    }
+
+    
+    public void testPeek()
+    {
+        try
+        {
+            stack.peek() ;
+            throw new AssertionError( 
+                    "Peek should have thrown an EmptyStackException" ) ;
+        }
+        catch( EmptyStackException e )
+        {
+            assertNotNull( "EmptyStackException should not be null", e ) ;
+        }
+        
+        for( int ii = 0; ii < 10; ii++ )
+        {    
+            stack.push( ii ) ;
+            assertEquals( ii, stack.peek() ) ;
+        }
+    }
+
+    
+    public void testPop()
+    {
+        try
+        {
+            stack.pop() ;
+            throw new AssertionError( 
+                    "Pop should have thrown an EmptyStackException" ) ;
+        }
+        catch( EmptyStackException e )
+        {
+            assertNotNull( "EmptyStackException should not be null", e ) ;
+        }
+        
+        for( int ii = 0; ii < 10; ii++ )
+        {    
+            stack.push( ii ) ;
+            assertEquals( ii, stack.pop() ) ;
+        }
+
+        for( int ii = 0; ii < 10; ii++ )
+        {    
+            stack.push( ii ) ;
+        }
+        for( int ii = 10; ii < 0; ii-- )
+        {    
+            stack.push( ii ) ;
+            assertEquals( ii, stack.pop() ) ;
+        }
+    }
+
+    
+    public void testPush()
+    {
+        stack.push( 0 ) ;
+        stack.push( 0 ) ;
+        assertFalse( stack.empty() ) ;
+        assertEquals( 0, stack.pop() ) ;
+        assertEquals( 0, stack.pop() ) ;
+    }
+
+    
+    public void testSearch()
+    {
+        stack.push( 0 ) ;
+        stack.push( 1 ) ;
+        assertEquals( 2, stack.search( 0 ) ) ;
+        stack.push( 0 ) ;
+        assertEquals( 1, stack.search( 0 ) ) ;
+        stack.push( 0 ) ;
+        assertEquals( 3, stack.search( 1 ) ) ;
+    }
+}

Added: incubator/directory/snickers/trunk/ber/src/test/org/apache/snickers/ber/ObjectVersePrimitiveTest.java
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/trunk/ber/src/test/org/apache/snickers/ber/ObjectVersePrimitiveTest.java	Tue Mar  9 15:48:20 2004
@@ -0,0 +1,158 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.snickers.ber ;
+
+
+import java.util.Stack;
+
+import org.apache.commons.lang.time.StopWatch;
+
+import junit.framework.TestCase ;
+
+
+/**
+ * $todo$ doc me
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class ObjectVersePrimitiveTest extends TestCase
+{
+    public static final int MEMBER_COUNT = 3 ;
+    public static final int INSTANCE_COUNT = 10000000 ;
+    public static final Class OBJECT_CLASS = Tuple.class ;
+    
+    long objTime = 0 ;
+    double objTimePerInst = 0.0 ;
+    long objTimeNew = 0 ;
+    double objTimeNewPerInst = 0.0 ;
+    long intTime = 0 ;
+    double intTimePerInst = 0.0 ;
+    
+    IntStack[] intStacks = new IntStack[MEMBER_COUNT] ;
+    Stack objStack = null ;
+
+    
+    public static void main( String[] args )
+    {
+        junit.textui.TestRunner.run( ObjectVersePrimitiveTest.class ) ;
+    }
+
+    
+    /* (non-Javadoc)
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception
+    {
+        super.setUp() ;
+        
+        objStack = new Stack() ;
+        for ( int ii = 0; ii < intStacks.length; ii++ )
+        {
+            intStacks[ii] = new IntStack() ;
+        }
+    }
+    
+    
+    /* (non-Javadoc)
+     * @see junit.framework.TestCase#tearDown()
+     */
+    protected void tearDown() throws Exception
+    {
+        super.tearDown();
+        
+        objStack = null ;
+        for ( int ii = 0; ii < intStacks.length; ii++ )
+        {
+            intStacks[ii] = null ;
+        }
+    }
+    
+    
+    public void testObject()
+    {
+        StopWatch sw = new StopWatch() ;
+        sw.start() ;
+        for ( int ii = 0; ii < INSTANCE_COUNT; ii++ )
+        {
+            Object obj = new Tuple() ;
+            objStack.push( obj ) ;
+            objStack.pop() ;
+        }
+        sw.stop() ;
+        objTime = sw.getTime() ;
+        objTimePerInst = objTime/INSTANCE_COUNT ;
+        System.out.println( "----------------------------------------------" ) ;
+        System.out.println( "TEST: java.lang.Object create, push and pop" ) ;
+        System.out.println( "----------------------------------------------" ) ;
+        System.out.println( "# of Instances: " + INSTANCE_COUNT ) ;
+        System.out.println( "Total Time: " + objTime ) ;
+        System.out.println( "Per Instance Time: " + objTimePerInst ) ;
+        System.out.println( "----------------------------------------------" ) ;
+    }
+    
+
+    public void testObjectNewInstance() throws Exception
+    {
+        StopWatch sw = new StopWatch() ;
+        sw.start() ;
+        for ( int ii = 0; ii < INSTANCE_COUNT; ii++ )
+        {
+            Object obj = OBJECT_CLASS.newInstance() ;
+            objStack.push( obj ) ;
+            objStack.pop() ;
+        }
+        sw.stop() ;
+        objTimeNew = sw.getTime() ;
+        objTimeNewPerInst = objTimeNew/INSTANCE_COUNT ;
+        System.out.println( "----------------------------------------------" ) ;
+        System.out.println( "TEST: " + OBJECT_CLASS 
+                + ".newInstance create, push, pop" ) ;
+        System.out.println( "----------------------------------------------" ) ;
+        System.out.println( "# of Instances: " + INSTANCE_COUNT ) ;
+        System.out.println( "Total Time: " + objTimeNew ) ;
+        System.out.println( "Per Instance Time: " + objTimeNewPerInst ) ;
+        System.out.println( "----------------------------------------------" ) ;
+    }
+
+
+    public void testPrimitive()
+    {
+        StopWatch sw = new StopWatch() ;
+        sw.start() ;
+        for ( int ii = 0; ii < INSTANCE_COUNT; ii++ )
+        {
+            for ( int jj = 0; jj < MEMBER_COUNT; jj++ )
+            {
+                intStacks[jj].push( jj ) ;
+                intStacks[jj].pop() ;
+            }
+        }
+        sw.stop() ;
+        intTime = sw.getTime() ;
+        intTimePerInst = intTime/INSTANCE_COUNT ;
+        System.out.println( "----------------------------------------------" ) ;
+        System.out.println( "TEST: push " + MEMBER_COUNT + " primitive ints "
+                + "onto separate stacks then pop em" ) ;
+        System.out.println( "----------------------------------------------" ) ;
+        System.out.println( "# of Instances: " + INSTANCE_COUNT ) ;
+        System.out.println( "Total Time: " + intTime ) ;
+        System.out.println( "Per Instance Time: " + intTimePerInst ) ;
+        System.out.println( "----------------------------------------------" ) ;
+    }
+}

Added: incubator/directory/snickers/trunk/ber/src/test/org/apache/snickers/ber/OneByteTagTests.java
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/trunk/ber/src/test/org/apache/snickers/ber/OneByteTagTests.java	Tue Mar  9 15:48:20 2004
@@ -0,0 +1,47 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.snickers.ber ;
+
+
+/**
+ * Here we test simple 1 byte tag and length values to test the decoder's 
+ * ability to handle these most simple tlvs.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class OneByteTagTests extends BERDecoderTest
+{
+
+    /**
+     * @param arg0
+     */
+    public OneByteTagTests( String arg0 )
+    {
+        super( arg0 ) ;
+    }
+    
+    
+    public void test0() throws Exception
+    {
+        Tuple tlv = decode( "01000001" ) ;
+        assertEquals( 1, tlv.id ) ;
+        assertEquals( 0, tlvList.size() ) ;
+        assertEquals( BERDecoderState.LENGTH, decoder.getState() ) ;
+    }
+}

Added: incubator/directory/snickers/trunk/ber/xdocs/decoder-design.xml
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/trunk/ber/xdocs/decoder-design.xml	Tue Mar  9 15:48:20 2004
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document>
+  <properties>
+    <author email="akarasulu@apache.org">Alex Karasulu</author>
+    <title>Design Documentation</title>
+  </properties>
+  <body>
+    <section name="Stateful Decoder">
+      <p>
+        We're designing the decoder peice using the stateful decoder interfaces
+        that were carved up for the commons-codec API within their stateful 
+        package.  The stateful decoder is designed to maintain state while 
+        processing arriving chunks of TLV data.
+      </p>
+      
+      <p>
+        The issues confronted by the decoder while decoding a stream of TLV 
+        trees where TLV tuples are nested are documented within the subsections 
+        to follow.
+      </p>
+    </section>
+    
+    <section name="Object Reuse and Using Primitive Types">
+      <p>
+        We need the decoder to be as fast and simple as possible.  We would 
+        like to do this one task and do it well.  When designing the decoder
+        we realized the volume of TLV tuples encountered will be huge.  The
+        the TLV density within a BER encoded message could be very high.  So 
+        we must make sure we're keeping object instantiation down to a minimum
+        if we want to keep performance high and memory overheads low.  There 
+        are two ways in which we 
+      </p>
+        <p>
+          The TLV trees of nested TLV tuples comming into the decoder are managed 
+          using multiple stacks.  Rather than instantiate TLV tuples for each TLV
+          encountered the decoder only uses a single tuple instance which it 
+          changes the values to.
+        </p>
+        
+      </subsection>
+    </section>
+    
+  </body>
+</document>
\ No newline at end of file

Modified: incubator/directory/snickers/trunk/ber/xdocs/design.xml
==============================================================================
--- incubator/directory/snickers/trunk/ber/xdocs/design.xml	(original)
+++ incubator/directory/snickers/trunk/ber/xdocs/design.xml	Tue Mar  9 15:48:20 2004
@@ -5,8 +5,96 @@
     <title>Design Documentation</title>
   </properties>
   <body>
-    <section name="Design Documentation">
-      <p>Hang tight we'll be working this as we solidify our thoughts.</p>
+    <section name="Introduction">
+      <p>
+        We're designing the decoder peice using the stateful decoder interfaces
+        that were carved up for the commons-codec API within their stateful 
+        package.  The stateful decoder is designed to maintain state while 
+        processing arriving chunks of TLV data.
+      </p>
+      
+      <p>
+        There are several issues confronted by the decoder while decoding a 
+        stream of TLV trees where TLV tuples are nested within each other.  In
+        general this decoder is viewed as a simple line parser for TLV tuples
+        notifying of their arrival via callbacks.
+      </p>
     </section>
+    
+    <section name="Requirements">
+      <p>
+        The decoder must be fast, have a fixed memory footprint, and be simple.
+        It should perform only one task: notifying content handlers via 
+        callbacks of the arrival of TLV tuples.  While doing so it must maintain
+        state in between calls to decode a chunk of arriving BER encoded data.
+      </p>
+      
+      <p>
+        It should not try to interpret the content of the TLV tuples.  These 
+        aspects are left to be handled by higher level content based facilities
+        that build on top of the BERDecoder.  These higher facilities provide 
+        their own callbacks to build on TLV events.
+      </p>
+    </section>
+    
+    <section name="Object Reuse and Using Primitive Types">
+      <p>
+        The density of TLV tuples encountered during decoder operation will 
+        vary based on message characteristics.  One of the most involved aspects
+        to the decoder is to spit out TLV tuples when emitting events.
+      </p>
+      
+      <p>
+        We could just instantiate a new TLV tuple object for every tuple but
+        this would slow the decoder down and increase the memory footprint 
+        making it less efficient.  For this reason we decided to reuse the same
+        TLV tuple to deliver TLV data via notification events on the callback.
+        The callback implementation must copy the tuple's data if it intends to
+        save the TLV for use later.  Otherwise the decoder will overwrite the 
+        TLV members on the next event.  We leave the option to copy the TLV 
+        upto the higher level facility that way only those TLV tuples of 
+        interest, known only to the content specific handler, can be copied.
+        Why waste space and time within the decoder one those events that will
+        not be of interest?
+      </p>
+       
+      <p>
+        The most complex part of the decoder deals with maintaining state while
+        decoding.  Data can arrive at any time to contain any part of a TLV or
+        multiple TLVs along with parts of others.  Often the fragmentation of
+        the data will not be known.  Furthermore the nesting of TLVs must be
+        tracked while maintaining state.  A stack is perhaps the best structure
+        to use to track the nesting of TLV tuples within a TLV tree.
+      </p>
+      
+      <p>
+        We do not instantiate TLV tuple objects so pushing the one TLV instance 
+        we reuse is pointless.  We could use two approaches here to handle this
+        nuisance.  First we could just create a new instance only for those TLV
+        tuples that nest others and hence need to be pushed onto the stack.  Or
+        we can use multiple primitive stacks based on an int to store the set
+        of values contained in the tuple.  The second approach leads to greater
+        complexity while the first leads to some overhead in extra instantiation
+        time and memory which is negligable really.  Which approach is best 
+        depends on the number of members in the tuple or in otherwords the 
+        number of primitive int stacks.
+      </p>
+      
+      <p>
+        We wrote a little test to figure out when one approach out performs the
+        other in the ObjectVersePrimitiveTest unit test case.  From tinkering
+        with the parameters of the test case we found the use of primitives to
+        out perform tuple object instantiation when the number of member stacks
+        is less than or equal to 2.  If the number of stacks used is 3 or more
+        then instantiating an TLV object and pushing it onto one stack is best.
+        In our case we have 3 peices of information that need to be pushed and
+        poped together so from this data the choice is clear.  We clone the TLV
+        tuple or instantiate a new one for constructed TLVs that are pushed onto
+        a single stack.  This is faster and removes the need to manage multiple
+        stacks making the code less complex.
+      </p>
+      </subsection>
+    </section>
+    
   </body>
 </document>

Mime
View raw message