directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From akaras...@apache.org
Subject svn commit: rev 9483 - in incubator/directory/snickers/branches/refactoring/ber/src: java/org/apache/snickers/asn java/org/apache/snickers/ber test/org/apache/snickers/ber
Date Mon, 15 Mar 2004 05:51:11 GMT
Author: akarasulu
Date: Sun Mar 14 21:51:10 2004
New Revision: 9483

Added:
   incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/Length.java
   incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/LengthDecoder.java
   incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/Tag.java
Modified:
   incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/asn/TLV.java
   incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/asn/TLVParsingUtility.java
   incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/BERDecoder.java
   incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/BERUtils.java
   incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/TagDecoder.java
   incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/Tuple.java
   incubator/directory/snickers/branches/refactoring/ber/src/test/org/apache/snickers/ber/BERUtilsTest.java
   incubator/directory/snickers/branches/refactoring/ber/src/test/org/apache/snickers/ber/TupleTest.java
Log:
started major refactoring

Modified: incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/asn/TLV.java
==============================================================================
--- incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/asn/TLV.java
(original)
+++ incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/asn/TLV.java
Sun Mar 14 21:51:10 2004
@@ -53,7 +53,7 @@
 import java.util.Collection;
 
 import org.apache.commons.codec.binary.Binary;
-import org.apache.snickers.ber.BERUtils;
+import org.apache.snickers.ber.Tag;
 import org.apache.snickers.ber.TypeClass;
 
 /**
@@ -208,7 +208,7 @@
      * @return the type class
      */
     public TypeClass getTypeClass() {
-        return BERUtils.getTypeClass( (byte) tag );
+        return TypeClass.getTypeClass( (byte) tag );
     }
 
     /**
@@ -231,7 +231,7 @@
     * @return true if the value is a primative, else false.
     */
    public boolean isPrimative() {
-       return BERUtils.isPrimitive( tag );
+       return Tag.isPrimitive( tag );
    }
    
    /**

Modified: incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/asn/TLVParsingUtility.java
==============================================================================
--- incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/asn/TLVParsingUtility.java
(original)
+++ incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/asn/TLVParsingUtility.java
Sun Mar 14 21:51:10 2004
@@ -102,8 +102,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((byte)tag);
+            boolean primative =  Tag.isPrimitive(tag);
+            TypeClass tc = TypeClass.getTypeClass((byte)tag);
             
             System.out.println( strIndent + ">>>>>>>>>>>>>>
TLV <<<<<<<<<<<<<" );
             System.out.println( strIndent + "Tag:  " + toBits(tag) );

Modified: incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/BERDecoder.java
==============================================================================
--- incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/BERDecoder.java
(original)
+++ incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/BERDecoder.java
Sun Mar 14 21:51:10 2004
@@ -185,12 +185,12 @@
             
             if ( tagBuffer.size() == 1 )
             {
-                int id = BERUtils.SHORT_TAG_MASK & octet ;
-                tlv.isPrimitive = BERUtils.isPrimitive( octet ) ; 
-                tlv.typeClass = BERUtils.getTypeClass( octet ) ;
+                int id = Tag.SHORT_MASK & octet ;
+                tlv.isPrimitive = Tag.isPrimitive( octet ) ; 
+                tlv.typeClass = TypeClass.getTypeClass( octet ) ;
                 
                 // continue to collect more octets if this is the long Tag form
-                if ( id == BERUtils.SHORT_TAG_MASK )
+                if ( id == Tag.SHORT_MASK )
                 {
                     continue ;
                 }
@@ -213,7 +213,7 @@
              */ 
             if ( ( octet & Binary.BIT_7 ) == 0 )
             {
-                tlv.id = BERUtils.getTagId( tagBuffer ) ;
+                tlv.id = Tag.getTagId( tagBuffer ) ;
                 fireTagDecoded() ;
                 state = state.getNext( tlv.isPrimitive ) ;
                 
@@ -240,14 +240,14 @@
             
             if ( lengthBuffer.size() == 1 )
             {
-                lengthOfLength = octet & BERUtils.LONG_TAG_MASK ;
+                lengthOfLength = octet & Tag.LONG_MASK ;
                 
                 // handle the short form of the length here
                 if ( ( octet & Binary.BIT_7 ) == 0 ) 
                 {
                     lengthOfLength = 0 ;
                     tlv.length = octet ;
-                    tlv.valueIndex = Tuple.UNDEFINED ;
+                    tlv.valueIndex = Length.UNDEFINED ;
 
                     if ( tlv.isPrimitive )
                     {
@@ -276,10 +276,10 @@
                 // the indefinate form of the length
                 else if ( lengthOfLength == 0 )
                 {
-                    lengthOfLength = Tuple.INDEFINATE ;
-                    tlv.index = Tuple.INDEFINATE ;
-                    tlv.length = Tuple.INDEFINATE ;
-                    tlv.valueIndex = Tuple.UNDEFINED ;
+                    lengthOfLength = Length.INDEFINATE ;
+                    tlv.index = Length.INDEFINATE ;
+                    tlv.length = Length.INDEFINATE ;
+                    tlv.valueIndex = Length.UNDEFINED ;
                     fireLengthDecoded() ;
                     tlvStack.push( tlv.clone() ) ;
                     tlv.clear() ;
@@ -298,8 +298,8 @@
             if ( lengthBuffer.size() == lengthOfLength + 1 )
             {
                 lengthOfLength = 0 ;
-                tlv.length = BERUtils.getLength( lengthBuffer ) ;
-                tlv.valueIndex = Tuple.UNDEFINED ;
+                tlv.length = Length.getLength( lengthBuffer ) ;
+                tlv.valueIndex = Length.UNDEFINED ;
                 
                 if ( tlv.isPrimitive )
                 {
@@ -334,8 +334,8 @@
     private void decodeValue( ByteBuffer buf ) throws DecoderException
     {
         byte[] value = ( byte [] ) tlv.value ;
-        int offset = Tuple.UNDEFINED ;
-        int needToRead = Tuple.UNDEFINED ;
+        int offset = Length.UNDEFINED ;
+        int needToRead = Length.UNDEFINED ;
 
         if ( ! tlv.isPrimitive )
         {
@@ -362,7 +362,7 @@
         /*
          * setup to start decoding the value
          */
-        if ( tlv.valueIndex == Tuple.UNDEFINED )
+        if ( tlv.valueIndex == Length.UNDEFINED )
         {
             needToRead = tlv.length ;
             offset = 0 ;
@@ -395,7 +395,7 @@
          */
         else
         {
-            if ( tlv.valueIndex == Tuple.UNDEFINED )
+            if ( tlv.valueIndex == Length.UNDEFINED )
             {
                 tlv.valueIndex = 0 ;
             }
@@ -494,7 +494,7 @@
                 
             t.index += increment ;
                 
-            if ( t.valueIndex == Tuple.UNDEFINED )
+            if ( t.valueIndex == Length.UNDEFINED )
             {
                 t.valueIndex = 0 ;
             }
@@ -554,7 +554,7 @@
             }
 
             Tuple top = ( Tuple ) tlvStack.peek() ;
-            if ( top.length != Tuple.INDEFINATE )
+            if ( top.length != Length.INDEFINATE )
             {
                 IllegalStateException e = new IllegalStateException(
                          msg + " but TLV on top has a definate length" ) ;

Modified: incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/BERUtils.java
==============================================================================
--- incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/BERUtils.java
(original)
+++ incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/BERUtils.java
Sun Mar 14 21:51:10 2004
@@ -17,11 +17,6 @@
 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 ;
-
-
 /**
  * Basic Encoding Rule (BER) utility functions.
  *
@@ -31,212 +26,4 @@
  */
 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 ) ;
-    }
-
-
-    /**
-     * 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 ;
-    }
-
-    
-    /**
-     * Decodes the length of a value for a tlv using the Length field bytes.
-     * 
-     * @param octets the length field bytes in the TLV
-     * @return the length of the TLV
-     * @throws DecoderException if the precision cannot hold the number
-     */
-    public static int getLength( 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( "Length number is too large." ) ;
-        }
-        
-        // if we are using the short form then just return the first octet
-        if ( ( octets.get( 0 ) & Binary.BIT_7 ) == 0 )
-        {
-            return octets.get( 0 ) ;
-        }
-        
-        // clear the id now
-        int length = 0 ;
-
-        // calculate tag value w/ long tag format
-        for( int ii = 1 ; ii < octets.size(); ii++ )
-        {    
-            int shift = ( ii - 1 ) * 8 ;
-            length |=  ( 0x00ff & ( int ) octets.get( ii ) ) << shift ;
-        }
-        
-        return length ;
-    }
 }

Added: incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/Length.java
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/Length.java
Sun Mar 14 21:51:10 2004
@@ -0,0 +1,193 @@
+/*
+ *   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.collections.primitives.ArrayByteList ;
+
+
+/**
+ * The length component of a BER TLV Tuple.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class Length
+{
+    /** used to mark length as indefinate */
+    public static final int INDEFINATE = -2 ;
+    /** used to mark length as undefined */ 
+    public static final int UNDEFINED = -1 ;
+    /** the end long form terminate bit flag mask */
+    public static final int END_MASK = 0x80 ;
+
+    /** the value for this tlv length */
+    private int value = UNDEFINED ;
+    /** the number of octets needed to complete this length component */
+    private int numOctets = UNDEFINED ;
+    /** whether or not this length has been fixated */
+    private boolean isFixated = false ;
+    /** a byte buffer used to collect the arriving length octets */ 
+    private final ArrayByteList buf = new ArrayByteList( 10 ) ;
+
+    
+    
+    /**
+     * Checks to see if the length has been fixated.
+     * 
+     * @return true if it is fixated, false if not
+     */
+    public boolean isFixated()
+    {
+        return isFixated ;
+    }
+    
+    
+    /**
+     * Clears this tag's data of all bytes and values calculated so all is as it
+     * was when this instance was created.
+     */
+    void clear()
+    {
+        isFixated = false ;
+        value = 0 ;
+        numOctets = 1 ;
+        buf.clear() ;
+    }
+    
+    
+    /**
+     * Fixates the data within this Tag calculating all the derived 
+     * properties from the existing set of octets.  While fixated octets
+     * cannot be added.
+     * 
+     * @throws DecoderException if this Tag is invalid
+     */
+    void fixate() throws DecoderException
+    {
+        value = getLength( buf ) ;
+        isFixated = true ;
+    }
+    
+    
+    /**
+     * Adds an octet to this Length component and as a side effect fixates the
+     * Length component if all the required length data has arrived.
+     * 
+     * @param octet the 8 bit byte to add
+     */
+    void add( byte octet ) throws DecoderException
+    {
+        if ( isFixated )
+        {  
+            throw new IllegalStateException( "data added to fixated length" ) ;
+        }
+        
+        buf.add( octet ) ;
+        
+        if ( buf.size() == 1 )
+        {
+            // if its the long form
+            if ( END_MASK == ( octet & END_MASK ) && ( octet & 0x7F ) >
0 )
+            {
+                // capture number of octets we need to compute length
+                numOctets = octet & 0x7F ;
+            }
+            else 
+            {    
+                fixate() ;
+            }
+        }
+        
+        /*
+         * if we have collected all the octets needed for computing the long
+         * form length so we need to calculate the length and just fixate
+         */
+        else if ( buf.size() >= numOctets + 1 )
+        {
+            fixate() ;
+        }
+    }
+    
+    
+    /**
+     * Gets a copy of the octets composing this Length component.
+     * 
+     * @return the octets representing this Length component
+     */
+    public byte[] getOctets()
+    {
+        return buf.toArray() ;
+    }
+    
+    
+    /**
+     * Gets the number of octets currently in this Length component.
+     * 
+     * @return the number of octets currently within this Length component
+     */
+    public int size()
+    {
+        return buf.size() ;
+    }
+
+    
+    /**
+     * Decodes the length of a value for a tlv using the Length field bytes.
+     * 
+     * @param octets the length field bytes in the TLV
+     * @return the length of the TLV
+     * @throws DecoderException if the precision cannot hold the number
+     */
+    public static int getLength( 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( "Length number is too large." ) ;
+        }
+        
+        // if we are using the short form then just return the first octet
+        if ( ( octets.get( 0 ) & END_MASK ) == 0 )
+        {
+            return octets.get( 0 ) ;
+        }
+        // using the indefinate form
+        else if ( ( octets.get( 0 ) & 0x7F ) == 0 )
+        {
+            return INDEFINATE ;
+        }
+        
+        // using the long form so we calculate the length from all octets
+        int length = 0 ;
+    
+        // calculate tag value w/ long tag format
+        for( int ii = 1 ; ii < octets.size(); ii++ )
+        {    
+            int shift = ( ii - 1 ) * 8 ;
+            length |=  ( 0xFF & ( int ) octets.get( ii ) ) << shift ;
+        }
+        
+        return length ;
+    }
+}

Added: incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/LengthDecoder.java
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/LengthDecoder.java
Sun Mar 14 21:51:10 2004
@@ -0,0 +1,62 @@
+/*
+ *   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.DecoderException ;
+import org.apache.commons.codec.stateful.AbstractStatefulDecoder ;
+
+
+/**
+ * A BER TLV Length component decoder.  This decoder delivers a Length instance
+ * to its callback.  For efficiency the same Length object is reused.  Callback
+ * implementations should not copy the handle to the Length object delivered but
+ * should copy the data if they need it over the long term.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev: 9470 $
+ */
+public class LengthDecoder extends AbstractStatefulDecoder
+{
+    /** the Length component decoded from a BER TLV Tuple */
+    private final Length length = new Length() ;
+    
+    
+    /* (non-Javadoc)
+     * @see org.apache.commons.codec.stateful.StatefulDecoder#decode(
+     * java.lang.Object)
+     */
+    public void decode( Object encoded ) throws DecoderException
+    {
+        ByteBuffer buf = ( ByteBuffer ) encoded ;
+        
+        while ( buf.hasRemaining() )
+        {
+            byte octet = buf.get() ;
+            length.add( octet ) ;
+            
+            if ( length.isFixated() )
+            {
+                decodeOccurred( length ) ;
+                length.clear() ;
+            }
+        }
+    }
+}

Added: incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/Tag.java
==============================================================================
--- (empty file)
+++ incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/Tag.java
Sun Mar 14 21:51:10 2004
@@ -0,0 +1,296 @@
+/*
+ *   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.collections.primitives.ArrayByteList ;
+
+
+/**
+ * The Tag component of a BER TLV Tuple.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">
+ * Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class Tag
+{
+    /** tag mask for the primitive/constructed bit - 0010 0000 - 0x20 */
+    private static final int PRIMITIVE_MASK = 0x20;
+    /** tag mask for the short tag format - 0001 1111 - 0x1F */
+    public static final int SHORT_MASK = 0x1F ;
+    /** tag mask for the long tag format - 0111 1111 - 0x7F */
+    public static final int LONG_MASK = 0x7F ; 
+
+    /** tag id */
+    private int id = 0 ;
+    /** whether or not this tag represents a primitive type */
+    private boolean isPrimitive = true ;
+    /** whether or not this tag has been fixated */
+    private boolean isFixated = false ;
+    /** the type class of this tag */
+    private TypeClass typeClass = TypeClass.APPLICATION ;
+    /** a byte buffer used to collect the arriving tag octets */ 
+    private final ArrayByteList buf = new ArrayByteList( 10 ) ;
+
+
+    /**
+     * Clears this tag's data of all bytes and values calculated so all is as it
+     * was when this instance was created.
+     */
+    void clear()
+    {
+        id = 0 ;
+        isFixated = false ;
+        isPrimitive = true ;
+        typeClass = TypeClass.APPLICATION ;
+        buf.clear() ;
+    }
+    
+    
+    /**
+     * Fixates the data within this Tag calculating all the derived 
+     * properties from the existing set of octets.  While fixated octets
+     * cannot be added.
+     * 
+     * @throws DecoderException if this Tag is invalid
+     */
+    void fixate() throws DecoderException
+    {
+        isFixated = true ;
+        id = Tag.getTagId( buf ) ;
+        isPrimitive = isPrimitive( buf.get( 0 ) ) ;
+        typeClass = TypeClass.getTypeClass( buf.get( 0 ) ) ;
+    }
+    
+    
+    /**
+     * Adds an octet to this Tag and as a size effect may fixate the Tag if
+     * all the expected data has arrived.
+     * 
+     * @param octet the 8 bit byte to add
+     */
+    void add( byte octet ) throws DecoderException
+    {
+        if ( isFixated )
+        {  
+            throw new IllegalStateException( "data added to fixated tag" ) ;
+        }
+        
+        buf.add( octet ) ;
+        
+        if ( buf.size() == 1 )
+        {
+            // its the short form so we just fixate
+            if ( ( 0x1F & octet ) != 0x1F )
+            {
+                fixate() ;
+            }
+        }
+        
+        /*
+         * From here on we're dealing with the long form of the tag.  The
+         * terminating octet for the long form uses a 0 for the most 
+         * significant bit to flag the end of the train of octets for the 
+         * tag id.
+         */ 
+        else if ( ( octet & 0x80 ) == 0 )
+        {
+            fixate() ;
+        }
+    }
+    
+    
+    /**
+     * Gets a copy of the octets composing this Tag.
+     * 
+     * @return the octets representing this Tag
+     */
+    public byte[] getOctets()
+    {
+        return buf.toArray() ;
+    }
+    
+    
+    /**
+     * Gets the number of octets in this Tag.
+     * 
+     * @return the number of octets within this Tag
+     */
+    public int size()
+    {
+        return buf.size() ;
+    }
+
+    
+    /**
+     * Gets the id.
+     * 
+     * @return the id
+     */
+    public int getId()
+    {
+        return id ;
+    }
+    
+    
+    /**
+     * Checks to see if the tag represented by this Tag is primitive or 
+     * constructed.
+     * 
+     * @return true if it is primitive, false if it is constructed
+     */
+    public boolean isPrimitive()
+    {
+        return isPrimitive ;
+    }
+    
+    
+    /**
+     * Checks to see if the tag has been fixated.
+     * 
+     * @return true if it is fixated, false if not
+     */
+    public boolean isFixated()
+    {
+        return isFixated ;
+    }
+    
+    
+    /**
+     * Gets the type class for this Tag.
+     * 
+     * @return the typeClass for this Tag
+     */
+    public TypeClass getTypeClass()
+    {
+        return typeClass ;
+    }
+
+
+    /**
+     * 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_MASK ;
+        
+        // if bits are not all 1's then return the value which is less than 31
+        if ( id != SHORT_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 ;
+            id |= ( octets[ii] & LONG_MASK ) << shift ;
+        }
+        
+        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_MASK ;
+        
+        // if bits are not all 1's then return the value which is less than 31
+        if ( id != SHORT_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 ;
+            id |= ( octets.get( ii ) & LONG_MASK ) << shift ;
+        }
+        
+        return id ;
+    }
+
+
+    /**
+     * Checks to see if the tag is a primitive.
+     * 
+     * @param octet the first octet of the tag
+     * @return true if this tag is of the simple type, false if constructed
+     */
+    public final static boolean isPrimitive( int octet )
+    {
+        return ( octet & PRIMITIVE_MASK ) == 0 ;
+    }
+
+
+    /**
+     * Checks to see if the tag is constructed.
+     * 
+     * @param octet the first octet of the tag
+     * @return true if constructed, false if primitive
+     */
+    public final static boolean isConstructed( int octet )
+    {
+        return ( octet & PRIMITIVE_MASK ) == PRIMITIVE_MASK ;
+    }
+}

Modified: incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/TagDecoder.java
==============================================================================
--- incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/TagDecoder.java
(original)
+++ incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/TagDecoder.java
Sun Mar 14 21:51:10 2004
@@ -17,47 +17,46 @@
 package org.apache.snickers.ber ;
 
 
+import java.nio.ByteBuffer ;
+
 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.AbstractStatefulDecoder ;
 
 
 /**
- * A BER Tag decoder.
+ * A BER TLV Tag component decoder.  This decoder delivers a Tag instance
+ * to its callback.  For efficiency the same Tag object is reused.  Callback
+ * implementations should not copy the handle to the Tag object delivered but
+ * should copy the data if they need it over the long term.
+ *
  *
  * @author <a href="mailto:directory-dev@incubator.apache.org">
  * Apache Directory Project</a>
  * @version $Rev$
  */
-public class TagDecoder implements StatefulDecoder
+public class TagDecoder extends AbstractStatefulDecoder
 {
+    private final Tag tag = new Tag() ;
     
-
     
     /* (non-Javadoc)
      * @see org.apache.commons.codec.stateful.StatefulDecoder#decode(
      * java.lang.Object)
      */
-    public void decode( Object arg0 ) throws DecoderException
-    {
-    }
-
-    
-    /* (non-Javadoc)
-     * @see org.apache.commons.codec.stateful.StatefulDecoder#setCallback(
-     * org.apache.commons.codec.stateful.DecoderCallback)
-     */
-    public void setCallback( DecoderCallback cb )
-    {
-    }
-
-    
-    /* (non-Javadoc)
-     * @see org.apache.commons.codec.stateful.StatefulDecoder#setDecoderMonitor(
-     * org.apache.commons.codec.stateful.DecoderMonitor)
-     */
-    public void setDecoderMonitor( DecoderMonitor monitor )
+    public void decode( Object encoded ) throws DecoderException
     {
+        ByteBuffer buf = ( ByteBuffer ) encoded ;
+        
+        while ( buf.hasRemaining() )
+        {
+            byte octet = buf.get() ;
+            tag.add( octet ) ;
+        
+            if ( tag.isFixated() )
+            {
+                decodeOccurred( tag ) ;
+                tag.clear() ;
+            }
+        }
     }
 }

Modified: incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/Tuple.java
==============================================================================
--- incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/Tuple.java
(original)
+++ incubator/directory/snickers/branches/refactoring/ber/src/java/org/apache/snickers/ber/Tuple.java
Sun Mar 14 21:51:10 2004
@@ -33,11 +33,6 @@
  */
 public class Tuple
 {
-    /** used to mark lengths and indices and indefinate */
-    public static final int INDEFINATE = -2 ;
-    /** used to mark indices as undefined */ 
-    public static final int UNDEFINED = -1 ;
-
     /** precalculated left shift of 1 by 7 places */
     static final int BIT_6 = 1 << 7 ;
     /** precalculated left shift of 1 by 8 places */
@@ -65,9 +60,9 @@
     Object value = ArrayUtils.EMPTY_BYTE_ARRAY ;
     
     /** tlv byte index */
-    int index = Tuple.UNDEFINED ;
+    int index = Length.UNDEFINED ;
     /** tlv value index for how far into the value we have read */
-    int valueIndex = Tuple.UNDEFINED ;
+    int valueIndex = Length.UNDEFINED ;
     
     
     // ------------------------------------------------------------------------
@@ -161,7 +156,7 @@
         this.id = id ;
         this.isPrimitive = false ;
         value = ArrayUtils.EMPTY_BYTE_ARRAY ;
-        length = Tuple.INDEFINATE ;
+        length = Length.INDEFINATE ;
         
         if ( typeClass != null )
         {
@@ -221,7 +216,7 @@
      */
     public boolean isIndefinate()
     {
-        return length == Tuple.INDEFINATE ;
+        return length == Length.INDEFINATE ;
     }
     
 
@@ -292,7 +287,7 @@
      */
     public int size()
     {
-        if ( this.length == Tuple.INDEFINATE )
+        if ( this.length == Length.INDEFINATE )
         {    
             return getTagLength() + getLengthLength() ;
         }
@@ -316,10 +311,10 @@
         this.id = 0 ;
         this.index = 0 ;
         this.isPrimitive = true ;
-        this.length = Tuple.UNDEFINED ;
+        this.length = Length.UNDEFINED ;
         this.typeClass = TypeClass.APPLICATION ;
         this.value = ArrayUtils.EMPTY_BYTE_ARRAY ;
-        this.valueIndex = Tuple.UNDEFINED ;
+        this.valueIndex = Length.UNDEFINED ;
     }
 
     
@@ -458,7 +453,7 @@
         }
         else
         {
-            octets[0] |= BERUtils.SHORT_TAG_MASK ;
+            octets[0] |= Tag.SHORT_MASK ;
         }
         
         if ( tagLength >= 2 )
@@ -558,7 +553,7 @@
      */
     void setLength( byte[] octets, int offset, int lengthBytes )
     {
-        if ( length == Tuple.INDEFINATE )
+        if ( length == Length.INDEFINATE )
         {
             octets[offset] |= BIT_6 ;
             return ;
@@ -658,7 +653,7 @@
      */
     public int getLengthLength()
     {
-        if ( length == Tuple.INDEFINATE )
+        if ( length == Length.INDEFINATE )
         {
             return 1 ;
         }

Modified: incubator/directory/snickers/branches/refactoring/ber/src/test/org/apache/snickers/ber/BERUtilsTest.java
==============================================================================
--- incubator/directory/snickers/branches/refactoring/ber/src/test/org/apache/snickers/ber/BERUtilsTest.java
(original)
+++ incubator/directory/snickers/branches/refactoring/ber/src/test/org/apache/snickers/ber/BERUtilsTest.java
Sun Mar 14 21:51:10 2004
@@ -66,24 +66,24 @@
     
     public void getTypeClass()
     {
-        assertEquals( TypeClass.UNIVERSAL, BERUtils.getTypeClass( (byte) 0 ) ) ;
+        assertEquals( TypeClass.UNIVERSAL, Tag.getTypeClass( (byte) 0 ) ) ;
     }
     
     public void testIsPrimitive() throws Exception
     {
         byte octet = Binary.BIT_5 ;
         
-        assertFalse( BERUtils.isPrimitive( octet ) ) ;
-        assertFalse( BERUtils.isPrimitive( Binary.BIT_5 ) ) ;
+        assertFalse( Tag.isPrimitive( octet ) ) ;
+        assertFalse( Tag.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 ) ) ;
+        assertTrue( Tag.isPrimitive( 0 ) ) ;
+        assertTrue( Tag.isPrimitive( Binary.BIT_0 ) ) ;
+        assertTrue( Tag.isPrimitive( Binary.BIT_1 ) ) ;
+        assertTrue( Tag.isPrimitive( Binary.BIT_2 ) ) ;
+        assertTrue( Tag.isPrimitive( Binary.BIT_3 ) ) ;
+        assertTrue( Tag.isPrimitive( Binary.BIT_4 ) ) ;
+        assertTrue( Tag.isPrimitive( Binary.BIT_6 ) ) ;
+        assertTrue( Tag.isPrimitive( Binary.BIT_7 ) ) ;
     }
 
 
@@ -91,17 +91,17 @@
     {
         byte octet = Binary.BIT_5 ;
         
-        assertTrue( BERUtils.isConstructed( octet ) ) ;
-        assertTrue( BERUtils.isConstructed( Binary.BIT_5 ) ) ;
+        assertTrue( Tag.isConstructed( octet ) ) ;
+        assertTrue( Tag.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 ) ) ;
+        assertFalse( Tag.isConstructed( 0 ) ) ;
+        assertFalse( Tag.isConstructed( Binary.BIT_0 ) ) ;
+        assertFalse( Tag.isConstructed( Binary.BIT_1 ) ) ;
+        assertFalse( Tag.isConstructed( Binary.BIT_2 ) ) ;
+        assertFalse( Tag.isConstructed( Binary.BIT_3 ) ) ;
+        assertFalse( Tag.isConstructed( Binary.BIT_4 ) ) ;
+        assertFalse( Tag.isConstructed( Binary.BIT_6 ) ) ;
+        assertFalse( Tag.isConstructed( Binary.BIT_7 ) ) ;
     }
     
     
@@ -115,11 +115,11 @@
             
             if ( ii < 31 ) 
             {
-                assertEquals( BERUtils.getTagId( octets ), ii ) ;
+                assertEquals( Tag.getTagId( octets ), ii ) ;
             }
             else
             {
-                assertTrue( BERUtils.getTagId( octets ) != ii ) ;
+                assertTrue( Tag.getTagId( octets ) != ii ) ;
             }
         }
         
@@ -133,11 +133,11 @@
             
             if ( ii < 128 ) 
             {
-                assertEquals( BERUtils.getTagId( octets ), ii ) ;
+                assertEquals( Tag.getTagId( octets ), ii ) ;
             }
             else
             {
-                assertTrue( BERUtils.getTagId( octets ) != ii ) ;
+                assertTrue( Tag.getTagId( octets ) != ii ) ;
             }
         }
         
@@ -148,16 +148,16 @@
         
         for ( int ii = 128 ; ii < 20000; ii++ )
         {
-            octets[1] = ( byte ) ( ii & BERUtils.LONG_TAG_MASK ) ;
-            octets[2] = ( byte ) ( ( ii >> 7 ) & BERUtils.LONG_TAG_MASK ) ;
+            octets[1] = ( byte ) ( ii & Tag.LONG_MASK ) ;
+            octets[2] = ( byte ) ( ( ii >> 7 ) & Tag.LONG_MASK ) ;
             
             if ( ii < 16384 ) 
             {
-                assertEquals( BERUtils.getTagId( octets ), ii ) ;
+                assertEquals( Tag.getTagId( octets ), ii ) ;
             }
             else
             {
-                assertTrue( BERUtils.getTagId( octets ) != ii ) ;
+                assertTrue( Tag.getTagId( octets ) != ii ) ;
             }
         }
 
@@ -171,23 +171,23 @@
         
         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 ) ;
+            octets[1] = ( byte ) ( ii & Tag.LONG_MASK ) ;
+            octets[2] = ( byte ) ( ( ii >> 7 ) & Tag.LONG_MASK ) ;
+            octets[3] = ( byte ) ( ( ii >> 14 ) & Tag.LONG_MASK ) ;
             
             if ( ii < 2097152 ) 
             {
-                assertEquals( BERUtils.getTagId( octets ), ii ) ;
+                assertEquals( Tag.getTagId( octets ), ii ) ;
             }
             else
             {
-                assertTrue( BERUtils.getTagId( octets ) != ii ) ;
+                assertTrue( Tag.getTagId( octets ) != ii ) ;
             }
         }
         
         ArrayByteList list = new ArrayByteList() ;
         list.add( (byte)1) ;
-        assertEquals( 1, BERUtils.getTagId( list ) ) ;
+        assertEquals( 1, Tag.getTagId( list ) ) ;
 
         list.add( (byte)1) ;
         list.add( (byte)1) ;
@@ -199,7 +199,7 @@
         list.add( (byte)1) ;
         try
         {
-            BERUtils.getTagId( list ) ;
+            Tag.getTagId( list ) ;
             fail( "should fail before getting here" ) ;
         }
         catch ( Throwable t )
@@ -210,7 +210,7 @@
     
         try
         {
-            BERUtils.getTagId( new byte[56] ) ;
+            Tag.getTagId( new byte[56] ) ;
             fail( "should fail before getting here" ) ;
         }
         catch ( Throwable t )
@@ -234,7 +234,7 @@
         
         try
         {
-            BERUtils.getLength( list ) ;
+            Length.getLength( list ) ;
             fail( "should fail before we get here" ) ;
         }
         catch ( Throwable t )
@@ -245,6 +245,6 @@
         
         list.clear() ;
         list.add(( byte ) 0x7 ) ;
-        assertEquals( 7, BERUtils.getLength( list ) ) ;
+        assertEquals( 7, Length.getLength( list ) ) ;
     }
 }

Modified: incubator/directory/snickers/branches/refactoring/ber/src/test/org/apache/snickers/ber/TupleTest.java
==============================================================================
--- incubator/directory/snickers/branches/refactoring/ber/src/test/org/apache/snickers/ber/TupleTest.java
(original)
+++ incubator/directory/snickers/branches/refactoring/ber/src/test/org/apache/snickers/ber/TupleTest.java
Sun Mar 14 21:51:10 2004
@@ -200,14 +200,14 @@
         assertEquals( 2, t.getId() ) ;
         assertEquals( TypeClass.PRIVATE, t.getTypeClass() ) ;
         assertEquals( false, t.isPrimitive() ) ;
-        assertEquals( Tuple.INDEFINATE, t.getLength() ) ;
+        assertEquals( Length.INDEFINATE, t.getLength() ) ;
         assertEquals( ArrayUtils.EMPTY_BYTE_ARRAY, t.getValue() ) ;
 
         t = new Tuple( 2, (TypeClass) null ) ;
         assertEquals( 2, t.getId() ) ;
         assertEquals( TypeClass.APPLICATION, t.getTypeClass() ) ;
         assertEquals( false, t.isPrimitive() ) ;
-        assertEquals( Tuple.INDEFINATE, t.getLength() ) ;
+        assertEquals( Length.INDEFINATE, t.getLength() ) ;
         assertEquals( ArrayUtils.EMPTY_BYTE_ARRAY, t.getValue() ) ;
     }
 
@@ -252,7 +252,7 @@
     {
         Tuple t = new Tuple() ;
         assertFalse( t.isIndefinate() ) ;
-        t.length = Tuple.INDEFINATE ;
+        t.length = Length.INDEFINATE ;
         assertTrue( t.isIndefinate() ) ;
     }
     
@@ -321,7 +321,7 @@
         t.length = 12 ;
         assertEquals( 12, t.length ) ;
         t.clear() ;
-        assertEquals( Tuple.UNDEFINED, t.length ) ;
+        assertEquals( Length.UNDEFINED, t.length ) ;
 
         t.index = 12 ;
         assertEquals( 12, t.index ) ;
@@ -346,7 +346,7 @@
         t.valueIndex = 12 ;
         assertEquals( 12, t.valueIndex ) ;
         t.clear() ;
-        assertEquals( Tuple.UNDEFINED, t.valueIndex ) ;
+        assertEquals( Length.UNDEFINED, t.valueIndex ) ;
 
     }
 

Mime
View raw message