/* * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * http://www.mozilla.org/NPL/. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the License. * * The Original Code is the Netscape Messaging Access SDK Version 3.5 code, * released on or about June 15, 1998. * * The Initial Developer of the Original Code is Netscape Communications * Corporation. Portions created by Netscape are Copyright (C) 1998 Netscape * Communications Corporation. All Rights Reserved. * * Contributor(s): ______________________________________. */ /* * Copyright (c) 1997 and 1998 Netscape Communications Corporation * (http://home.netscape.com/misc/trademarks.html) */ package netscape.messaging.mime; import java.io.*; import java.lang.*; import java.net.*; import java.util.*; /** * The MIMEHelper class defines a set of utility functions. * @author Prasad Yendluri, Carson Lee */ public class MIMEHelper { // error messages final static public String szERROR_BAD_PARAMETER = "Error: Bad parameter"; final static public String szERROR_OUT_OF_MEMORY = "Error: Out of memory"; final public static String szERROR_EMPTY_MESSAGE = "Error: Empty message"; final public static String szERROR_BAD_MIME_MESSAGE = "Error: Bad mime message"; final public static String szERROR_BAD_EXTERNAL_MESSAGE_PART = "Error: No External headers in Message/external-body"; final public static String szERROR_UNSUPPORTED_PARTIAL_SUBTYPE = "Error: Unsupported Partial SubType"; final public static String szINVALID_CODE = "is an invalid code"; protected static final int BUFSZ = 4096; private static final byte base64map [] = {// 0 1 2 3 4 5 6 7 'A','B','C','D','E','F','G','H', // 0 'I','J','K','L','M','N','O','P', // 1 'Q','R','S','T','U','V','W','X', // 2 'Y','Z','a','b','c','d','e','f', // 3 'g','h','i','j','k','l','m','n', // 4 'o','p','q','r','s','t','u','v', // 5 'w','x','y','z','0','1','2','3', // 6 '4','5','6','7','8','9','+','/' // 7 }; private static final byte hexmap [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; private static final byte CR = '\r'; private static final byte LF = '\n'; private static final byte EQ = '='; private static final byte HT = '\t'; private static final byte[] CRLF = "\r\n".getBytes(); private static final byte[] EQCRLF = "=\r\n".getBytes(); private static final byte[] EQQ = "=?".getBytes(); private static final byte[] QEQ = "?=".getBytes(); private static final byte[] QB64Q = "?B?".getBytes(); private static final byte[] QQPQ = "?Q?".getBytes(); // Generate base64 decode mapping private static byte[] Base64DecMap; static { Base64DecMap = new byte[128]; for ( int idx = 0; idx < base64map.length; idx++ ) Base64DecMap[ base64map[idx] ] = (byte) idx; } //============= BEGIN NEW ONE /** * Base64 Encodes data from InputStream and writes to OutputStream. * @param input InputStream that supplies the data to be encoded. * @param output OutputStream that accepts the encoded data. * @return Number of bytes written. * @exception MIMEException If an encoding error occurs. * @exception IOException If an I/O error occurs. */ public static long encodeBase64 (InputStream input, OutputStream output) throws MIMEException, IOException { byte buf[] = new byte [3]; byte a, b, c; int read =0, offset=0, nullCount = 0, linelen = 0, written = 0, readlen = 0, leftover=0; byte l_bufenc[] = new byte [80]; byte l_readbuf[] = new byte [BUFSZ]; int triggerCount = 0; while (true) { readlen = input.read (l_readbuf, 0, BUFSZ); // trim off the last potential nulls if (readlen < BUFSZ && readlen > 0) { while (l_readbuf [readlen-1] == 0x00) { readlen--; if (readlen == 0) break; //System.out.println ("decrementing readlen =" + readlen); } } if (readlen <= 0) { if (leftover == 0) { break; } else if (leftover == 2) { a = buf[0]; b = buf[1]; c = 0; l_bufenc[linelen++] = (base64map[(a >>> 2) & 0x3F]); l_bufenc[linelen++] = (base64map[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]); l_bufenc[linelen++] = (base64map[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]); l_bufenc[linelen++] = EQ; written += 4; break; } else if (leftover == 1) { a = buf[0]; b = 0; c = 0; l_bufenc[linelen++] = (base64map[(a >>> 2) & 0x3F]); l_bufenc[linelen++] = (base64map[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]); l_bufenc[linelen++] = EQ; l_bufenc[linelen++] = EQ; written += 4; break; } } offset = 0; while (readlen > 0) { if (leftover > 0) { if (leftover == 2) { buf [2] = l_readbuf [offset++]; readlen -= 1; read = 3; leftover = 0; } else if (leftover == 1) { buf [1] = l_readbuf [offset++]; readlen -= 1; if (readlen > 0) { buf [2] = l_readbuf [offset++]; readlen -= 1; read = 3; leftover = 0; } else { leftover = 2; continue; } } } else if (readlen >= 3) { buf [0] = l_readbuf [offset++]; buf [1] = l_readbuf [offset++]; buf [2] = l_readbuf [offset++]; readlen -= 3; read = 3; leftover = 0; } else if (readlen == 2) { buf [0] = l_readbuf [offset++]; buf [1] = l_readbuf [offset++]; readlen = 0; leftover = 2; continue; } else if (readlen == 1) { buf [0] = l_readbuf [offset++]; readlen = 0; leftover = 1; continue; } if ((read == 3 && buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x00) || (read == 2 && buf[0] == 0x00 && buf[1] == 0x00) || (read == 1 && buf[0] == 0x00)) { nullCount += read; } else nullCount = 0; //if (read == 3 && !(nullCount > 100)) if (read == 3) { a = buf[0]; b = buf[1]; c = buf[2]; l_bufenc[linelen++] = (base64map[(a >>> 2) & 0x3F]); l_bufenc[linelen++] = (base64map[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]); l_bufenc[linelen++] = (base64map[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]); l_bufenc[linelen++] = (base64map[c & 0x3F]); //linelen += 4; written += 4; } //else if (read == 2 && !(nullCount > 100)) else if (read == 2) { a = buf[0]; b = buf[1]; c = 0; l_bufenc[linelen++] = (base64map[(a >>> 2) & 0x3F]); l_bufenc[linelen++] = (base64map[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]); l_bufenc[linelen++] = (base64map[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]); l_bufenc[linelen++] = EQ; //linelen += 4; written += 4; } //else if (read == 1 && !(nullCount > 100)) else if (read == 1) { a = buf[0]; b = 0; c = 0; l_bufenc[linelen++] = (base64map[(a >>> 2) & 0x3F]); l_bufenc[linelen++] = (base64map[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]); l_bufenc[linelen++] = EQ; l_bufenc[linelen++] = EQ; //linelen += 4; written += 4; } if (linelen > 71) { //output.write (LF); //written += 1; l_bufenc[linelen++] = CR; l_bufenc[linelen++] = LF; //linelen += 2; written += 2; output.write (l_bufenc, 0, linelen); linelen = 0; } } // end while } // end outer while // write out the leftover stuff if (linelen > 0) { l_bufenc[linelen++] = CR; l_bufenc[linelen++] = LF; written += 2; //l_bufenc[linelen++] = CR; //l_bufenc[linelen++] = LF; //written += 4; //linelen += 4; output.write (l_bufenc, 0, linelen); triggerCount += linelen; if (triggerCount > 1000000) { System.gc(); //output.flush(); triggerCount = 0; } linelen = 0; } return (written); } //============= END NEW ONE //============= BEGIN OLD ONE /** * Base64 Encodes data from InputStream and writes to OutputStream. * @param input InputStream that supplies the data to be encoded. * @param output OutputStream that accepts the encoded data. * @return Number of bytes written. * @exception MIMEException If an encoding error occurs. * @exception IOException If an I/O error occurs. */ protected static long encodeBase64O (InputStream input, OutputStream output) throws MIMEException, IOException { byte buf[] = new byte [3]; byte a, b, c; int nullCount = 0, linelen = 0, written = 0, dummy[] = new int[2]; byte l_bufenc[] = new byte [80]; int triggerCount = 0; while (true) { int read = input.read (buf, 0, 3); if (read <= 0) { break; } if ((read == 3 && buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x00) || (read == 2 && buf[0] == 0x00 && buf[1] == 0x00) || (read == 1 && buf[0] == 0x00)) { nullCount += read; } else nullCount = 0; //if (read == 3 && !(nullCount > 100)) if (read == 3) { a = buf[0]; b = buf[1]; c = buf[2]; l_bufenc[linelen++] = (base64map[(a >>> 2) & 0x3F]); l_bufenc[linelen++] = (base64map[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]); l_bufenc[linelen++] = (base64map[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]); l_bufenc[linelen++] = (base64map[c & 0x3F]); //linelen += 4; written += 4; } //else if (read == 2 && !(nullCount > 100)) else if (read == 2) { a = buf[0]; b = buf[1]; c = 0; l_bufenc[linelen++] = (base64map[(a >>> 2) & 0x3F]); if (b != 0x00) { l_bufenc[linelen++] = (base64map[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]); l_bufenc[linelen++] = (base64map[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]); } else l_bufenc[linelen++] = EQ; l_bufenc[linelen++] = EQ; //linelen += 4; written += 4; } //else if (read == 1 && !(nullCount > 100)) else if (read == 1) { a = buf[0]; b = 0; c = 0; l_bufenc[linelen++] = (base64map[(a >>> 2) & 0x3F]); l_bufenc[linelen++] = (base64map[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]); l_bufenc[linelen++] = EQ; l_bufenc[linelen++] = EQ; //linelen += 4; written += 4; } if (linelen > 71) { //output.write (LF); //written += 1; l_bufenc[linelen++] = CR; l_bufenc[linelen++] = LF; //linelen += 2; written += 2; output.write (l_bufenc, 0, linelen); linelen = 0; } } // end while // write out the leftover stuff if (linelen > 0) { l_bufenc[linelen++] = CR; l_bufenc[linelen++] = LF; l_bufenc[linelen++] = CR; l_bufenc[linelen++] = LF; //linelen += 4; written += 4; output.write (l_bufenc, 0, linelen); triggerCount += linelen; if (triggerCount > 1000000) { System.gc(); //output.flush(); triggerCount = 0; } linelen = 0; } return (written); } //============= END OLD ONE /** * QuotedPrintable Encodes data from InputStream and writes to OutputStream. * @param input InputStream that supplies the data to be encoded. * @param output OutputStream that accepts the encoded data. * @return Number of bytes written. * @exception MIMEException If an encoding error occurs. * @exception IOException If an I/O error occurs. */ public static long encodeQP (InputStream input, OutputStream output) throws MIMEException, IOException { byte current = (byte)0, previous = (byte)0; int read, linelen = 0, written = 0, lastspace = 0, nullCount = 0; byte l_bufenc[] = new byte [80]; while (true) { read = input.read(); if (read == -1) { if (linelen > 0) { output.write (l_bufenc, 0, linelen); output.write (CRLF); written += 2; } return (written); } current = (byte) read; if (current == 0x00) { nullCount++; previous = current; lastspace = 0; continue; } else if (nullCount > 0) { // write out all the nulls first and fall through to process current char. for (int idx = 1; idx <= nullCount ; idx++) { byte tmp = 0x00; l_bufenc [linelen++] = EQ; l_bufenc [linelen++] = (byte) hexmap [(tmp >>> 4) & 0xF]; l_bufenc [linelen++] = (byte) hexmap [(tmp & 0xF)]; // l_bufenc [linelen++] = (byte)0x00; // l_bufenc [linelen++] = (byte)0x00; written += 3; if (linelen > 74) { output.write (l_bufenc, 0, linelen); output.write (EQCRLF); written += 3; linelen = 0; } } previous = (byte) 0; nullCount = 0; } if ((current > ' ') && (current < 0x7F) && (current != '=')) { // Printable chars //output.write ((byte) current); l_bufenc [linelen++] = (byte) current; //linelen += 1; written += 1; lastspace = 0; previous = current; } else if ((current == ' ') || (current == HT)) { //output.write ((byte) current); l_bufenc [linelen++] = (byte) current; //linelen += 1; written += 1; lastspace = 1; previous = current; } else if ((current == LF) && (previous == CR)) { // handled this already. Ignore. previous = (byte) 0; } else if ((current == CR ) || (current == LF)) { // Need to emit a soft line break if last char was SPACE/HT or // if we have a period on a line by itself. if ((lastspace == 1) || ((previous == '.') && (linelen == 1))) { l_bufenc [linelen++] = EQ; l_bufenc [linelen++] = CR; l_bufenc [linelen++] = LF; written += 3; } l_bufenc [linelen++] = CR; l_bufenc [linelen++] = LF; lastspace = 0; written += 2; output.write (l_bufenc, 0, linelen); previous = (byte) 0; linelen = 0; //output.write (CRLF); //previous = current; } else if ( (current < ' ') || (current == '=') || (current >= 0x7F) ) { // Special Chars //output.write ((byte) '='); //output.write ((byte) hexmap [(current >>> 4)]); //output.write ((byte) hexmap [(current & 0xF)]); l_bufenc [linelen++] = EQ; l_bufenc [linelen++] = (byte) hexmap [(current >>> 4) & 0xF]; l_bufenc [linelen++] = (byte) hexmap [(current & 0xF)]; lastspace = 0; //linelen += 3; written += 3; previous = current; } else { //output.write ((byte) current); l_bufenc [linelen++] = (byte) current; lastspace = 0; //linelen += 1; written += 1; previous = current; } if (linelen > 74) { output.write (l_bufenc, 0, linelen); output.write (EQCRLF); written += 3; linelen = 0; previous = (byte) 0; } } // while } //encodeQP /** * Q Encodes data from InputStream and writes to OutputStream. * @param input InputStream that supplies the data to be encoded. * @param output OutputStream that accepts the encoded data. * @return Number of bytes written. * @exception MIMEException If an encoding error occurs. * @exception IOException If an I/O error occurs. */ private static long encodeQ (InputStream input, OutputStream output) throws MIMEException, IOException { byte current = (byte)0; boolean encode = false; int read, written = 0; while (true) { read = input.read(); if (read == -1) { return (written); } current = (byte) read; if ((current >= 0x30 && current <= 0x39) || // 0-9 (current >= 0x41 && current <= 0x5A) || // A-Z (current >= 0x61 && current <= 0x7A) || // a-z (current == 0x21 || current == 0x2A) || // !* (current == 0x2B || current == 0x2D) || // +- (current == 0x2F || current == 0x5F)) // /_ { encode = false; } else encode = true; if (encode) { // Special Chars output.write ((byte) '='); output.write ((byte) hexmap [(current >>> 4)]); output.write ((byte) hexmap [(current & 0xF)]); written += 3; } else { output.write ((byte) current); written += 1; } } // while } /** * String version. Base64 Decodes data from the input string. * @param str The base64-encoded string. * @return The decoded string */ protected final static String decodeBase64( String str ) { if (str == null) return null; // byte data[] = new byte[str.length()]; // str.getBytes(0, str.length(), data, 0); return new String( decodeBase64( str.getBytes() ) ); } /** * byte[] version. Base64 Decodes input bytes. * @param data base64-encoded bytes. * @return the decoded bytes */ protected final static byte[] decodeBase64( byte[] data ) { return decodeBase64( data, data.length ); } // byte[] version, ByteBuffer version // carsonl /** * byte[] version. Base64 Decodes input bytes of given length. * @param data base64-encoded bytes. * @param len length of base64-encoded bytes. * @return the decoded bytes */ protected final static byte[] decodeBase64( byte[] data, int len ) { if (data == null) return null; while (data[len-1] == '=') len--; byte dest[] = new byte[len - data.length/4]; // ascii printable to 0-63 conversion for (int idx = 0; idx >> 4) & 003) ); dest[didx+1] = (byte) ( ((data[sidx+1] << 4) & 255) | ((data[sidx+2] >>> 2) & 017) ); dest[didx+2] = (byte) ( ((data[sidx+2] << 6) & 255) | (data[sidx+3] & 077) ); } if (didx < dest.length) dest[didx] = (byte) ( ((data[sidx] << 2) & 255) | ((data[sidx+1] >>> 4) & 003) ); if (++didx < dest.length) dest[didx] = (byte) ( ((data[sidx+1] << 4) & 255) | ((data[sidx+2] >>> 2) & 017) ); return dest; } /** * QuotedPrintable Decodes data from InputStream and writes to OutputStream * @param input InputStream that supplies the data to be decoded. * @param output OutputStream that accepts the decoded data. * @exception MIMEException if a decoding error occurs. * @exception IOException if io error occurs. */ public static void decodeQP (InputStream input, OutputStream output) throws MIMEException { byte inputBuffer[]; try { inputBuffer = new byte[ input.available() + 1 ]; input.read( inputBuffer ); output.write( decodeQP( inputBuffer ) ); } catch ( IOException e ) { throw new MIMEException ( e.getMessage() ); } catch ( Exception e ) { throw new MIMEException ( e.getMessage() ); } return; } /** * String version. QP decodes data from the input string. * @param str the QP-encoded string. * @return the decoded string */ protected final static String decodeQP( String str ) throws MIMEException { String decodedString = null; if (str == null) return null; // byte data[] = new byte[str.length()]; // str.getBytes(0, str.length(), data, 0); try { decodedString = new String( decodeQP( str.getBytes() ) ); } catch( Exception e ) { throw new MIMEException( e.getMessage() ); } return decodedString; } /** * byte[] version. QP decodes input bytes. * @param bytesIn QP-encoded bytes. * @return the decoded bytes */ protected final static byte[] decodeQP( byte[] bytesIn ) throws MIMEException { return decodeQP( bytesIn, bytesIn.length ); } /** * byte[] version. QP decodes input bytes of given length. * @param bytesIn QP-encoded bytes. * @param len length of QP-encoded bytes. * @return the decoded bytes * @exception ParseException If a '=' is not followed by a valid * 2-digit hex number or '\r\n'. */ protected final static byte[] decodeQP( byte[] bytesIn, int len ) throws MIMEException { if ( bytesIn == null ) throw new MIMEException( szERROR_BAD_PARAMETER ); byte res[] = new byte[ (int) ( len * 1.1) ]; byte src[] = bytesIn; byte nl[] = System.getProperty("line.separator", "\n").getBytes(); int last = 0, j = 0; for (int i = 0; i < len; ) { byte ch = src[i++]; if (ch == '=') { if (src[i] == '\n' || src[i] == '\r') { // Rule #5 i++; if (src[i-1] == '\r' && src[i] == '\n') i++; } else // Rule #1 { byte repl; int hi = Character.digit( (char) src[i], 16), lo = Character.digit( (char) src[i+1], 16); if ((hi | lo) < 0) throw new MIMEException( new String(src, i-1, 3) + szINVALID_CODE ); else { repl = (byte) (hi << 4 | lo); i += 2; } res[j++] = repl; } last = j; } else if (ch == '\n' || ch == '\r') // Rule #4 { if (src[i-1] == '\r' && src[i] == '\n') i++; for (int idx = 0; idx < nl.length; idx++) res[last++] = nl[idx]; j = last; } else // Rule #1, #2 { res[j++] = ch; if (ch != ' ' && ch != '\t') // Rule #3 last = j; } if ( j > res.length - 5 ) { byte tmp[] = new byte[ res.length + 500 ]; System.arraycopy( res, 0, tmp, 0, res.length ); res = tmp; } } return res; } /** * Encodes a string that typically goes in a header but uses characters other than ASCII * per RFC2047. Can be used on unstructured rfc822 headers or comments of structured ones. * The returned string can be passed to setHeader() method in MIMEMessage class. * @param inputString The string to encode. * @param charsetName Name of the charset the input string is in. If null uses iso-8859-1. * @param encoding_type Must "B" or "Q". * @return The encoded header string. * @exception MIMEException if an encoding error occurs. */ public static String encodeHeader (String inputString, String charsetName, String encoding_type) throws MIMEException, UnsupportedEncodingException { int l_encoding = -1; // 0 = b64, 1= Q int l_inlength = 0; byte [] l_inbuf; if (encoding_type.equalsIgnoreCase ("B")) l_encoding = 0; else if (encoding_type.equalsIgnoreCase ("Q")) l_encoding = 1; else throw new MIMEException ("Invalid encoding_type: " + encoding_type); if (charsetName == null) l_inbuf = inputString.getBytes("iso-8859-1"); else l_inbuf = inputString.getBytes(charsetName); l_inlength = l_inbuf.length; try { ByteArrayInputStream ins = new ByteArrayInputStream (l_inbuf); ByteArrayOutputStream os = new ByteArrayOutputStream (l_inlength * 2); long enclen; if (l_encoding == 0) // base64 enclen = encodeBase64 (ins, os); else enclen = encodeQ (ins, os); if (enclen <= 0) throw new MIMEException (" Header Encoding error: " + encoding_type); //ByteString l_bs64 = new ByteString (os.toByteArray(), 0, (int)enclen-1); // hi is length of array not last index! --------------------^^^^^^^^^^ ByteString l_bsenc = new ByteString (os.toByteArray(), 0, (int)enclen); ByteBuffer l_bufenc = new ByteBuffer (l_bsenc); ByteBuffer l_retbuf = new ByteBuffer ((int)enclen+20); l_retbuf.append (EQQ); l_retbuf.append (charsetName.getBytes()); if (l_encoding == 0) // base64 l_retbuf.append (QB64Q); else l_retbuf.append (QQPQ); l_retbuf.append (l_bsenc); l_retbuf.append (QEQ); return (new String (l_retbuf.buffer)); } catch (Exception e) { throw new MIMEException (e.getMessage()); } } /** * Decodes a string encoded in RFC2047 format. If the string is not encoded * returns the original string. Can be used on the header value returned by * getHeader() and getAllHeaders() methods in MIMEMessage class. * @param inputString The string to decode. * @return The decoded header string. * @exception MIMEException If an decoding error occurs. */ public static String decodeHeader (String inputString) throws MIMEException { int len; int i, j; int nStart = 0; int nEnd = 0; String szEncodedText; StringBuffer OutputBuffer = new StringBuffer(); String plainPart=null; byte decodedText[] = null; char achCharset[] = new char[16]; boolean bEncodeBase64 = false; boolean bEncodeQP = false; boolean bEncodeString = false; if ( inputString == null ) throw new MIMEException( szERROR_BAD_PARAMETER ); len = inputString.length(); /* find start of encoding text */ for ( i = 0; i < len && inputString.charAt(i) != 0 ; i++ ) { if ( inputString.charAt(i) == '=' && inputString.charAt(i+1) == '?' ) { bEncodeString = true; break; } } if (!bEncodeString) return inputString; if (i > 0) { plainPart = inputString.substring (0, i); } /* get charset */ for ( i += 2, j = 0; i < len && inputString.charAt(i) != '?'; i++, j++ ) { achCharset[j] = inputString.charAt(i); } achCharset[j] = 0; i++; /* skip ? */ /* get encoding type */ if ( inputString.charAt(i) == 'Q' || inputString.charAt(i) == 'q' ) bEncodeQP = true; else if ( inputString.charAt(i) == 'B' || inputString.charAt(i) == 'b' ) bEncodeBase64 = true; if (inputString.charAt(i+1) == '?') i++; /* skip ? */ nStart = ++i; /* look for end of encoded text */ for ( j = 0; i < len && inputString.charAt(i) != 0 ; i++, j++ ) { if ( inputString.charAt(i) == '?' && i+1 < len && inputString.charAt(i+1) == '=' ) { nEnd = i; break; } } if ( nEnd > 0 ) { /* extract encoded text */ szEncodedText = inputString.substring( nStart, nStart + j ); if ( bEncodeQP ) decodedText = decodeQP( szEncodedText.getBytes() ); else if ( bEncodeBase64 ) decodedText = decodeBase64( szEncodedText.getBytes() ); } else { throw new MIMEException ("Improper encoded String"); } if (plainPart != null) { OutputBuffer.append (plainPart); } if ( decodedText != null ) { OutputBuffer.append (new String(decodedText)); } if (nEnd+2 < len-1) { String remainder = inputString.substring (nEnd+2, len); String retString = decodeHeader (remainder); if (retString != null) OutputBuffer.append (retString); } return (OutputBuffer.toString()); } /** * Generates and returns a boundary string that can be used in multi-parts. * @return The boundary string. */ public static String generateBoundary () { Random l_rand = new Random (System.currentTimeMillis()); long l_numboundary = l_rand.nextLong(); String l_boundary = new String ("-----" + Long.toHexString(l_numboundary)); return (l_boundary); } /** * Converts the input unicode ASCII printable chars to ASCII bytes. * @param inputString The string to convert. * @exception MIMEException If the input contains non-printable ASCII or non-ASCII chars. */ public static byte[] unicodeToASCII (String inputString) throws UnsupportedEncodingException, MIMEException { //byte [] l_bytebuf = inputString.getBytes("iso-8859-1"); byte [] l_bytebuf = inputString.getBytes(); for (int i=0, len = l_bytebuf.length; i < len; i++) { if ( (l_bytebuf[i] > 126 || l_bytebuf[i] < 32) && l_bytebuf[i] != CR && l_bytebuf[i] != LF ) throw new MIMEException ("Invalid non-printable ASCII or non-ASCII character." + l_bytebuf[i]); } return (l_bytebuf); } // unicodeToASCII /** * Based on file extension, attempts to determine the file MIME content-type * sub-type, params and extension. By default returns application/octet-stream. * @param filename Filename in the form name.ext. If no extension returns application/octet-stream. * @return Object of class fileMIMEType that has the MIME content-type* info set. */ public static fileMIMEType getFileMIMEType (String filename) { String inStr, extn; int strLen, sepIndex; fileMIMEType fmt = new fileMIMEType(); inStr = filename.trim(); strLen = inStr.length(); sepIndex = inStr.lastIndexOf ('.'); extn = inStr.substring (sepIndex+1, strLen); fmt.file_extn = extn; File ff = new File (filename); fmt.file_shortname = ff.getName(); if (extn.equalsIgnoreCase ("txt") || extn.equalsIgnoreCase ("java") || extn.equalsIgnoreCase ("c") || extn.equalsIgnoreCase ("C") || extn.equalsIgnoreCase ("cc") || extn.equalsIgnoreCase ("CC") || extn.equalsIgnoreCase ("h") || extn.equalsIgnoreCase ("hxx") || extn.equalsIgnoreCase ("bat") || extn.equalsIgnoreCase ("rc") || extn.equalsIgnoreCase ("ini") || extn.equalsIgnoreCase ("cmd") || extn.equalsIgnoreCase ("awk") || extn.equalsIgnoreCase ("html") || extn.equalsIgnoreCase ("sh") || extn.equalsIgnoreCase ("ksh") || extn.equalsIgnoreCase ("pl") || extn.equalsIgnoreCase ("DIC") || extn.equalsIgnoreCase ("EXC") || extn.equalsIgnoreCase ("LOG") || extn.equalsIgnoreCase ("SCP") || extn.equalsIgnoreCase ("WT") || extn.equalsIgnoreCase ("mk") || extn.equalsIgnoreCase ("htm")) // what else? { fmt.content_type = MIMEBasicPart.TEXT; if (extn.equalsIgnoreCase ("html") || extn.equalsIgnoreCase ("htm")) fmt.content_subtype = "html"; else fmt.content_subtype = "plain"; fmt.content_params = "us-ascii"; fmt.mime_encoding = MIMEBodyPart.E7BIT; } else if (extn.equals ("pdf")) // PDF is different { fmt.content_type = MIMEBasicPart.APPLICATION; fmt.content_subtype = "pdf"; } else if (extn.equalsIgnoreCase ("AIF") || extn.equalsIgnoreCase ("AIFC") || extn.equalsIgnoreCase ("AIFF")) { fmt.content_type = MIMEBasicPart.AUDIO; fmt.content_subtype = "aiff"; } else if (extn.equalsIgnoreCase ("AU") || extn.equalsIgnoreCase ("SND")) { fmt.content_type = MIMEBasicPart.AUDIO; fmt.content_subtype = "basic"; } else if (extn.equalsIgnoreCase ("WAV")) { fmt.content_type = MIMEBasicPart.AUDIO; fmt.content_subtype = "wav"; } else if (extn.equalsIgnoreCase ("gif") ) { fmt.content_type = MIMEBasicPart.IMAGE; fmt.content_subtype = "gif"; } else if (extn.equalsIgnoreCase ("jpg") ) { fmt.content_type = MIMEBasicPart.IMAGE; fmt.content_subtype = "jpeg"; } else if (extn.equalsIgnoreCase ("jpeg") ) { fmt.content_type = MIMEBasicPart.IMAGE; fmt.content_subtype = "jpeg"; } else if (extn.equalsIgnoreCase ("tif") ) { fmt.content_type = MIMEBasicPart.IMAGE; fmt.content_subtype = "tiff"; } else if (extn.equalsIgnoreCase ("XBM") ) { fmt.content_type = MIMEBasicPart.IMAGE; fmt.content_subtype = "x-xbitmap"; } else if (extn.equalsIgnoreCase ("avi") ) { fmt.content_type = MIMEBasicPart.VIDEO; fmt.content_subtype = "avi"; } else if (extn.equalsIgnoreCase ("mpeg") ) { fmt.content_type = MIMEBasicPart.VIDEO; fmt.content_subtype = "mpeg"; } else if (extn.equalsIgnoreCase ("ps") || extn.equalsIgnoreCase ("EPS")) { fmt.content_type = MIMEBasicPart.APPLICATION; fmt.content_subtype = "postscript"; } else if (extn.equalsIgnoreCase ("tar") ) { fmt.content_type = MIMEBasicPart.APPLICATION; fmt.content_subtype = "x-tar"; } else if (extn.equalsIgnoreCase ("zip") ) { fmt.content_type = MIMEBasicPart.APPLICATION; fmt.content_subtype = "zip"; } else if (extn.equalsIgnoreCase ("js") ) { fmt.content_type = MIMEBasicPart.APPLICATION; fmt.content_subtype = "x-javascript"; } else if (extn.equalsIgnoreCase ("doc") ) { fmt.content_type = MIMEBasicPart.APPLICATION; fmt.content_subtype = "msword"; } else if (extn.equalsIgnoreCase ("nsc") ) { fmt.content_type = MIMEBasicPart.APPLICATION; fmt.content_subtype = "x-conference"; } else if (extn.equalsIgnoreCase ("ARC") || extn.equalsIgnoreCase ("ARJ") || extn.equalsIgnoreCase ("B64") || extn.equalsIgnoreCase ("BHX") || extn.equalsIgnoreCase ("GZ") || extn.equalsIgnoreCase ("HQX")) { fmt.content_type = MIMEBasicPart.APPLICATION; fmt.content_subtype = "x-gzip"; } else { fmt.content_type = MIMEBasicPart.APPLICATION; fmt.content_subtype = "octet-stream"; } return (fmt); } /* protected static byte[] decodeQPVector( Vector v, int nStart, int nEnd, int nMessageLen, int[] param ) throws MIMEException { int i, j, nLen = 0, nTotalLen = 0, last = 0, jj = 0; byte[] line; byte[] output; byte nl[] = System.getProperty("line.separator", "\n").getBytes(); if ( v == null || param == null ) throw new MIMEException( szERROR_BAD_PARAMETER ); // get message len for ( j = nStart; j <= nEnd; j++ ) { line = (byte[]) v.elementAt( j ); nTotalLen = nTotalLen + line.length; } output = new byte[ (int)( nTotalLen * 1.1 ) ]; if ( output == null ) throw new MIMEException( "Not enough memory" ); // read off data from vector line by line for ( j = nStart; j <= nEnd; j++ ) { line = (byte[]) v.elementAt( j ); nLen = line.length; for ( i = 0; i < nLen; ) { byte ch = line[i++]; if (ch == '=') { if (line[i] == '\n' || line[i] == '\r') { // Rule #5 i++; if (line[i-1] == '\r' && line[i] == '\n') i++; } else // Rule #1 { byte repl; int hi = Character.digit( (char) line[i], 16), lo = Character.digit( (char) line[i+1], 16); if ((hi | lo) < 0) throw new MIMEException(new String(line, i-1, 3) + "is an invalid code"); else { repl = (byte) (hi << 4 | lo); i += 2; } output[j++] = repl; } last = jj; } else if (ch == '\n' || ch == '\r') // Rule #4 { if (line[i-1] == '\r' && line[i] == '\n') i++; for (int idx = 0; idx < nl.length; idx++) output[last++] = nl[idx]; jj = last; } else // Rule #1, #2 { output[jj++] = ch; if (ch != ' ' && ch != '\t') // Rule #3 last = jj; } if ( jj > output.length - 5 ) { byte tmp[] = new byte[ output.length + 500 ]; System.arraycopy( output, 0, tmp, 0, output.length ); output = tmp; } } // for each line } // for vector param[2] = jj; // len return output; } */ /* * carsonl, jan 8,98 * hex to decimal * * parameter : * * int nFirstByte : first hex byte * int nSecondByte : second hex byte * * returns : decimal */ static byte nConvertHexToDec( int nFirstByte, int nSecondByte ) { byte nValue = 0; switch ( nFirstByte ) { case ' ': case '0': nValue += 0; break; case '1': nValue += 16; break; case '2': nValue += 32; break; case '3': nValue += 48; break; case '4': nValue += 64; break; case '5': nValue += 80; break; case '6': nValue += 96; break; case '7': nValue += 112; break; case '8': nValue += 128; break; case '9': nValue += 144; break; case 'A': case 'a': nValue += 160; break; case 'B': case 'b': nValue += 176; break; case 'C': case 'c': nValue += 192; break; case 'D': case 'd': nValue += 208; break; case 'E': case 'e': nValue += 224; break; case 'F': case 'f': nValue += 240; break; } switch ( nSecondByte ) { case ' ': case '0': nValue += 0; break; case '1': nValue += 1; break; case '2': nValue += 2; break; case '3': nValue += 3; break; case '4': nValue += 4; break; case '5': nValue += 5; break; case '6': nValue += 6; break; case '7': nValue += 7; break; case '8': nValue += 8; break; case '9': nValue += 9; break; case 'A': case 'a': nValue += 10; break; case 'B': case 'b': nValue += 11; break; case 'C': case 'c': nValue += 12; break; case 'D': case 'd': nValue += 13; break; case 'E': case 'e': nValue += 14; break; case 'F': case 'f': nValue += 15; break; } return nValue; } protected static byte[] decodeQPVectorNew (Vector v, int nStart, int nEnd, int[] param, byte[] leftOverBytes) throws MIMEException { int i = 0, j = 0, ii = 0, nLen = 0, written=0; byte[] line, buffer, retbuf; byte[] token = new byte [3]; int nNoOfLeftOverBytes; if ( v == null || param == null ) throw new MIMEException( szERROR_BAD_PARAMETER ); if ( nStart == -1 || nEnd == -1 ) return null; nNoOfLeftOverBytes = param[0]; // get message len nLen = nNoOfLeftOverBytes; for (j = nStart; j <= nEnd; j++) { line = (byte[]) v.elementAt (j); nLen = nLen + line.length; } j = 0; buffer = new byte[(int) (nLen * 1.1)]; if (buffer == null) throw new MIMEException( szERROR_OUT_OF_MEMORY ); nLen = 0; /* get each line */ for ( ii = nStart; ii <= nEnd; ii++ ) { line = (byte[]) v.elementAt(ii); if (ii == nStart && nNoOfLeftOverBytes > 0) { System.arraycopy (leftOverBytes, 0, buffer, 0, nNoOfLeftOverBytes); nLen += nNoOfLeftOverBytes; } if (line == null || line.length == 0) continue; System.arraycopy (line, 0, buffer, nLen, line.length); nLen += line.length; } written = 0; i=0; int read_offset = 0; /* first time do it outside the loop */ while (i < 3 && read_offset < nLen) { token [i++] = buffer [read_offset++]; } while (read_offset < nLen || i != 0) { while (i < 3 && read_offset < nLen) { token [i++] = buffer [read_offset++]; } if (i < 3) /* did not get enough for a token */ { if (i == 2 && token [0] == CR && token [1] == LF) { buffer[written++] = token[0]; buffer[written++] = token[1]; nNoOfLeftOverBytes = 0; } else { for (j=0; j < i; j++) leftOverBytes [j] = token [j]; nNoOfLeftOverBytes = i; } param[0] = nNoOfLeftOverBytes; if (written > 0) { retbuf = new byte [written]; System.arraycopy (buffer, 0, retbuf, 0, written); return (retbuf); } } i = 0; if (token [0] == '=') { byte c = (byte)0; if ((token[1] >= '0' && token[1] <= '9') || (token[1] >= 'A' && token[1] <= 'F') || (token[1] >= 'a' && token[1] <= 'f')) c = token[1]; else if (token[1] == CR || token[1] == LF) { /* =\n means ignore the newline. */ if (token[1] == CR && token[2] == LF) ; /* swallow all three chars */ else { read_offset--; /* put the third char back */ } continue; } else { /* = followed by something other than hex or newline - pass it through unaltered, I guess. */ if (read_offset > written) { buffer[written++] = token[0]; } if (read_offset > written) { buffer[written++] = token[1]; } if (read_offset > written) { buffer[written++] = token[2]; } continue; } /* Second hex digit */ if ((token[2] >= '0' && token[2] <= '9') || (token[2] >= 'A' && token[2] <= 'F') || (token[2] >= 'a' && token[2] <= 'f')) c = (byte) ((c << 4) | token[2]); else { /* We got =xy where "x" was hex and "y" was not, so treat that as a literal "=", x, and y. */ if (read_offset > written) { buffer[written++] = token[0];} if (read_offset > written) { buffer[written++] = token[1];} if (read_offset > written) { buffer[written++] = token[2];} continue; } buffer[written++] = c; } else { buffer[written++] = token[0]; token[0] = token[1]; token[1] = token[2]; i = 2; } } param[0] = 0; // nothing leftover if (written > 0) { retbuf = new byte [written]; System.arraycopy (buffer, 0, retbuf, 0, written); return (retbuf); } return null; } /* * carson, Jan 8,98 * QuotedPrintable Decodes data from vector, write decoded data to szOutput * * params : * * int nStart : starting element in vector * int nEndt : ending element in vector * Vector *v : vector * char *szOutput : output buffer * int MaxBufferSize : max buffer size * * return : number of decoded bytes */ protected static byte[] decodeQPVector( Vector v, int nStart, int nEnd, int[] param, byte[] leftOverBytes ) throws MIMEException { byte ch, ch2; int i = 0; int j = 0; int k = 0; int ii, nLen=0; byte[] line; byte[] output; byte[] buffer; boolean bAppendLeftOverBytes = false; int nNoOfLeftOverBytes; int hi = 0, lo = 0, last = 0; char nl[] = System.getProperty("line.separator", "\n").toCharArray(); if ( v == null || param == null ) throw new MIMEException( szERROR_BAD_PARAMETER ); if ( nStart == -1 || nEnd == -1 ) return null; nNoOfLeftOverBytes = param[0]; // get message len for ( j = nStart; j <= nEnd; j++ ) { line = (byte[]) v.elementAt( j ); nLen = nLen + line.length; } output = new byte[ (int) ( nLen * 1.1 ) ]; buffer = new byte[ 128 ]; j = 0; if ( output == null || buffer == null ) throw new MIMEException( szERROR_OUT_OF_MEMORY ); /* get each line */ for ( ii = nStart; ii <= nEnd; ii++ ) { line = (byte[]) v.elementAt(ii); if ( !bAppendLeftOverBytes ) { if ( nNoOfLeftOverBytes > 0 ) { System.arraycopy( leftOverBytes, 0, buffer, 0, nNoOfLeftOverBytes ); System.arraycopy( line, 0, buffer, nNoOfLeftOverBytes, line.length ); line = buffer; } bAppendLeftOverBytes = false; } if ( line.length == 0 ) continue; /* enumerate through each char */ // for ( i = 0, ch = line[i]; ch != 0 && i < line.length; ch = line[++i] ) /* ---------------- old --------------------------- for ( i = 0; i < line.length; i++ ) { ch = line[i]; if ( ( ch >= 33 && ch <= 60 ) || ( ch >= 62 && ch <= 126 ) || ( ch == 9 || ch == 32 ) ) { output[j++] = ch; } else if ( ch == '=' ) { if ( i + 2 < line.length ) { output[j++] = nConvertHexToDec( line[++i], line[++i] ); } // get more data else if ( ii < nEnd ) { int len2 = line.length - i - 1; System.arraycopy( line, i, buffer, 0, len2 ); line = (byte[]) v.elementAt(++ii); System.arraycopy( line, 0, buffer, len2, line.length ); line = buffer; i = -1; } // save it for next time else { leftOverBytes[0] = ch; nNoOfLeftOverBytes = 1; if ( i+1 < line.length ) leftOverBytes[1] = ch; nNoOfLeftOverBytes = 2; } } } ----------- old ------------------------------------ */ /* -------------------------- new ---------------------*/ for ( i = 0; i < line.length; ) { ch = line[i++]; if (ch == '=') { if ( i < line.length && ( line[i] == '\n' || line[i] == '\r' ) ) { // Rule #5 i++; if ( i < line.length && line[i-1] == '\r' && line[i] == '\n') i++; } else if ( i + 1 < line.length ) // Rule #1 { hi = Character.digit( (char) line[i], 16); lo = Character.digit( (char) line[i+1], 16); if ( hi < 0 ) hi = 0; if ( lo < 0 ) lo = 0; { ch2 = (byte) (hi << 4 | lo); i += 2; } output[j++] = ch2; } // get more data else if ( ii < nEnd ) { int len2 = line.length - i; System.arraycopy( line, i, buffer, 0, len2 ); line = (byte[]) v.elementAt(++ii); System.arraycopy( line, 0, buffer, len2, line.length ); line = buffer; } last = j; } else if (ch == '\n' || ch == '\r') // Rule #4 { if ( ch == '\n' && i >= line.length - 1 && i >= 3 && line[i-3] != '=' ) { output[last++] = 10; } else if ( ch == '\r' ) { if ( i < line.length && line[i-1] == '\r' && line[i] == '\n') i++; output[last++] = 13; } /* for ( k = 0; k < nl.length; k++ ) { output[last++] = (byte) nl[k]; } */ j = last; } else // Rule #1, #2 { output[j++] = ch; if (ch != ' ' && ch != '\t') // Rule #3 last = j; } // if (j > output.length-5) // output = Util.outputizeArray(output, output.length+500); } /*-------------------------------------------------------------- */ } param[0] = nNoOfLeftOverBytes; param[1] = j; buffer = null; return output; } /** * Base64 Decodes data from InputStream and writes to OutputStream. * @param input InputStream that supplies the data to be decoded. * @param output OutputStream that accepts the decoded data. * @exception MIMEException If a decoding error occurs. * return Number of decoded bytes */ protected static byte[] decodeBase64Vector( Vector v, int nStart, int nEnd, int nMessageLen, int param[] ) throws MIMEException { int add_bits; int mask; int out_byte = 0; int out_bits = 0; int byte_pos = 0; int i, j, nLen = 0, nTotalLen = 0; byte[] szLine; byte[] output; if ( v == null || param == null ) throw new MIMEException( szERROR_BAD_PARAMETER ); // restore previous state out_byte = param[0]; out_bits = param[1]; // invalid range if ( nStart == -1 || nEnd == -1 ) return null; // get message len for ( j = nStart; j <= nEnd; j++ ) { szLine = (byte[]) v.elementAt( j ); nTotalLen = nTotalLen + szLine.length; } output = new byte[ nTotalLen ]; if ( output == null ) throw new MIMEException( szERROR_OUT_OF_MEMORY ); // read off data from vector line by line for ( j = nStart; j <= nEnd; j++ ) { szLine = (byte[]) v.elementAt( j ); nLen = szLine.length; // process line for ( i = 0; i < nLen && szLine[i] != 0; i++ ) { add_bits = Base64DecMap[(char) szLine[i]]; if (add_bits >= 64) continue; out_byte = (out_byte << 6) + add_bits; out_bits += 6; // If the queue has gotten big enough, put into the buffer if (out_bits >= 24) { if ( byte_pos < nTotalLen - 3 ) { output[byte_pos++] = (byte) ( (out_byte & 0xFF0000) >> 16 ); output[byte_pos++] = (byte) ( (out_byte & 0x00FF00) >> 8 ); output[byte_pos++] = (byte) ( (out_byte & 0x0000FF) ); out_bits = 0; out_byte = 0; } else { System.out.println( "byte_pos = " + byte_pos ); break; } } } } // save current state param[0] = out_byte; param[1] = out_bits; param[2] = byte_pos; return output; } protected static byte[] decodeBase64LeftOverBytes( int out_bits, int out_byte ) { int mask; byte[] output = new byte[4]; int byte_pos = 0; /* Handle any bits still in the queue */ while (out_bits >= 8) { if (out_bits == 8) { output[byte_pos++] = (byte) out_byte; out_byte = 0; } else { mask = out_bits == 8 ? 0xFF : (0xFF << (out_bits - 8)); output[byte_pos++] = (byte) ( (out_byte & mask) >> (out_bits - 8) ); out_byte &= ~mask; } out_bits -= 8; } return byteSubstring( output, 0, byte_pos ); } /** * * Base64 Decodes data from InputStream and writes to OutputStream * @param input InputStream that supplies the data to be decoded. * @param output OutputStream that accepts the decoded data. * @exception MIMEException if a decoding error occurs. * return number of decoded bytes */ public static void decodeBase64( InputStream input, OutputStream output ) throws MIMEException { int add_bits; int mask; int out_byte = 0; int out_bits = 0; int byte_pos = 0; int i, nLen; if ( input == null || output == null ) throw new MIMEException( szERROR_BAD_PARAMETER ); try { /* Queue up relevant bits */ for ( i = 0, nLen = input.available(); i < nLen; i++ ) { add_bits = Base64DecMap[(char) input.read() ]; if (add_bits >= 64) continue; out_byte = (out_byte << 6) + add_bits; out_bits += 6; /* If the queue has gotten big enough, put into the buffer */ if (out_bits == 24) { output.write( (byte) ( (out_byte & 0xFF0000) >> 16 ) ); output.write( (byte) ( (out_byte & 0x00FF00) >> 8 ) ); output.write( (byte) ( (out_byte & 0x0000FF) ) ); byte_pos =+ 3; out_bits = 0; out_byte = 0; } } /* Handle any bits still in the queue */ while ( out_bits >= 8 ) { if (out_bits == 8) { output.write( (byte) out_byte ); byte_pos++; out_byte = 0; } else { mask = out_bits == 8 ? 0xFF : (0xFF << (out_bits - 8)); output.write( (byte) ( (out_byte & mask) >> (out_bits - 8) ) ); byte_pos++; out_byte &= ~mask; } out_bits -= 8; } } catch ( IOException e ) { throw new MIMEException ( e.getMessage() ); } return; } /* ------------------- utility functions ------------------ * determine if both strings are the same based on the length of the second string * case insensitive * clee, oct 6,97 * return TRUE if equale */ protected static boolean bStringEquals( String s1, String s2 ) { char ch; if ( s1 != null && s2 != null ) { int len = s2.length(); if ( len > s1.length() ) return false; for ( int i = 0; i < len; i++ ) { ch = s2.charAt(i); // lowercase if ( ch >= 97 ) { if ( s1.charAt(i) != ch && s1.charAt(i) != ( ch - 32 ) ) return false; } else if ( s1.charAt(i) != ch && s1.charAt(i) != ( ch + 32 ) ) return false; } return true; } return false; } /* ------------------- utility functions ------------------ * determine if both strings are the same based on the length of the second string * case insensitive * clee, oct 6,97 * return TRUE if equale */ protected static boolean bStringEquals( byte s1[], String s2 ) { char ch; if ( s1 != null && s2 != null ) { int len = s2.length(); if ( len > s1.length ) return false; for ( int i = 0; i < len; i++ ) { ch = s2.charAt(i); // lowercase if ( ch >= 97 ) { if ( s1[i] != ch && s1[i] != ( ch - 32 ) ) return false; } else if ( s1[i] != ch && s1[i] != ( ch + 32 ) ) return false; } return true; } return false; } protected static boolean bStringEqualsLtrim( byte s1[], String s2 ) { char ch; if ( s1 != null && s2 != null ) { int j=0; int len = s2.length(); if ( len > s1.length ) return false; for (j = 0; j < len; j++) { if (s1[j] == '\n' || s1[j] == '\r' || s1[j] == '\t' || s1[j] == ' '); else { break; } } if (j > 0) { return (bStringEquals(j+1, s1, s2)); } for ( int i = 0; i < len; i++ ) { ch = s2.charAt(i); // lowercase if ( ch >= 97 ) { if ( s1[i] != ch && s1[i] != ( ch - 32 ) ) return false; } else if ( s1[i] != ch && s1[i] != ( ch + 32 ) ) return false; } return true; } return false; } /* ------------------- utility functions ------------------ * determine if both strings are the same based on the length of the second string * case insensitive * clee, oct 6,97 * return TRUE if equale */ protected static boolean bStringEquals( byte s1[], int s1_len, String s2 ) { char ch; if ( s1 != null && s2 != null ) { int len = s2.length(); if ( len > s1_len ) return false; for ( int i = 0; i < len; i++ ) { ch = s2.charAt(i); // lowercase if ( ch >= 97 ) { if ( s1[i] != ch && s1[i] != ( ch - 32 ) ) return false; } else if ( s1[i] != ch && s1[i] != ( ch + 32 ) ) return false; } return true; } return false; } /* ------------------- utility functions ------------------ * determine if both strings are the same based on the length of the second string * case insensitive * clee, oct 6,97 * return TRUE if equale */ protected static boolean bStringEquals( int offset, byte s1[], String s2 ) { char ch; if ( s1 != null && s2 != null ) { int len = s2.length(); if ( len > s1.length ) return false; for ( int i = 0; i < len; i++ ) { ch = s2.charAt(i); // lowercase if ( ch >= 97 ) { if ( s1[i+offset] != ch && s1[i+offset] != ( ch - 32 ) ) return false; } else if ( s1[i+offset] != ch && s1[i+offset] != ( ch + 32 ) ) return false; } return true; } return false; } /* ------------------- utility functions ------------------ * determine if both strings are the same based on the length of the second string * case insensitive * clee, oct 6,97 * return TRUE if equale */ protected static boolean bStringEquals( byte s1[], byte s2[] ) { char ch; if ( s2.length > s1.length ) return false; if ( s1 != null && s2 != null ) { for ( int i = 0; i < s2.length; i++ ) { // lowercase if ( s2[i] >= 97 ) { if ( s1[i] != s2[i] && s1[i] != ( s2[i] - 32 ) ) return false; } else if ( s1[i] != s2[i] && s1[i] != ( s2[i] + 32 ) ) return false; } return true; } return false; } protected static byte[] stringToByte( String s ) { return s.getBytes(); } protected static byte[] stringToByte( char[] s, int len ) { byte b[] = new byte[ len ]; for ( int i = 0; i < len; i++ ) b[i] = (byte) s[i]; return b; } protected static byte[] byteSubstring( byte[] s, int len ) { byte b[] = new byte[ len ]; for ( int i = 0; i < len; i++ ) b[i] = s[i]; return b; } protected static byte[] byteSubstring( byte[] s, int offset, int len ) { byte b[] = new byte[ len ]; for ( int i = 0, j = offset; i < len && j < s.length; i++, j++ ) b[i] = s[j]; return b; } //---------------------------------------------------------------------------------------- } // End class