costin      01/02/19 19:12:14

  Added:       src/share/org/apache/tomcat/util/buf Ascii.java Base64.java
                        ByteChunk.java CharChunk.java DateTool.java
                        HexUtils.java MessageBytes.java
  Log:
  Moving files from tomcat.util in sub-packages.
  
  This avoids name polution and makes easy to understand the dependencies.
  
  Revision  Changes    Path
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/util/buf/Ascii.java
  
  Index: Ascii.java
  ===================================================================
  /*
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, 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 acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", 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 [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * 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 (INCLUDING, 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/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  package org.apache.tomcat.util.buf;
  
  /**
   * This class implements some basic ASCII character handling functions.
   *
   * @author [EMAIL PROTECTED]
   * @author James Todd [[EMAIL PROTECTED]]
   */
  public final class Ascii {
      /*
       * Character translation tables.
       */
  
      private static final byte[] toUpper = new byte[256];
      private static final byte[] toLower = new byte[256];
  
      /*
       * Character type tables.
       */
  
      private static final boolean[] isAlpha = new boolean[256];
      private static final boolean[] isUpper = new boolean[256];
      private static final boolean[] isLower = new boolean[256];
      private static final boolean[] isWhite = new boolean[256];
      private static final boolean[] isDigit = new boolean[256];
  
      /*
       * Initialize character translation and type tables.
       */
  
      static {
        for (int i = 0; i < 256; i++) {
            toUpper[i] = (byte)i;
            toLower[i] = (byte)i;
        }
  
        for (int lc = 'a'; lc <= 'z'; lc++) {
            int uc = lc + 'A' - 'a';
  
            toUpper[lc] = (byte)uc;
            toLower[uc] = (byte)lc;
            isAlpha[lc] = true;
            isAlpha[uc] = true;
            isLower[lc] = true;
            isUpper[uc] = true;
        }
  
        isWhite[ ' '] = true;
        isWhite['\t'] = true;
        isWhite['\r'] = true;
        isWhite['\n'] = true;
        isWhite['\f'] = true;
        isWhite['\b'] = true;
  
        for (int d = '0'; d <= '9'; d++) {
            isDigit[d] = true;
        }
      }
  
      /**
       * Returns the upper case equivalent of the specified ASCII character.
       */
  
      public static int toUpper(int c) {
        return toUpper[c & 0xff] & 0xff;
      }
  
      /**
       * Returns the lower case equivalent of the specified ASCII character.
       */
  
      public static int toLower(int c) {
        return toLower[c & 0xff] & 0xff;
      }
  
      /**
       * Returns true if the specified ASCII character is upper or lower case.
       */
  
      public static boolean isAlpha(int c) {
        return isAlpha[c & 0xff];
      }
  
      /**
       * Returns true if the specified ASCII character is upper case.
       */
  
      public static boolean isUpper(int c) {
        return isUpper[c & 0xff];
      }
  
      /**
       * Returns true if the specified ASCII character is lower case.
       */
  
      public static boolean isLower(int c) {
        return isLower[c & 0xff];
      }
  
      /**
       * Returns true if the specified ASCII character is white space.
       */
  
      public static boolean isWhite(int c) {
        return isWhite[c & 0xff];
      }
  
      /**
       * Returns true if the specified ASCII character is a digit.
       */
  
      public static boolean isDigit(int c) {
        return isDigit[c & 0xff];
      }
  
      /**
       * Parses an unsigned integer from the specified subarray of bytes.
       * @param b the bytes to parse
       * @param off the start offset of the bytes
       * @param len the length of the bytes
       * @exception NumberFormatException if the integer format was invalid
       */
      public static int parseInt(byte[] b, int off, int len)
        throws NumberFormatException
      {
          int c;
  
        if (b == null || len <= 0 || !isDigit(c = b[off++])) {
            throw new NumberFormatException();
        }
  
        int n = c - '0';
  
        while (--len > 0) {
            if (!isDigit(c = b[off++])) {
                throw new NumberFormatException();
            }
            n = n * 10 + c - '0';
        }
  
        return n;
      }
  
      public static int parseInt(char[] b, int off, int len)
        throws NumberFormatException
      {
          int c;
  
        if (b == null || len <= 0 || !isDigit(c = b[off++])) {
            throw new NumberFormatException();
        }
  
        int n = c - '0';
  
        while (--len > 0) {
            if (!isDigit(c = b[off++])) {
                throw new NumberFormatException();
            }
            n = n * 10 + c - '0';
        }
  
        return n;
      }
  
  }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/util/buf/Base64.java
  
  Index: Base64.java
  ===================================================================
  /*
   * $Header: 
/home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/buf/Base64.java,v 1.1 
2001/02/20 03:12:13 costin Exp $
   * $Revision: 1.1 $
   * $Date: 2001/02/20 03:12:13 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, 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 acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", 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 [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * 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 (INCLUDING, 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/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  
  package org.apache.tomcat.util.buf;
  
  
  /**
   * This class provides encode/decode for RFC 2045 Base64 as
   * defined by RFC 2045, N. Freed and N. Borenstein.
   * RFC 2045: Multipurpose Internet Mail Extensions (MIME)
   * Part One: Format of Internet Message Bodies. Reference
   * 1996 Available at: http://www.ietf.org/rfc/rfc2045.txt
   * This class is used by XML Schema binary format validation
   *
   * @author Jeffrey Rodriguez
   * @version $Revision: 1.1 $ $Date: 2001/02/20 03:12:13 $
   */
  
  public final class Base64 {
  
  
      static private final int  BASELENGTH         = 255;
      static private final int  LOOKUPLENGTH       = 63;
      static private final int  TWENTYFOURBITGROUP = 24;
      static private final int  EIGHTBIT           = 8;
      static private final int  SIXTEENBIT         = 16;
      static private final int  SIXBIT             = 6;
      static private final int  FOURBYTE           = 4;
  
  
      static private final byte PAD               = ( byte ) '=';
      static private byte [] base64Alphabet       = new byte[BASELENGTH];
      static private byte [] lookUpBase64Alphabet = new byte[LOOKUPLENGTH];
  
      static {
  
          for (int i = 0; i<BASELENGTH; i++ ) {
              base64Alphabet[i] = -1;
          }
          for ( int i = 'Z'; i >= 'A'; i-- ) {
              base64Alphabet[i] = (byte) (i-'A');
          }
          for ( int i = 'z'; i>= 'a'; i--) {
              base64Alphabet[i] = (byte) ( i-'a' + 26);
          }
  
          for ( int i = '9'; i >= '0'; i--) {
              base64Alphabet[i] = (byte) (i-'0' + 52);
          }
  
          base64Alphabet['+']  = 62;
          base64Alphabet['/']  = 63;
  
         for (int i = 0; i<=25; i++ )
              lookUpBase64Alphabet[i] = (byte) ('A'+i );
  
          for (int i = 26,  j = 0; i<=51; i++, j++ )
              lookUpBase64Alphabet[i] = (byte) ('a'+ j );
  
          for (int i = 52,  j = 0; i<=61; i++, j++ )
              lookUpBase64Alphabet[i] = (byte) ('0' + j );
  
      }
  
  
      static boolean isBase64( byte octect ) {
          //shall we ignore white space? JEFF??
          return(octect == PAD || base64Alphabet[octect] != -1 );
      }
  
  
      static boolean isArrayByteBase64( byte[] arrayOctect ) {
          int length = arrayOctect.length;
          if ( length == 0 )
              return false;
          for ( int i=0; i < length; i++ ) {
              if ( Base64.isBase64( arrayOctect[i] ) == false)
                  return false;
          }
          return true;
      }
  
      /**
       * Encodes hex octects into Base64
       *
       * @param binaryData Array containing binaryData
       * @return Encoded Base64 array
       */
      public static byte[] encode( byte[] binaryData ) {
          int      lengthDataBits    = binaryData.length*EIGHTBIT;
          int      fewerThan24bits   = lengthDataBits%TWENTYFOURBITGROUP;
          int      numberTriplets    = lengthDataBits/TWENTYFOURBITGROUP;
          byte     encodedData[]     = null;
  
  
          if ( fewerThan24bits != 0 ) //data not divisible by 24 bit
              encodedData = new byte[ (numberTriplets + 1 )*4  ];
          else // 16 or 8 bit
              encodedData = new byte[ numberTriplets*4 ];
  
          byte k=0, l=0, b1=0,b2=0,b3=0;
  
          int encodedIndex = 0;
          int dataIndex   = 0;
          int i           = 0;
          for ( i = 0; i<numberTriplets; i++ ) {
  
              dataIndex = i*3;
              b1 = binaryData[dataIndex];
              b2 = binaryData[dataIndex + 1];
              b3 = binaryData[dataIndex + 2];
  
              l  = (byte)(b2 & 0x0f);
              k  = (byte)(b1 & 0x03);
  
              encodedIndex = i*4;
              encodedData[encodedIndex]   = lookUpBase64Alphabet[ b1 >>2 ];
              encodedData[encodedIndex+1] = lookUpBase64Alphabet[(b2 >>4 ) |
  ( k<<4 )];
              encodedData[encodedIndex+2] = lookUpBase64Alphabet[ (l <<2 ) |
  ( b3>>6)];
              encodedData[encodedIndex+3] = lookUpBase64Alphabet[ b3 & 0x3f ];
          }
  
          // form integral number of 6-bit groups
          dataIndex    = i*3;
          encodedIndex = i*4;
          if (fewerThan24bits == EIGHTBIT ) {
              b1 = binaryData[dataIndex];
              k = (byte) ( b1 &0x03 );
              encodedData[encodedIndex]     = lookUpBase64Alphabet[ b1 >>2 ];
              encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ k<<4 ];
              encodedData[encodedIndex + 2] = PAD;
              encodedData[encodedIndex + 3] = PAD;
          } else if ( fewerThan24bits == SIXTEENBIT ) {
  
              b1 = binaryData[dataIndex];
              b2 = binaryData[dataIndex +1 ];
              l = ( byte ) ( b2 &0x0f );
              k = ( byte ) ( b1 &0x03 );
              encodedData[encodedIndex]     = lookUpBase64Alphabet[ b1 >>2 ];
              encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ (b2 >>4 )
  | ( k<<4 )];
              encodedData[encodedIndex + 2] = lookUpBase64Alphabet[ l<<2 ];
              encodedData[encodedIndex + 3] = PAD;
          }
          return encodedData;
      }
  
  
      /**
       * Decodes Base64 data into octects
       *
       * @param binaryData Byte array containing Base64 data
       * @return Array containind decoded data.
       */
      public byte[] decode( byte[] base64Data ) {
          int      numberQuadruple    = base64Data.length/FOURBYTE;
          byte     decodedData[]      = null;
          byte     b1=0,b2=0,b3=0, b4=0, marker0=0, marker1=0;
  
          // Throw away anything not in base64Data
          // Adjust size
  
          int encodedIndex = 0;
          int dataIndex    = 0;
          decodedData      = new byte[ numberQuadruple*3 + 1 ];
  
          for (int i = 0; i<numberQuadruple; i++ ) {
              dataIndex = i*4;
              marker0   = base64Data[dataIndex +2];
              marker1   = base64Data[dataIndex +3];
  
              b1 = base64Alphabet[base64Data[dataIndex]];
              b2 = base64Alphabet[base64Data[dataIndex +1]];
  
              if ( marker0 != PAD && marker1 != PAD ) {     //No PAD e.g 3cQl
                  b3 = base64Alphabet[ marker0 ];
                  b4 = base64Alphabet[ marker1 ];
  
                  decodedData[encodedIndex]   = (byte)(  b1 <<2 | b2>>4 ) ;
                  decodedData[encodedIndex+1] = (byte)(((b2 & 0xf)<<4 ) |(
  (b3>>2) & 0xf) );
                  decodedData[encodedIndex+2] = (byte)( b3<<6 | b4 );
              } else if ( marker0 == PAD ) {               //Two PAD e.g. 3c[Pad][Pad]
                  decodedData[encodedIndex]   = (byte)(  b1 <<2 | b2>>4 ) ;
                  decodedData[encodedIndex+1] = (byte)((b2 & 0xf)<<4 );
                  decodedData[encodedIndex+2] = (byte) 0;
              } else if ( marker1 == PAD ) {              //One PAD e.g. 3cQ[Pad]
                  b3 = base64Alphabet[ marker0 ];
  
                  decodedData[encodedIndex]   = (byte)(  b1 <<2 | b2>>4 );
                  decodedData[encodedIndex+1] = (byte)(((b2 & 0xf)<<4 ) |(
  (b3>>2) & 0xf) );
                  decodedData[encodedIndex+2] = (byte)( b3<<6);
              }
              encodedIndex += 3;
          }
          return decodedData;
  
      }
  
      static final int base64[]= {
        64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
            64,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
            64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
            41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
      };
  
      public static String base64Decode( String orig ) {
        char chars[]=orig.toCharArray();
        StringBuffer sb=new StringBuffer();
        int i=0;
  
        int shift = 0;   // # of excess bits stored in accum
        int acc = 0;
        
        for (i=0; i<chars.length; i++) {
            int v = base64[ chars[i] & 0xFF ];
            
            if ( v >= 64 ) {
                if( chars[i] != '=' )
                    System.out.println("Wrong char in base64: " + chars[i]);
            } else {
                acc= ( acc << 6 ) | v;
                shift += 6;
                if ( shift >= 8 ) {
                    shift -= 8;
                    sb.append( (char) ((acc >> shift) & 0xff));
                }
            }
        }
        return sb.toString();
      }
  
  
  }
  
  
  
  
  1.1                  
jakarta-tomcat/src/share/org/apache/tomcat/util/buf/ByteChunk.java
  
  Index: ByteChunk.java
  ===================================================================
  /*
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, 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 acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", 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 [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * 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 (INCLUDING, 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/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  package org.apache.tomcat.util.buf;
  
  import java.text.*;
  import java.util.*;
  import java.io.Serializable;
  
  /**
   * This class is used to represent a chunk of bytes, and
   * utilities to manipulate byte[].
   *
   * In a server it is very important to be able to operate on
   * the original byte[] without converting everything to chars.
   * Some protocols are ASCII only, and some allow different
   * non-UNICODE encodings. The encoding is not known beforehand,
   * and can even change during the execution of the protocol.
   * ( for example a multipart message may have parts with different
   *  encoding )
   *
   * For HTTP it is not very clear how the encoding of RequestURI
   * and mime values can be determined, but it is a great advantage
   * to be able to parse the request without converting to string.
   *
   * @author [EMAIL PROTECTED]
   * @author James Todd [[EMAIL PROTECTED]]
   * @author Costin Manolache
   */
  public final class ByteChunk implements Cloneable, Serializable {
      // byte[]
      private byte[] bytes;
      private int bytesOff;
      private int bytesLen;
      private String enc;
      private boolean isSet=false;
      
      /**
       * Creates a new, uninitialized ByteChunk object.
       */
      public ByteChunk() {
      }
  
      public ByteChunk getClone() {
        try {
            return (ByteChunk)this.clone();
        } catch( Exception ex) {
            return null;
        }
      }
  
      public boolean isNull() {
        return ! isSet; // bytes==null;
      }
      
      /**
       * Resets the message bytes to an uninitialized state.
       */
      public void recycle() {
        bytes = null;
        enc=null;
        isSet=false;
      }
  
      /**
       * Sets the message bytes to the specified subarray of bytes.
       * 
       * @param b the ascii bytes
       * @param off the start offset of the bytes
       * @param len the length of the bytes
       */
      public void setBytes(byte[] b, int off, int len) {
        bytes = b;
        bytesOff = off;
        bytesLen = len;
        isSet=true;
      }
  
      public void setEncoding( String enc ) {
        this.enc=enc;
      }
  
      // convert an int to byte[]
      public void setInt(int i) {
        // XXX TODO
      }
      // -------------------- Conversion and getters --------------------
      public static boolean isUTF8Compatible(String enc) {
        if( enc==null ) return true;
        // add known encodings
        return false;
      }
      
      public String toString() {
        if (null == bytes) {
            return null;
        }
        String strValue=null;
        try {
            if( enc==null )
                strValue=toStringUTF8();
            else {
                strValue=new String(bytes, bytesOff, bytesLen, enc);
                // this will display when we implement I18N
                System.out.println("Converting from bytes to string using " +
                                   enc + ":" + strValue  );
            }
            return strValue;
        } catch (java.io.UnsupportedEncodingException e) {
            return null;  // can't happen
        }
      }
  
      private char[] conversionBuff;
      
      private String toStringUTF8() {
        if( conversionBuff==null || bytesLen > conversionBuff.length ) {
            conversionBuff=new char[bytesLen];
        }
  
        int j=bytesOff;
        for( int i=0; i< bytesLen; i++ ) {
            conversionBuff[i]=(char)bytes[j++];
        }
        return new String( conversionBuff, 0, bytesLen);
      }
  
      public int getInt()
      {
        return Ascii.parseInt(bytes, bytesOff,bytesLen);
      }
  
      // --------------------
      
      /**
       * Returns the message bytes.
       */
      public byte[] getBytes() {
        return bytes;
      }
  
      /**
       * Returns the start offset of the bytes.
       */
      public int getOffset() {
        return bytesOff;
      }
  
      /**
       * Returns the length of the bytes.
       */
      public int getLength() {
        return bytesLen;
      }
  
      // -------------------- equals --------------------
  
      /**
       * Compares the message bytes to the specified String object.
       * @param s the String to compare
       * @return true if the comparison succeeded, false otherwise
       */
      public boolean equals(String s) {
        // XXX ENCODING - this only works if encoding is UTF8-compat
        // ( ok for tomcat, where we compare ascii - header names, etc )!!!
        
        byte[] b = bytes;
        int blen = bytesLen;
        if (b == null || blen != s.length()) {
            return false;
        }
        int boff = bytesOff;
        for (int i = 0; i < blen; i++) {
            if (b[boff++] != s.charAt(i)) {
                return false;
            }
        }
        return true;
      }
  
      /**
       * Compares the message bytes to the specified String object.
       * @param s the String to compare
       * @return true if the comparison succeeded, false otherwise
       */
      public boolean equalsIgnoreCase(String s) {
        byte[] b = bytes;
        int blen = bytesLen;
        if (b == null || blen != s.length()) {
            return false;
        }
        int boff = bytesOff;
        for (int i = 0; i < blen; i++) {
            if (Ascii.toLower(b[boff++]) != Ascii.toLower(s.charAt(i))) {
                return false;
            }
        }
        return true;
      }
  
      public boolean equals( ByteChunk bb ) {
        return equals( bb.getBytes(), bb.getOffset(), bb.getLength());
      }
      
      public boolean equals( byte b2[], int off2, int len2) {
        byte b1[]=bytes;
        if( b1==null && b2==null ) return true;
  
        int len=bytesLen;
        if ( len2 != len || b1==null || b2==null ) 
            return false;
                
        int off1 = bytesOff;
  
        while ( len-- > 0) {
            if (b1[off1++] != b2[off2++]) {
                return false;
            }
        }
        return true;
      }
  
      public boolean equals( CharChunk cc ) {
        return equals( cc.getChars(), cc.getOffset(), cc.getLength());
      }
      
      public boolean equals( char c2[], int off2, int len2) {
        // XXX works only for enc compatible with ASCII/UTF !!!
        byte b1[]=bytes;
        if( c2==null && b1==null ) return true;
        
        if (b1== null || c2==null || bytesLen != len2 ) {
            return false;
        }
        int off1 = bytesOff;
        int len=bytesLen;
        
        while ( len-- > 0) {
            if ( (char)b1[off1++] != c2[off2++]) {
                return false;
            }
        }
        return true;
      }
  
      /**
       * Returns true if the message bytes starts with the specified string.
       * @param s the string
       */
      public boolean startsWith(String s) {
        // Works only if enc==UTF
        byte[] b = bytes;
        int blen = s.length();
        if (b == null || blen > bytesLen) {
            return false;
        }
        int boff = bytesOff;
        for (int i = 0; i < blen; i++) {
            if (b[boff++] != s.charAt(i)) {
                return false;
            }
        }
        return true;
      }
  
      /**
       * Returns true if the message bytes starts with the specified string.
       * @param s the string
       */
      public boolean startsWithIgnoreCase(String s, int pos) {
        byte[] b = bytes;
        int len = s.length();
        if (b == null || len+pos > bytesLen) {
            return false;
        }
        int off = bytesOff+pos;
        for (int i = 0; i < len; i++) {
            if (Ascii.toLower( b[off++] ) != Ascii.toLower( s.charAt(i))) {
                return false;
            }
        }
        return true;
      }
      
  
  
      // based on ap_unescape_url ( util.c, Apache2.0 )
      public int unescapeURL()
      {
        int end=bytesOff+ bytesLen;
        int idx= indexOf( bytes, bytesOff, end, '%' );
        if( idx<0) return 0;
  
        for( int j=idx; j<end; j++, idx++ ) {
            if( bytes[ j ] != '%' ) {
                bytes[idx]=bytes[j];
            } else {
                // read next 2 digits
                if( j+2 >= end ) {
                    // invalid
                    return 400; // BAD_REQUEST
                }
                byte b1= bytes[j+1];
                byte b2=bytes[j+2];
                if( !isHexDigit( b1 ) || ! isHexDigit(b2 ))
                    return 400;
                
                j+=2;
                int res=x2c( b1, b2 );
                if( res=='/' || res=='\0' )
                    return 400;
                bytes[idx]=(byte)res;
                bytesLen-=2;
            }
        }
        return 0;
      }
  
      public static boolean isHexDigit( int c ) {
        return ( ( c>='0' && c<='9' ) ||
                 ( c>='a' && c<='f' ) ||
                 ( c>='A' && c<='F' ));
      }
      
      public static int x2c( byte b1, byte b2 ) {
        int digit= (b1>='A') ? ( (b1 & 0xDF)-'A') + 10 :
            (b1 -'0');
        digit*=16;
        digit +=(b2>='A') ? ( (b2 & 0xDF)-'A') + 10 :
            (b2 -'0');
        return digit;
      }
  
      // -------------------- Hash code  --------------------
  
      // normal hash. 
      public int hash() {
        return hashBytes( bytes, bytesOff, bytesLen);
      }
  
      // hash ignoring case
      public int hashIgnoreCase() {
        return hashBytesIC( bytes, bytesOff, bytesLen );
      }
  
      private static int hashBytes( byte bytes[], int bytesOff, int bytesLen ) {
        int max=bytesOff+bytesLen;
        byte bb[]=bytes;
        int code=0;
        for (int i = bytesOff; i < max ; i++) {
            code = code * 37 + bb[i];
        }
        return code;
      }
  
      private static int hashBytesIC( byte bytes[], int bytesOff,
                                    int bytesLen )
      {
        int max=bytesOff+bytesLen;
        byte bb[]=bytes;
        int code=0;
        for (int i = bytesOff; i < max ; i++) {
            code = code * 37 + Ascii.toLower(bb[i]);
        }
        return code;
      }
  
      /**
       * Returns true if the message bytes starts with the specified string.
       * @param s the string
       */
      public int indexOf(char c, int starting) {
        return indexOf( bytes, bytesOff+starting, bytesOff+bytesLen, c);
      }
  
      public static int  indexOf( byte bytes[], int off, int end, char qq )
      {
        // Works only for UTF 
        while( off < end ) {
            byte b=bytes[off];
            if( b==qq )
                return off;
            off++;
        }
        return -1;
      }
  
          /** Find a character, no side effects.
       *  @returns index of char if found, -1 if not
       */
      public static int findChar( byte buf[], int start, int end, char c ) {
        byte b=(byte)c;
        int offset = start;
        while (offset < end) {
            if (buf[offset] == b) {
                return offset;
            }
            offset++;
        }
        return -1;
      }
  
      /** Find a character, no side effects.
       *  @returns index of char if found, -1 if not
       */
      public static int findChars( byte buf[], int start, int end, byte c[] ) {
        int clen=c.length;
        int offset = start;
        while (offset < end) {
            for( int i=0; i<clen; i++ ) 
                if (buf[offset] == c[i]) {
                    return offset;
                }
            offset++;
        }
        return -1;
      }
  
      /** Find the first character != c 
       *  @returns index of char if found, -1 if not
       */
      public static int findNotChars( byte buf[], int start, int end, byte c[] )
      {
        int clen=c.length;
        int offset = start;
        boolean found;
                
        while (offset < end) {
            found=true;
            for( int i=0; i<clen; i++ ) {
                if (buf[offset] == c[i]) {
                    found=false;
                    break;
                }
            }
            if( found ) { // buf[offset] != c[0..len]
                return offset;
            }
            offset++;
        }
        return -1;
      }
  
  
      
  }
  
  
  
  1.1                  
jakarta-tomcat/src/share/org/apache/tomcat/util/buf/CharChunk.java
  
  Index: CharChunk.java
  ===================================================================
  /*
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, 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 acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", 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 [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * 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 (INCLUDING, 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/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  package org.apache.tomcat.util.buf;
  
  import java.text.*;
  import java.util.*;
  import java.io.Serializable;
  
  /**
   * Utilities to manipluate char chunks. While String is
   * the easiest way to manipulate chars ( search, substrings, etc),
   * it is known to not be the most efficient solution - Strings are
   * designed as imutable and secure objects.
   * 
   * @author [EMAIL PROTECTED]
   * @author James Todd [[EMAIL PROTECTED]]
   * @author Costin Manolache
   */
  public final class CharChunk implements Cloneable, Serializable {
      // char[]
      private char chars[];
      private int charsOff;
      private int charsLen;
      private boolean isSet=false;    
      /**
       * Creates a new, uninitialized CharChunk object.
       */
      public CharChunk() {
      }
  
      public CharChunk getClone() {
        try {
            return (CharChunk)this.clone();
        } catch( Exception ex) {
            return null;
        }
      }
  
      public boolean isNull() {
        return !isSet;
      }
      
      /**
       * Resets the message bytes to an uninitialized state.
       */
      public void recycle() {
        //      chars=null;
        isSet=false;
      }
  
      public void setChars( char[] c, int off, int len ) {
        recycle();
        chars=c;
        charsOff=off;
        charsLen=len;
      }
  
      // -------------------- Conversion and getters --------------------
  
      public String toString() {
        if( chars==null ) return null;
        return new String( chars, charsOff, charsLen);
      }
  
      public int getInt()
      {
        return Ascii.parseInt(chars, charsOff,
                                charsLen);
      }
      
      public char[] getChars()
      {
        return chars;
      }
      
      /**
       * Returns the start offset of the bytes.
       */
      public int getOffset() {
        return charsOff;
      }
  
      /**
       * Returns the length of the bytes.
       */
      public int getLength() {
        return charsLen;
      }
  
      // -------------------- equals --------------------
  
      /**
       * Compares the message bytes to the specified String object.
       * @param s the String to compare
       * @return true if the comparison succeeded, false otherwise
       */
      public boolean equals(String s) {
        char[] c = chars;
        int len = charsLen;
        if (c == null || len != s.length()) {
            return false;
        }
        int off = charsOff;
        for (int i = 0; i < len; i++) {
            if (c[off++] != s.charAt(i)) {
                return false;
            }
        }
        return true;
      }
  
      /**
       * Compares the message bytes to the specified String object.
       * @param s the String to compare
       * @return true if the comparison succeeded, false otherwise
       */
      public boolean equalsIgnoreCase(String s) {
        char[] c = chars;
        int len = charsLen;
        if (c == null || len != s.length()) {
            return false;
        }
        int off = charsOff;
        for (int i = 0; i < len; i++) {
            if (Ascii.toLower( c[off++] ) != Ascii.toLower( s.charAt(i))) {
                return false;
            }
        }
        return true;
      }
  
      public boolean equals(CharChunk cc) {
        return equals( cc.getChars(), cc.getOffset(), cc.getLength());
      }
  
      public boolean equals(char b2[], int off2, int len2) {
        char b1[]=chars;
        if( b1==null && b2==null ) return true;
        
        if (b1== null || b2==null || charsLen != len2) {
            return false;
        }
        int off1 = charsOff;
        int len=charsLen;
        while ( len-- > 0) {
            if (b1[off1++] != b2[off2++]) {
                return false;
            }
        }
        return true;
      }
  
      public boolean equals(byte b2[], int off2, int len2) {
        char b1[]=chars;
        if( b2==null && b1==null ) return true;
  
        if (b1== null || b2==null || charsLen != len2) {
            return false;
        }
        int off1 = charsOff;
        int len=charsLen;
        
        while ( len-- > 0) {
            if ( b1[off1++] != (char)b2[off2++]) {
                return false;
            }
        }
        return true;
      }
      
      /**
       * Returns true if the message bytes starts with the specified string.
       * @param s the string
       */
      public boolean startsWith(String s) {
        char[] c = chars;
        int len = s.length();
        if (c == null || len > charsLen) {
            return false;
        }
        int off = charsOff;
        for (int i = 0; i < len; i++) {
            if (c[off++] != s.charAt(i)) {
                return false;
            }
        }
        return true;
      }
      
      /**
       * Returns true if the message bytes starts with the specified string.
       * @param s the string
       */
      public boolean startsWithIgnoreCase(String s, int pos) {
        char[] c = chars;
        int len = s.length();
        if (c == null || len+pos > charsLen) {
            return false;
        }
        int off = charsOff+pos;
        for (int i = 0; i < len; i++) {
            if (Ascii.toLower( c[off++] ) != Ascii.toLower( s.charAt(i))) {
                return false;
            }
        }
        return true;
      }
      
  
      // -------------------- Hash code  --------------------
  
      // normal hash. 
      public int hash() {
        int code=0;
        for (int i = charsOff; i < charsOff + charsLen; i++) {
            code = code * 37 + chars[i];
        }
        return code;
      }
  
      // hash ignoring case
      public int hashIgnoreCase() {
        int code=0;
        for (int i = charsOff; i < charsOff + charsLen; i++) {
            code = code * 37 + Ascii.toLower(chars[i]);
        }
        return code;
      }
  
      public int indexOf(char c) {
        return indexOf( c, charsOff);
      }
      
      /**
       * Returns true if the message bytes starts with the specified string.
       * @param s the string
       */
      public int indexOf(char c, int starting) {
        return indexOf( chars, charsOff+starting, charsOff+charsLen, c );
      }
  
      public static int indexOf( char chars[], int off, int end, char qq )
      {
        while( off < end ) {
            char b=chars[off];
            if( b==qq )
                return off;
            off++;
        }
        return -1;
      }
  
      // based on ap_unescape_url ( util.c, Apache2.0 )
      public int unescapeURL()
      {
        int end=charsOff+ charsLen;
        int idx= indexOf( chars, charsOff, end, '%' );
        if( idx<0) return 0;
  
        for( int j=idx; j<end; j++, idx++ ) {
            if( chars[ j ] != '%' ) {
                chars[idx]=chars[j];
            } else {
                // read next 2 digits
                if( j+2 >= end ) {
                    // invalid
                    return 400; // BAD_REQUEST
                }
                char b1= chars[j+1];
                char b2=chars[j+2];
                if( !isHexDigit( b1 ) || ! isHexDigit(b2 ))
                    return 400;
                
                j+=2;
                int res=x2c( b1, b2 );
                if( res=='/' || res=='\0' )
                    return 400;
                chars[idx]=(char)res;
                charsLen-=2;
            }
        }
        return 0;
      }
  
      public static boolean isHexDigit( int c ) {
        return ( ( c>='0' && c<='9' ) ||
                 ( c>='a' && c<='f' ) ||
                 ( c>='A' && c<='F' ));
      }
      
      public static int x2c( char b1, char b2 ) {
        int digit= (b1>='A') ? ( (b1 & 0xDF)-'A') + 10 :
            (b1 -'0');
        digit*=16;
        digit +=(b2>='A') ? ( (b2 & 0xDF)-'A') + 10 :
            (b2 -'0');
        return digit;
      }
  
  
      
      /**
       * This method decodes the given urlencoded string.
       *
       * @param  str the url-encoded string
       * @return the decoded string
       * @exception IllegalArgumentException If a '%' is not
       * followed by a valid 2-digit hex number.
       *
       * @author: cut & paste from JServ, much faster that previous tomcat impl 
       */
      public final static String unescapeURL(String str)
      {
        // old code
        //System.out.println("XXX old unescape URL "+ str);
  
          if (str == null)  return  null;
        
        // pay for what you use - unencoded requests will not get
        // less overhead
        // XXX this should be in the caller ?
        if( str.indexOf( '+' ) <0 && str.indexOf( '%' ) < 0 )
            return str;
        
          StringBuffer dec = new StringBuffer();    // decoded string output
          int strPos = 0;
          int strLen = str.length();
  
          dec.ensureCapacity(str.length());
          while (strPos < strLen) {
              int laPos;        // lookahead position
  
              // look ahead to next URLencoded metacharacter, if any
              for (laPos = strPos; laPos < strLen; laPos++) {
                  char laChar = str.charAt(laPos);
                  if ((laChar == '+') || (laChar == '%')) {
                      break;
                  }
              }
  
              // if there were non-metacharacters, copy them all as a block
              if (laPos > strPos) {
                  dec.append(str.substring(strPos,laPos));
                  strPos = laPos;
              }
  
              // shortcut out of here if we're at the end of the string
              if (strPos >= strLen) {
                  break;
              }
  
              // process next metacharacter
              char metaChar = str.charAt(strPos);
              if (metaChar == '+') {
                  dec.append(' ');
                  strPos++;
                  continue;
              } else if (metaChar == '%') {
                // We throw the original exception - the super will deal with
                // it
                //                try {
                dec.append((char)Integer.
                           parseInt(str.substring(strPos + 1, strPos + 3),16));
                  strPos += 3;
              }
          }
  
          return dec.toString();
      }
  
  
  
  
  }
  
  
  
  1.1                  
jakarta-tomcat/src/share/org/apache/tomcat/util/buf/DateTool.java
  
  Index: DateTool.java
  ===================================================================
  /*
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, 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 acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", 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 [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * 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 (INCLUDING, 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/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  package org.apache.tomcat.util.buf;
  
  import java.io.IOException;
  import java.io.OutputStream;
  import java.util.*;
  import java.text.*;
  
  import org.apache.tomcat.util.res.StringManager;
  
  /**
   *  Common place for date utils.
   *
   * @author [EMAIL PROTECTED]
   * @author Jason Hunter [[EMAIL PROTECTED]]
   * @author James Todd [[EMAIL PROTECTED]]
   * @author Costin Manolache
   */
  public class DateTool {
  
      /** US locale - all HTTP dates are in english
       */
      public final static Locale LOCALE_US = Locale.US;
  
      /** GMT timezone - all HTTP dates are on GMT
       */
      public final static TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT");
  
      /** format for RFC 1123 date string -- "Sun, 06 Nov 1994 08:49:37 GMT"
       */
      public final static String RFC1123_PATTERN =
          "EEE, dd MMM yyyyy HH:mm:ss z";
  
      // format for RFC 1036 date string -- "Sunday, 06-Nov-94 08:49:37 GMT"
      private final static String rfc1036Pattern =
          "EEEEEEEEE, dd-MMM-yy HH:mm:ss z";
  
      // format for C asctime() date string -- "Sun Nov  6 08:49:37 1994"
      private final static String asctimePattern =
          "EEE MMM d HH:mm:ss yyyyy";
  
      /** Pattern used for old cookies
       */
      public final static String OLD_COOKIE_PATTERN = "EEE, dd-MMM-yyyy HH:mm:ss z";
  
      /** DateFormat to be used to format dates
       */
      public final static DateFormat rfc1123Format =
        new SimpleDateFormat(RFC1123_PATTERN, LOCALE_US);
      
      /** DateFormat to be used to format old netscape cookies
       */
      public final static DateFormat oldCookieFormat =
        new SimpleDateFormat(OLD_COOKIE_PATTERN, LOCALE_US);
      
      public final static DateFormat rfc1036Format =
        new SimpleDateFormat(rfc1036Pattern, LOCALE_US);
      
      public final static DateFormat asctimeFormat =
        new SimpleDateFormat(asctimePattern, LOCALE_US);
      
      static {
        rfc1123Format.setTimeZone(GMT_ZONE);
        oldCookieFormat.setTimeZone(GMT_ZONE);
        rfc1036Format.setTimeZone(GMT_ZONE);
        asctimeFormat.setTimeZone(GMT_ZONE);
      }
   
      private static StringManager sm =
          StringManager.getManager("org.apache.tomcat.resources");
      
      public static long parseDate( MessageBytes value ) {
        return parseDate( value.toString());
      }
  
      public static long parseDate( String dateString ) {
        Date date=null;
          try {
              date = DateTool.rfc1123Format.parse(dateString);
            return date.getTime();
        } catch (ParseException e) { }
        
          try {
            date = DateTool.rfc1036Format.parse(dateString);
            return date.getTime();
        } catch (ParseException e) { }
        
          try {
              date = DateTool.asctimeFormat.parse(dateString);
            return date.getTime();
          } catch (ParseException pe) {
          }
        String msg = sm.getString("httpDate.pe", dateString);
        throw new IllegalArgumentException(msg);
      }
  
  }
  
  
  
  1.1                  
jakarta-tomcat/src/share/org/apache/tomcat/util/buf/HexUtils.java
  
  Index: HexUtils.java
  ===================================================================
  /*
   * $Header: 
/home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/buf/HexUtils.java,v 1.1 
2001/02/20 03:12:13 costin Exp $
   * $Revision: 1.1 $
   * $Date: 2001/02/20 03:12:13 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, 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 acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", 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 [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * 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 (INCLUDING, 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/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  
  package org.apache.tomcat.util.buf;
  
  import java.io.ByteArrayOutputStream;
  import org.apache.tomcat.util.res.StringManager;
  
  /**
   * Library of utility methods useful in dealing with converting byte arrays
   * to and from strings of hexadecimal digits.
   *
   * @author Craig R. McClanahan
   */
  
  public final class HexUtils {
      // Code from Ajp11, from Apache's JServ
      
      // Table for HEX to DEC byte translation
      public static final int[] DEC = {
          -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
          -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
          -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
          00, 01, 02, 03, 04, 05, 06, 07,  8,  9, -1, -1, -1, -1, -1, -1,
          -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
          -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
          -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
          -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
          -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
          -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
          -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
          -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
          -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
          -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
          -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
          -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      };
      
  
  
      /**
       * The string manager for this package.
       */
      private static StringManager sm =
        StringManager.getManager("org.apache.tomcat.resources");
  
  
      /**
       * Convert a String of hexadecimal digits into the corresponding
       * byte array by encoding each two hexadecimal digits as a byte.
       *
       * @param digits Hexadecimal digits representation
       *
       * @exception IllegalArgumentException if an invalid hexadecimal digit
       *  is found, or the input string contains an odd number of hexadecimal
       *  digits
       */
      public static byte[] convert(String digits) {
  
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        for (int i = 0; i < digits.length(); i += 2) {
            char c1 = digits.charAt(i);
            if ((i+1) >= digits.length())
                throw new IllegalArgumentException
                    (sm.getString("hexUtil.odd"));
            char c2 = digits.charAt(i + 1);
            byte b = 0;
            if ((c1 >= '0') && (c1 <= '9'))
                b += ((c1 - '0') * 16);
            else if ((c1 >= 'a') && (c1 <= 'f'))
                b += ((c1 - 'a' + 10) * 16);
            else if ((c1 >= 'A') && (c1 <= 'F'))
                b += ((c1 - 'A' + 10) * 16);
            else
                throw new IllegalArgumentException
                    (sm.getString("hexUtil.bad"));
            if ((c2 >= '0') && (c2 <= '9'))
                b += (c2 - '0');
            else if ((c2 >= 'a') && (c2 <= 'f'))
                b += (c2 - 'a' + 10);
            else if ((c2 >= 'A') && (c2 <= 'F'))
                b += (c2 - 'A' + 10);
            else
                throw new IllegalArgumentException
                    (sm.getString("hexUtil.bad"));
            baos.write(b);
        }
        return (baos.toByteArray());
  
      }
  
  
      /**
       * Convert a byte array into a printable format containing a
       * String of hexadecimal digit characters (two per byte).
       *
       * @param bytes Byte array representation
       */
      public static String convert(byte bytes[]) {
  
        StringBuffer sb = new StringBuffer(bytes.length * 2);
        for (int i = 0; i < bytes.length; i++) {
            sb.append(convertDigit((int) (bytes[i] >> 4)));
            sb.append(convertDigit((int) (bytes[i] & 0x0f)));
        }
        return (sb.toString());
  
      }
  
      /**
       * Convert 4 hex digits to an int, and return the number of converted
       * bytes.
       *
       * @param hex Byte array containing exactly four hexadecimal digits
       *
       * @exception IllegalArgumentException if an invalid hexadecimal digit
       *  is included
       */
      public static int convert2Int( byte[] hex ) {
        // Code from Ajp11, from Apache's JServ
      
        // assert b.length==4
        // assert valid data
        int len;
        if(hex.length < 4 ) return 0;
        if( DEC[hex[0]]<0 )
            throw new IllegalArgumentException(sm.getString("hexUtil.bad"));
        len = DEC[hex[0]];
        len = len << 4;
        if( DEC[hex[1]]<0 )
            throw new IllegalArgumentException(sm.getString("hexUtil.bad"));
        len += DEC[hex[1]];
        len = len << 4;
        if( DEC[hex[2]]<0 )
            throw new IllegalArgumentException(sm.getString("hexUtil.bad"));
        len += DEC[hex[2]];
        len = len << 4;
        if( DEC[hex[3]]<0 )
            throw new IllegalArgumentException(sm.getString("hexUtil.bad"));
        len += DEC[hex[3]];
        return len;
      }
  
  
  
      /**
       * [Private] Convert the specified value (0 .. 15) to the corresponding
       * hexadecimal digit.
       *
       * @param value Value to be converted
       */
      private static char convertDigit(int value) {
  
        value &= 0x0f;
        if (value >= 10)
            return ((char) (value - 10 + 'a'));
        else
            return ((char) (value + '0'));
  
      }
  
  
  }
  
  
  
  1.1                  
jakarta-tomcat/src/share/org/apache/tomcat/util/buf/MessageBytes.java
  
  Index: MessageBytes.java
  ===================================================================
  /*
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, 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 acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", 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 [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * 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 (INCLUDING, 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/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  package org.apache.tomcat.util.buf;
  
  import java.text.*;
  import java.util.*;
  import java.io.Serializable;
  
  // XXX XXX Need StringBuffer support !
  
  
  /**
   * This class is used to represent a subarray of bytes in an HTTP message.
   *
   * @author [EMAIL PROTECTED]
   * @author James Todd [[EMAIL PROTECTED]]
   * @author Costin Manolache
   */
  public final class MessageBytes implements Cloneable, Serializable {
      public static final String DEFAULT_CHAR_ENCODING="8859_1";
      
      // primary type ( whatever is set as original value )
      private int type = T_NULL;
      
      public static final int T_NULL = 0;
      public static final int T_STR  = 1;
      public static final int T_BYTES = 2;
      public static final int T_CHARS = 3;
  
      private int hashCode=0;
      private boolean hasHashCode=false;
  
      private boolean caseSensitive=true;
      
      ByteChunk byteC=new ByteChunk();
  
      CharChunk charC=new CharChunk();
      
      // String
      private String strValue;
      private boolean hasStrValue=false;
  
      // efficient int and date
      // XXX used only for headers - shouldn't be
      // stored here.
      private int intValue;
      private boolean hasIntValue=false;
      private Date dateValue;
      private boolean hasDateValue=false;
      
      /**
       * Creates a new, uninitialized MessageBytes object.
       */
      public MessageBytes() {
      }
  
      public void setCaseSenitive( boolean b ) {
        caseSensitive=b;
      }
  
      public MessageBytes getClone() {
        try {
            return (MessageBytes)this.clone();
        } catch( Exception ex) {
            return null;
        }
      }
  
      public boolean isNull() {
        return byteC.isNull() && charC.isNull() && ! hasStrValue;
        // bytes==null && strValue==null;
      }
      
      /**
       * Resets the message bytes to an uninitialized state.
       */
      public void recycle() {
        type=T_NULL;
        byteC.recycle();
        charC.recycle();
  
        strValue=null;
        caseSensitive=true;
  
        hasStrValue=false;
        hasHashCode=false;
        hasIntValue=false;
        hasDateValue=false;     
      }
  
  
      /**
       * Sets the message bytes to the specified subarray of bytes.
       * @param b the ascii bytes
       * @param off the start offset of the bytes
       * @param len the length of the bytes
       */
      public void setBytes(byte[] b, int off, int len) {
        recycle(); // a new value is set, cached values must reset
        byteC.setBytes( b, off, len );
        type=T_BYTES;
      }
  
      public void setEncoding( String enc ) {
        if( !byteC.isNull() ) {
            // if the encoding changes we need to reset the converion results
            charC.recycle();
            hasStrValue=false;
        }
        byteC.setEncoding(enc);
      }
      
      public void setChars( char[] c, int off, int len ) {
        recycle();
        charC.setChars( c, off, len );
        type=T_CHARS;
      }
  
      public void setString( String s ) {
        recycle();
        strValue=s;
        hasStrValue=true;
        type=T_STR;
      }
  
      public void setTime(long t) {
        // XXX replace it with a byte[] tool
        recycle();
        if( dateValue==null)
            dateValue=new Date(t);
        else
            dateValue.setTime(t);
        strValue=DateTool.rfc1123Format.format(dateValue);
        hasStrValue=true;
        hasDateValue=true;
        type=T_STR;   
      }
  
      /** Set the buffer to the representation of an int 
       */
      public void setInt(int i) {
        // XXX replace it with a byte[] tool
        recycle();
        strValue=String.valueOf( i );
        intValue=i;
        hasIntValue=true;
        hasStrValue=true;
        type=T_STR;
      }
  
      // -------------------- Conversion and getters --------------------
      public String toString() {
        if( hasStrValue ) return strValue;
        hasStrValue=true;
        
        switch (type) {
        case T_CHARS:
            strValue=charC.toString();
            return strValue;
        case T_BYTES:
            strValue=byteC.toString();
            return strValue;
        }
        return null;
      }
      
      public long getTime()
      {
        if( hasDateValue ) {
            if( dateValue==null) return -1;
            return dateValue.getTime();
        }
        
        long l=DateTool.parseDate( this );
        if( dateValue==null)
            dateValue=new Date(l);
        else
            dateValue.setTime(l);
        hasDateValue=true;
        return l;
      }
      
  
      /** Convert the buffer to an int, cache the value
       */ 
      public int getInt() 
      {
        if( hasIntValue )
            return intValue;
        
        switch (type) {
        case T_BYTES:
            intValue=byteC.getInt();
            break;
        default:
            intValue=Integer.parseInt(toString());
        }
        hasIntValue=true;
        return intValue;
      }
      
      //----------------------------------------
      public int getType() {
        return type;
      }
      
      /**
       * Returns the message bytes.
       */
      public ByteChunk getByteChunk() {
        return byteC;
      }
  
      public CharChunk getCharChunk() {
        return charC;
      }
  
      // Convert to bytes !!!
      public void toBytes() {
        // XXX todo - not used 
      }
  
      public void toChars() {
        if( ! charC.isNull() ) {
            return;
        }
        // inefficient
        toString();
        char cc[]=strValue.toCharArray();
        charC.setChars(cc, 0, cc.length);
      }
      
  
      /**
       * Returns the length of the buffer.
       */
      public int getLength() {
        if(type==T_BYTES)
            return byteC.getLength();
        if(type==T_CHARS) {
            return charC.getLength();
        }
        if(type==T_STR)
            return strValue.length();
        toString();
        return strValue.length();
      }
  
      // -------------------- equals --------------------
  
      /**
       * Compares the message bytes to the specified String object.
       * @param s the String to compare
       * @return true if the comparison succeeded, false otherwise
       */
      public boolean equals(String s) {
        if( ! caseSensitive )
            return equalsIgnoreCase( s );
        switch (type) {
        case T_STR:
            if( strValue==null && s!=null) return false;
            return strValue.equals( s );
        case T_CHARS:
            return charC.equals( s );
        case T_BYTES:
            return byteC.equals( s );
        default:
            return false;
        }
      }
  
      /**
       * Compares the message bytes to the specified String object.
       * @param s the String to compare
       * @return true if the comparison succeeded, false otherwise
       */
      public boolean equalsIgnoreCase(String s) {
        switch (type) {
        case T_STR:
            if( strValue==null && s!=null) return false;
            return strValue.equalsIgnoreCase( s );
        case T_CHARS:
            return charC.equalsIgnoreCase( s );
        case T_BYTES:
            return byteC.equalsIgnoreCase( s );
        default:
            return false;
        }
      }
  
      public int unescapeURL() {
        switch (type) {
        case T_STR:
            if( strValue==null ) return 0;
            strValue=CharChunk.unescapeURL( strValue );
        case T_CHARS:
            return charC.unescapeURL();
        case T_BYTES:
            return byteC.unescapeURL();
        }
        return 0;
      }
      
      public boolean equals(MessageBytes mb) {
        switch (type) {
        case T_STR:
            return mb.equals( strValue );
        }
  
        if( mb.type != T_CHARS &&
            mb.type!= T_BYTES ) {
            // it's a string or int/date string value
            return equals( mb.toString() );
        }
  
        // mb is either CHARS or BYTES.
        // this is either CHARS or BYTES
        // Deal with the 4 cases ( in fact 3, one is simetric)
        
        if( mb.type == T_CHARS && type==T_CHARS ) {
            return charC.equals( mb.charC );
        } 
        if( mb.type==T_BYTES && type== T_BYTES ) {
            return byteC.equals( mb.byteC );
        }
        if( mb.type== T_CHARS && type== T_BYTES ) {
            return byteC.equals( mb.charC );
        }
        if( mb.type== T_BYTES && type== T_CHARS ) {
            return mb.byteC.equals( charC );
        }
        // can't happen
        return true;
      }
  
      
      /**
       * Returns true if the message bytes starts with the specified string.
       * @param s the string
       */
      public boolean startsWith(String s) {
        switch (type) {
        case T_STR:
            return strValue.startsWith( s );
        case T_CHARS:
            return charC.startsWith( s );
        case T_BYTES:
            return byteC.startsWith( s );
        default:
            return false;
        }
      }
  
      /**
       * Returns true if the message bytes starts with the specified string.
       * @param s the string
       */
      public boolean startsWithIgnoreCase(String s, int pos) {
        switch (type) {
        case T_STR:
            if( strValue==null ) return false;
            if( strValue.length() < pos + s.length() ) return false;
            
            for( int i=0; i<s.length(); i++ ) {
                if( Ascii.toLower( s.charAt( i ) ) !=
                    Ascii.toLower( strValue.charAt( pos + i ))) {
                    return false;
                }
            }
            return true;
        case T_CHARS:
            return charC.startsWithIgnoreCase( s, pos );
        case T_BYTES:
            return byteC.startsWithIgnoreCase( s, pos );
        default:
            return false;
        }
      }
  
      
  
      // -------------------- Hash code  --------------------
      public  int hashCode() {
        if( hasHashCode ) return hashCode;
        int code = 0;
  
        if( caseSensitive ) 
            code=hash(); 
        else
            code=hashIgnoreCase();
        hashCode=code;
        hasHashCode=true;
        return code;
      }
  
      // normal hash. 
      private int hash() {
        int code=0;
        switch (type) {
        case T_STR:
            // We need to use the same hash function
            for (int i = 0; i < strValue.length(); i++) {
                code = code * 37 + strValue.charAt( i );
            }
            return code;
        case T_CHARS:
            return charC.hash();
        case T_BYTES:
            return byteC.hash();
        default:
            return 0;
        }
      }
  
      // hash ignoring case
      private int hashIgnoreCase() {
        int code=0;
        switch (type) {
        case T_STR:
            for (int i = 0; i < strValue.length(); i++) {
                code = code * 37 + Ascii.toLower(strValue.charAt( i ));
            }
            return code;
        case T_CHARS:
            return charC.hashIgnoreCase();
        case T_BYTES:
            return byteC.hashIgnoreCase();
        default:
            return 0;
        }
      }
  
      public int indexOf(char c) {
        return indexOf( c, 0);
      }
  
      // Inefficient initial implementation. Will be replaced on the next
      // round of tune-up
      public int indexOf(String s, int starting) {
        toString();
        return strValue.indexOf( s, starting );
      }
      
      public int indexOfIgnoreCase(String s, int starting) {
        toString();
        String upper=strValue.toUpperCase();
        String sU=s.toUpperCase();
        return upper.indexOf( sU, starting );
      }
      
      /**
       * Returns true if the message bytes starts with the specified string.
       * @param s the string
       */
      public int indexOf(char c, int starting) {
        switch (type) {
        case T_STR:
            return strValue.indexOf( c, starting );
        case T_CHARS:
            return charC.indexOf( c, starting);
        case T_BYTES:
            return byteC.indexOf( c, starting );
        default:
            return -1;
        }
      }
  
  
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, email: [EMAIL PROTECTED]

Reply via email to