You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@apache.org on 2001/02/20 04:12:14 UTC

cvs commit: jakarta-tomcat/src/share/org/apache/tomcat/util/buf Ascii.java Base64.java ByteChunk.java CharChunk.java DateTool.java HexUtils.java MessageBytes.java

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 apache@apache.org.
   *
   * 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 dac@eng.sun.com
   * @author James Todd [gonzo@eng.sun.com]
   */
  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 apache@apache.org.
   *
   * 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 apache@apache.org.
   *
   * 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 dac@eng.sun.com
   * @author James Todd [gonzo@eng.sun.com]
   * @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 apache@apache.org.
   *
   * 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 dac@eng.sun.com
   * @author James Todd [gonzo@eng.sun.com]
   * @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 apache@apache.org.
   *
   * 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 dac@eng.sun.com
   * @author Jason Hunter [jch@eng.sun.com]
   * @author James Todd [gonzo@eng.sun.com]
   * @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 apache@apache.org.
   *
   * 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 apache@apache.org.
   *
   * 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 dac@eng.sun.com
   * @author James Todd [gonzo@eng.sun.com]
   * @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;
  	}
      }
  
  
  }