Java/Email/Formatter

Материал из Java эксперт
Перейти к: навигация, поиск

Convert date information contained in Date into RFC2822 and UTC ("Zulu") strings

  
/*
 * Funambol is a mobile platform developed by Funambol, Inc. 
 * Copyright (C) 2003 - 2007 Funambol, Inc.
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission 
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE 
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Affero General Public License 
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 * 
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite 
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.ru.
 * 
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 * 
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably 
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */

import java.util.Calendar;
import java.util.Date;
import java.util.Hashtable;
/**
 * A utility class providing methods to convert date information contained in
 * <code>Date</code> objects into RFC2822 and UTC ("Zulu") strings, and to
 * build <code>Date</code> objects starting from string representations of
 * dates in RFC2822 and UTC format
 */
public class MailDateFormatter {
    
    /** Format date as: MM/DD */
    public static final int FORMAT_MONTH_DAY = 0;
    /** Format date as: MM/DD/YYYY */
    public static final int FORMAT_MONTH_DAY_YEAR = 1;
    /** Format date as: hh:mm */
    public static final int FORMAT_HOURS_MINUTES = 2;
    /** Format date as: hh:mm:ss */
    public static final int FORMAT_HOURS_MINUTES_SECONDS = 3;
    /** Format date as: DD/MM */
    public static final int FORMAT_DAY_MONTH = 4;
    /** Format date as: DD/MM/YYYY */
    public static final int FORMAT_DAY_MONTH_YEAR = 5;
    
    /** Device offset, as string */
    private static String deviceOffset = "+0000";
    /** Device offset, in millis */
    private static long millisDeviceOffset = 0;
    /** Names of the months */
    private static String[] monthNames = new String[] {
        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    };
     
    /**
     * Transforms data contained in a <code>Date</code> object (expressed in
     * UTC) in a string formatted as per RFC2822 in local time (par. 3.3)
     *
     * @return A string representing the date contained in the passed
     *         <code>Date</code> object formatted as per RFC 2822 and in local
     *         time
     */
    public static String dateToRfc2822(Date date) {
        
        Calendar deviceTime = Calendar.getInstance();
        deviceTime.setTime(date);
   
        String dayweek = "";
        int dayOfWeek = deviceTime.get(deviceTime.DAY_OF_WEEK);
        switch (dayOfWeek) {
            case 1 : dayweek = "Sun"; break;
            case 2 : dayweek = "Mon"; break;
            case 3 : dayweek = "Tue"; break;
            case 4 : dayweek = "Wed"; break;
            case 5 : dayweek = "Thu"; break;
            case 6 : dayweek = "Fri"; break;
            case 7 : dayweek = "Sat"; break;
        }
        
        int dayOfMonth = deviceTime.get(deviceTime.DAY_OF_MONTH);
        
        String monthInYear = getMonthName(deviceTime.get(deviceTime.MONTH));
        
        int year = deviceTime.get(deviceTime.YEAR);
        int hourOfDay = deviceTime.get(deviceTime.HOUR_OF_DAY);
        int minutes = deviceTime.get(deviceTime.MINUTE);
        int seconds = deviceTime.get(deviceTime.SECOND);
        
        String rfc = dayweek + ", " +                                   // Tue
                dayOfMonth + " " +                                      // 7
                monthInYear + " " +                                     // Nov
                year + " " +                                            // 2006
                hourOfDay + ":" + minutes + ":" + seconds + " " +       // 14:13:26
                deviceOffset;                                           //+0200  
        return rfc;
    }
    
    
    /**
     * Converts a <code>Date</code> object into a string in "Zulu" format
     *
     * @param d
     *            A <code>Date</code> object to be converted into a string in
     *            "Zulu" format
     * @return A string representing the date contained in the passed
     *         <code>Date</code> object in "Zulu" format (e.g.
     *         yyyyMMDDThhmmssZ)
     */
    public static String dateToUTC(Date d) {
        StringBuffer date = new StringBuffer();
        Calendar cal = Calendar.getInstance();
        cal.setTime(d);
        
        date.append(cal.get(Calendar.YEAR));
        
        date.append(printTwoDigits(cal.get(Calendar.MONTH) + 1))
            .append(printTwoDigits(cal.get(Calendar.DATE)))
            .append("T");
        
        date.append(printTwoDigits(cal.get(Calendar.HOUR_OF_DAY)))
            .append(printTwoDigits(cal.get(Calendar.MINUTE)))
            .append(printTwoDigits(cal.get(Calendar.SECOND)))
            .append("Z");
        
        return date.toString();
    }
    
    
    /**
     * A method that returns a string rapresenting a date.
     *
     * @param date the date
     *
     * @param format the format as one of
     * FORMAT_MONTH_DAY,
     * FORMAT_MONTH_DAY_YEAR,
     * FORMAT_HOURS_MINUTES,
     * FORMAT_HOURS_MINUTES_SECONDS
     * FORMAT_DAY_MONTH
     * FORMAT_DAY_MONTH_YEAR
     * constants
     *
     * @param separator the separator to be used
     */
    public static String getFormattedStringFromDate(
            Date date, int format, String separator) {
        
        Calendar cal=Calendar.getInstance();
        cal.setTime(date);
        StringBuffer ret = new StringBuffer();
        
        switch (format) {
            case FORMAT_HOURS_MINUTES:
                //if pm and hour == 0 we want to write 12, not 0
                if (cal.get(Calendar.AM_PM)==Calendar.PM
                        && cal.get(Calendar.HOUR) == 0) {
                    ret.append("12");
                } else {
                    ret.append(cal.get(Calendar.HOUR));
                }
                ret.append(separator)
                    .append(printTwoDigits(cal.get(Calendar.MINUTE)))
                    .append(getAMPM(cal));
                break;
                
            case FORMAT_HOURS_MINUTES_SECONDS:
                //if pm and hour == 0 we want to write 12, not 0
                if (cal.get(Calendar.AM_PM)==Calendar.PM
                        && cal.get(Calendar.HOUR) == 0) {
                    ret.append("12");
                } else {
                    ret.append(cal.get(Calendar.HOUR));
                }
                ret.append(separator)
                    .append(printTwoDigits(cal.get(Calendar.MINUTE)))
                    .append(separator)
                    .append(cal.get(Calendar.SECOND))
                    .append(getAMPM(cal));
                break;
                
            case FORMAT_MONTH_DAY:
                ret.append(cal.get(Calendar.MONTH)+1)
                    .append(separator)
                    .append(cal.get(Calendar.DAY_OF_MONTH));
                break;
                
            case FORMAT_DAY_MONTH:
                ret.append(cal.get(Calendar.DAY_OF_MONTH))
                    .append(separator)
                    .append(cal.get(Calendar.MONTH)+1);
                break;
                
            case FORMAT_MONTH_DAY_YEAR:
                ret.append(cal.get(Calendar.MONTH)+1)
                    .append(separator)
                    .append(cal.get(Calendar.DAY_OF_MONTH))
                    .append(separator)
                    .append(cal.get(Calendar.YEAR));
                break;
                
            case FORMAT_DAY_MONTH_YEAR:
                ret.append(cal.get(Calendar.DAY_OF_MONTH))
                    .append(separator)
                    .append(cal.get(Calendar.MONTH)+1)
                    .append(separator)
                    .append(cal.get(Calendar.YEAR));
                break;
                
            default:
              //  Log.error("getFormattedStringFromDate: invalid format ("+
                //        format+")");
        }
        
        return ret.toString();
    }
    
    /**
     * Returns a localized string representation of Date.
     */
    public static String formatLocalTime(Date d) {
        int dateFormat = FORMAT_MONTH_DAY_YEAR;
        int timeFormat = FORMAT_HOURS_MINUTES;
        
        if(!System.getProperty("microedition.locale").equals("en")) {
            dateFormat = FORMAT_DAY_MONTH_YEAR;
        }
        return getFormattedStringFromDate(d,FORMAT_MONTH_DAY_YEAR,"/")
                +" "+getFormattedStringFromDate(d,FORMAT_HOURS_MINUTES,":");
    }
    
    
    /**
     * Parses the string in RFC 2822 format and return a <code>Date</code>
     * object. <p>
     * Parse strings like:
     * Thu, 03 May 2007 14:45:38 GMT
     * Thu, 03 May 2007 14:45:38 GMT+0200
     * Thu,  1 Feb 2007 03:57:01 -0800
     * Fri, 04 May 2007 13:40:17 PDT
     * 
     * @param d the date representation to parse
     * @return a date, if valid, or null on error
     *
     */
    public static Date parseRfc2822Date(String stringDate) {
        if (stringDate == null) {
            return null;
        }
        
        long hourOffset=0;
        long minOffset=0;
        Calendar cal = Calendar.getInstance();
        
        try {
            
            // We use the " " as separator and we expect only one space. We
            // clean the string to remove extra spaces
            StringBuffer cleanedDate = new StringBuffer();
            char previous = "a";
            for(int i=0;i<stringDate.length();++i) {
                char ch = stringDate.charAt(i);
                if (ch != " " || previous != " ") {
                    cleanedDate.append(ch);
                }
                previous = ch;
            }
            stringDate = cleanedDate.toString();
           // Log.debug("Cleaned date: " + stringDate);
            
            // Just skip the weekday if present
            int start = stringDate.indexOf(",");
            //put start after ", "
            start = (start == -1) ? 0 : start + 2;
            
            stringDate = stringDate.substring(start).trim();
            start = 0;
            
            // Get day of month
            int end = stringDate.indexOf(" ", start);
           
            //4  Nov 2008 10:30:05 -0400
            
            int day =1;
            try {
               day = Integer.parseInt(stringDate.substring(start, end)); 
            } catch (NumberFormatException ex) {
                day = Integer.parseInt(stringDate.substring(start+3, end));
            }
            
            cal.set(Calendar.DAY_OF_MONTH,day);
            
            // Get month
            start = end + 1;
            end = stringDate.indexOf(" ", start);
            cal.set(Calendar.MONTH, getMonthNumber(stringDate.substring(start, end)));
            // Get year
            start = end + 1;
            end = stringDate.indexOf(" ", start);
            cal.set(Calendar.YEAR,
                    Integer.parseInt(stringDate.substring(start, end)));
            // Get hour
            start = end + 1;
            end = stringDate.indexOf(":", start);
            cal.set(Calendar.HOUR_OF_DAY,
                    Integer.parseInt(stringDate.substring(start, end).trim()));
            // Get min
            start = end + 1;
            end = stringDate.indexOf(":", start);
            cal.set(Calendar.MINUTE,
                    Integer.parseInt(stringDate.substring(start, end)));
            // Get sec
            start = end + 1;
            end = stringDate.indexOf(" ", start);
            cal.set(Calendar.SECOND,
                    Integer.parseInt(stringDate.substring(start, end)));
            // Get OFFSET
            start = end +1;
            end = stringDate.indexOf("\r", start);
            
            // Process Timezone, checking first for the actual RFC2822 format,
            // and then for nthe obsolete syntax.
            char sign = "+";
            String hourDiff = "0";
            String minDiff = "0";
            String offset = stringDate.substring(start).trim();
            if (offset.startsWith("+") || offset.startsWith("-")) {
                if(offset.length() >= 5 ){
                    sign = offset.charAt(0);
                    hourDiff = offset.substring(1,3);
                    minDiff = offset.substring(3,5);
                }
                else if(offset.length() == 3){
                    sign = offset.charAt(0);
                    hourDiff = offset.substring(1);
                    minDiff = "00";
                }
                // Convert offset to int
                hourOffset = Long.parseLong(hourDiff);
                minOffset = Long.parseLong(minDiff);
                if(sign == "-") {
                    hourOffset = -hourOffset;
                }
            }
            else if(offset.equals("EDT")){
                hourOffset = -4;
            }
            else if(offset.equals("EST") || offset.equals("CDT")){
                hourOffset = -5;
            }
            else if(offset.equals("CST") || offset.equals("MDT")){
                hourOffset = -6;
            }
            else if(offset.equals("PDT") || offset.equals("MST")){
                hourOffset = -7;
            }
            else if(offset.equals("PST")){
                hourOffset = -8;
            }
            else if(offset.equals("GMT") || offset.equals("UT")){
                hourOffset = 0;
            }
            else if (offset.substring(0,3).equals("GMT") && offset.length() > 3){
                sign = offset.charAt(3);
                hourDiff = offset.substring(4,6);
                minDiff = offset.substring(6,8);                
            }
            long millisOffset = (hourOffset * 3600000) + (minOffset * 60000);
     
            Date gmtDate = cal.getTime();
            long millisDate = gmtDate.getTime();
            
            millisDate -= millisOffset;
            
            gmtDate.setTime(millisDate);
            return gmtDate;
            
        } catch (Exception e) {
      
            e.printStackTrace();
            return null;
        }
    }
    
    /**
     * Convert the given date (GMT) into the local date.
     * NOTE: changes the original date too!
     * Should we change it to a void toLocalDate(Date) that changes the
     * input date only?
     */
    public static Date getDeviceLocalDate (Date gmtDate){
        if (null != gmtDate){
            /*long dateInMillis = gmtDate.getTime();
            Date deviceDate = new Date();
            deviceDate.setTime(dateInMillis+millisDeviceOffset);
            return deviceDate;
             **/
            gmtDate.setTime(gmtDate.getTime()+millisDeviceOffset);
            return gmtDate;
        }
        else {
            return null;
        }
    }
    
    
    /**
     * Gets a <code>Date</code> object from a string representing a date in
     * "Zulu" format (yyyyMMddTHHmmssZ)
     *
     * @param utc
     *            date in "Zulu" format (yyyyMMddTHHmmssZ)
     * @return A <code>Date</code> object obtained starting from a time in
     *         milliseconds from the Epoch
     */
    public static Date parseUTCDate(String utc) {
        
        int day = 0;
        int month = 0;
        int year = 0;
        int hour = 0;
        int minute = 0;
        int second = 0;
        Calendar calendar = null;
        
        day = Integer.parseInt(utc.substring(6, 8));
        month = Integer.parseInt(utc.substring(4, 6));
        year = Integer.parseInt(utc.substring(0, 4));
        hour = Integer.parseInt(utc.substring(9, 11));
        minute = Integer.parseInt(utc.substring(11, 13));
        second = Integer.parseInt(utc.substring(13, 15));
        
        
        calendar = Calendar.getInstance();
        
        calendar.set(Calendar.DAY_OF_MONTH, day);
        calendar.set(Calendar.MONTH, month - 1);
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        
        
        Date date = calendar.getTime();
        long dateInMillis = date.getTime();
            
        date.setTime(dateInMillis+millisDeviceOffset);
            
        return date;
    }
    
    public static void setTimeZone(String timeZone){
        
        if (timeZone == null || timeZone.length() < 5) {
           // Log.error("setTimeZone: invalid timezone " + timeZone);
        }
        try {
            deviceOffset = timeZone;
            String hstmz = deviceOffset.substring(1, 3);
            String mstmz = deviceOffset.substring(3, 5);
            
            long hhtmz = Long.parseLong(hstmz);
            long mmtmz = Long.parseLong(mstmz);
            millisDeviceOffset = (hhtmz * 3600000) + (mmtmz * 60000);
            if(deviceOffset.charAt(0)=="-") {
                millisDeviceOffset *= -1;
            }   
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * returns a date with string representation of the month
     * @param date input date in the format MM/DD/YYYY HH:MMp/a
     * @return a representation of the date in the format <MonthName> DD, YYYY HH:MM
     */
    public static String getReplyDateString(String date) {
        StringBuffer ret = new StringBuffer();
        //Replace the month number with the month name
        String monthName = getMonthName(
                Integer.parseInt(date.substring(0, date.indexOf("/")))-1
                );
        String day = date.substring(date.indexOf("/")+1, date.lastIndexOf("/"));
        String yearAndTime = date.substring(date.lastIndexOf("/")+1);
        
        ret.append(monthName).append(" ").append(day).append(", ").append(yearAndTime);
        //Replace the slash char between DD and YYYY with ", "
        return ret.toString();
    } 
    
    //------------------------------------------------------------- Private methods
    /**
     * Get the number of the month, given the name.
     */
    private static int getMonthNumber(String name) {
        for(int i=0, l=monthNames.length; i<l; i++) {
            if(monthNames[i].equals(name)) {
                return i;
            }
        }
        return -1;
    }
    /**
     * Get the name of the month, given the number.
     */
    private static String getMonthName(int number) {
        if(number>=0 && number<monthNames.length) {
            return monthNames[number];
        }
        else return null;
    }
    private static String getAMPM(Calendar cal) {
        return (cal.get(Calendar.AM_PM)==Calendar.AM)?"a":"p";
    }
    
    /**
     * Returns a string representation of number with at least 2 digits
     */
    private static String printTwoDigits(int number) {
        if (number>9) {
            return String.valueOf(number);
        } else {
            return "0"+number;
        }
    }
}





Convert lines into the canonical MIME format, that is, terminate lines with CRLF

 
/*
 * @(#)CRLFOutputStream.java  1.3 01/05/23
 *
 * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * 
 * - Redistribution 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.
 * 
 * Neither the name of Sun Microsystems, Inc. or the names of contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND
 * ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES
 * SUFFERED BY LICENSEE AS A RESULT OF  OR RELATING TO USE, MODIFICATION
 * OR DISTRIBUTION OF THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
 * FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
 * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
 * ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS
 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 * You acknowledge that Software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
 * Convert lines into the canonical MIME format, that is, terminate lines with
 * CRLF.
 * <p>
 * 
 * This stream can be used with the Part.writeTo and Message.writeTo methods to
 * generate the canonical MIME format of the data for the purpose of (e.g.)
 * sending it via SMTP or computing a digital signature.
 */
public class CRLFOutputStream extends FilterOutputStream {
  protected int lastb = -1;
  protected static byte[] newline;
  static {
    newline = new byte[2];
    newline[0] = (byte) "\r";
    newline[1] = (byte) "\n";
  }
  public CRLFOutputStream(OutputStream os) {
    super(os);
  }
  public void write(int b) throws IOException {
    if (b == "\r") {
      out.write(newline);
    } else if (b == "\n") {
      if (lastb != "\r")
        out.write(newline);
    } else {
      out.write(b);
    }
    lastb = b;
  }
  public void write(byte b[]) throws IOException {
    write(b, 0, b.length);
  }
  public void write(byte b[], int off, int len) throws IOException {
    int start = off;
    len += off;
    for (int i = start; i < len; i++) {
      if (b[i] == "\r") {
        out.write(b, start, i - start);
        out.write(newline);
        start = i + 1;
      } else if (b[i] == "\n") {
        if (lastb != "\r") {
          out.write(b, start, i - start);
          out.write(newline);
        }
        start = i + 1;
      }
      lastb = b[i];
    }
    if ((len - start) > 0)
      out.write(b, start, len - start);
  }
}





Convert the various newline conventions to the local platform"s newline convention

 
/*
 * @(#)NewlineOutputStream.java 1.3 01/05/23
 *
 * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * 
 * - Redistribution 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.
 * 
 * Neither the name of Sun Microsystems, Inc. or the names of contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND
 * ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES
 * SUFFERED BY LICENSEE AS A RESULT OF  OR RELATING TO USE, MODIFICATION
 * OR DISTRIBUTION OF THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
 * FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
 * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
 * ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS
 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 * You acknowledge that Software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
 * Convert the various newline conventions to the local platform"s newline
 * convention.
 * <p>
 * 
 * This stream can be used with the Message.writeTo method to generate a message
 * that uses the local plaform"s line terminator for the purpose of (e.g.)
 * saving the message to a local file.
 */
public class NewlineOutputStream extends FilterOutputStream {
  private int lastb = -1;
  private static byte[] newline;
  public NewlineOutputStream(OutputStream os) {
    super(os);
    if (newline == null) {
      String s = System.getProperty("line.separator");
      if (s == null || s.length() <= 0)
        s = "\n";
      newline = new byte[s.length()];
      s.getBytes(0, s.length(), newline, 0);
    }
  }
  public void write(int b) throws IOException {
    if (b == "\r") {
      out.write(newline);
    } else if (b == "\n") {
      if (lastb != "\r")
        out.write(newline);
    } else {
      out.write(b);
    }
    lastb = b;
  }
  public void write(byte b[]) throws IOException {
    write(b, 0, b.length);
  }
  public void write(byte b[], int off, int len) throws IOException {
    for (int i = 0; i < len; i++) {
      write(b[off + i]);
    }
  }
}