Hi

Bruno, thanks for the changes in the Font class.

This update fixes the problems with fonts with a BaseFont.
It is now possible to use fonts created with a BaseFont or using the 
FontFactory class.

Greetings,
Mark
/**
 * $Id: RtfWriter.java,v 1.22 2002/03/25 10:37:01 blowagie Exp $
 * $Name:  $
 *
 * Copyright 2001, 2002 by Mark Hall
 *
 * The contents of this file are subject to the Mozilla Public License Version 1.1
 * (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/MPL/
 *
 * 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 'iText, a free JAVA-PDF library'.
 *
 * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
 * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
 * All Rights Reserved.
 * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
 * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
 *
 * Contributor(s): all the names of the contributors are added in the source code
 * where applicable.
 *
 * Alternatively, the contents of this file may be used under the terms of the
 * LGPL license (the �GNU LIBRARY GENERAL PUBLIC LICENSE�), in which case the
 * provisions of LGPL are applicable instead of those above.  If you wish to
 * allow use of your version of this file only under the terms of the LGPL
 * License and not to allow others to use your version of this file under
 * the MPL, indicate your decision by deleting the provisions above and
 * replace them with the notice and other provisions required by the LGPL.
 * If you do not delete the provisions above, a recipient may use your version
 * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the MPL as stated above or under the terms of the GNU
 * Library General Public License as published by the Free Software Foundation;
 * either version 2 of the License, or any later version.
 *
 * This library 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 Library general Public License for more
 * details.
 *
 * If you didn't download this code from the following link, you should check if
 * you aren't using an obsolete version:
 * http://www.lowagie.com/iText/
 */

package com.lowagie.text.rtf;

import com.lowagie.text.*;

import java.io.*;
import java.util.*;
import java.awt.Color;
import java.text.SimpleDateFormat;
import java.text.ParsePosition;

/**
 * A <CODE>DocWriter</CODE> class for Rich Text Files (RTF).
 * <P>
 * A <CODE>RtfWriter</CODE> can be added as a <CODE>DocListener</CODE>
 * to a certain <CODE>Document</CODE> by getting an instance.
 * Every <CODE>Element</CODE> added to the original <CODE>Document</CODE>
 * will be written to the <CODE>OutputStream</CODE> of this <CODE>RtfWriter</CODE>.
 * <P>
 * Example:
 * <BLOCKQUOTE><PRE>
 * // creation of the document with a certain size and certain margins
 * Document document = new Document(PageSize.A4, 50, 50, 50, 50);
 * try {
 *    // this will write RTF to the Standard OutputStream
 *    <STRONG>RtfWriter.getInstance(document, System.out);</STRONG>
 *    // this will write Rtf to a file called text.rtf
 *    <STRONG>RtfWriter.getInstance(document, new 
FileOutputStream("text.rtf"));</STRONG>
 *    // this will write Rtf to for instance the OutputStream of a 
HttpServletResponse-object
 *    <STRONG>RtfWriter.getInstance(document, response.getOutputStream());</STRONG>
 * }
 * catch(DocumentException de) {
 *    System.err.println(de.getMessage());
 * }
 * // this will close the document and all the OutputStreams listening to it
 * <STRONG>document.close();</CODE>
 * </PRE></BLOCKQUOTE>
 * <P>
 * <STRONG>LIMITATIONS</STRONG><BR>
 * There are currently still a few limitations on what the RTF Writer can do:
 * <UL>
 *  <LI>Only PNG / JPEG Images are supported.</LI>
 *  <LI>Rotating of Images is not supported.</LI>
 *  <LI>Only one Header and one Footer are possible.</LI>
 *  <LI>Nested Tables are not supported.</LI>
 *  <LI>The <CODE>Leading</CODE> is not supported.</LI>
 * </UL>
 * <br />
 * Parts of this Class were contributed by Steffen Stundzig. Many thanks for the
 * improvements.
 */
public class RtfWriter extends DocWriter implements DocListener
{
  /**
   * Static Constants
   */
    
  /**
   * General
   */
    
  /** This is the escape character which introduces RTF tags. */
    public static final byte escape = (byte) '\\';

  /** This is another escape character which introduces RTF tags. */
    private static final byte[] extendedEscape = "\\*\\".getBytes();

  /** This is the delimiter between RTF tags and normal text. */
    protected static final byte delimiter = (byte) ' ';

  /** This is another delimiter between RTF tags and normal text. */
    private static final byte commaDelimiter = (byte) ';';

  /** This is the character for beginning a new group. */
    public static final byte openGroup = (byte) '{';
    
  /** This is the character for closing a group. */
    public static final byte closeGroup = (byte) '}';
    
  /**
   * RTF Information
   */
    
  /** RTF begin and version. */
    private static final byte[] docBegin = "rtf1".getBytes();
    
  /** RTF encoding. */
    private static final byte[] ansi = "ansi".getBytes();
    
  /** RTF encoding codepage. */
    private static final byte[] ansiCodepage = "ansicpg".getBytes();
    
  /**
   *Font Data
   */
    
  /** Begin the font table tag. */
    private static final byte[] fontTable = "fonttbl".getBytes();
    
  /** Font number tag. */
    protected static final byte fontNumber = (byte) 'f';
    
  /** Font size tag. */
    protected static final byte[] fontSize = "fs".getBytes();

  /** Font color tag. */
    protected static final byte[] fontColor = "cf".getBytes();
    
  /** Modern font tag. */
    private static final byte[] fontModern = "fmodern".getBytes();
    
  /** Swiss font tag. */
    private static final byte[] fontSwiss = "fswiss".getBytes();
    
  /** Roman font tag. */
    private static final byte[] fontRoman = "froman".getBytes();
    
  /** Tech font tag. */
    private static final byte[] fontTech = "ftech".getBytes();
    
  /** Font charset tag. */
    private static final byte[] fontCharset = "fcharset".getBytes();
    
  /** Font Courier tag. */
    private static final byte[] fontCourier = "Courier".getBytes();
    
  /** Font Arial tag. */
    private static final byte[] fontArial = "Arial".getBytes();
    
  /** Font Symbol tag. */
    private static final byte[] fontSymbol = "Symbol".getBytes();
    
  /** Font Times New Roman tag. */
    private static final byte[] fontTimesNewRoman = "Times New Roman".getBytes();
    
  /** Font Windings tag. */
    private static final byte[] fontWindings = "Windings".getBytes();
    
  /** Default Font. */
    private static final byte[] defaultFont = "deff".getBytes();
    
  /** First indent tag. */
    private static final byte[] firstIndent = "fi".getBytes();
    
  /** List indent tag. */
    private static final byte[] listIndent = "li".getBytes();
    
  /**
   * Sections / Paragraphs
   */
    
  /** Reset section defaults tag. */
    private static final byte[] sectionDefaults = "sectd".getBytes();
    
  /** Begin new section tag. */
    private static final byte[] section = "sect".getBytes();

  /** Reset paragraph defaults tag. */
    public static final byte[] paragraphDefaults = "pard".getBytes();

  /** Begin new paragraph tag. */
    public static final byte[] paragraph = "par".getBytes();
    
  /**
   * Lists
   */

  /** Begin the List Table */
    private static final byte[] listtableGroup = "listtable".getBytes();
    
  /** Begin the List Override Table */
    private static final byte[] listoverridetableGroup = 
"listoverridetable".getBytes();
    
  /** Begin a List definition */
    private static final byte[] listDefinition = "list".getBytes();
    
  /** List Template ID */
    private static final byte[] listTemplateID = "listtemplateid".getBytes();
    
  /** RTF Writer outputs hybrid lists */
    private static final byte[] hybridList = "hybrid".getBytes();
    
  /** Current List level */
    private static final byte[] listLevelDefinition = "listlevel".getBytes();
    
  /** Level numbering (old) */
    private static final byte[] listLevelTypeOld = "levelnfc".getBytes();
    
  /** Level numbering (new) */
    private static final byte[] listLevelTypeNew = "levelnfcn".getBytes();
    
  /** Level alignment (old) */
    private static final byte[] listLevelAlignOld = "leveljc".getBytes();
    
  /** Level alignment (new) */
    private static final byte[] listLevelAlignNew = "leveljcn".getBytes();
    
  /** Level starting number */
    private static final byte[] listLevelStartAt = "levelstartat".getBytes();
    
  /** Level text group */
    private static final byte[] listLevelTextDefinition = "leveltext".getBytes();
    
  /** Filler for Level Text Length */
    private static final byte[] listLevelTextLength = "\'0".getBytes();
    
  /** Level Text Numbering Style */
    private static final byte[] listLevelTextStyleNumbers = "\'00.".getBytes();
    
  /** Level Text Bullet Style */
    private static final byte[] listLevelTextStyleBullet = "u-3913 ?".getBytes();
    
  /** Level Numbers Definition */
    private static final byte[] listLevelNumbersDefinition = "levelnumbers".getBytes();
    
  /** Filler for Level Numbers */
    private static final byte[] listLevelNumbers = "\\'0".getBytes();
    
  /** Tab Stop */
    private static final byte[] tabStop = "tx".getBytes();
    
  /** Actual list begin */
    private static final byte[] listBegin = "ls".getBytes();
    
  /** Current list level */
    private static final byte[] listCurrentLevel = "ilvl".getBytes();
    
  /** List text group for older browsers */
    private static final byte[] listTextOld = "listtext".getBytes();
    
  /** Tab */
    private static final byte[] tab = "tab".getBytes();
    
  /** Old Bullet Style */
    private static final byte[] listBulletOld = "\'b7".getBytes();
    
  /** Current List ID */
    private static final byte[] listID = "listid".getBytes();

  /** List override */
    private static final byte[] listOverride = "listoverride".getBytes();

  /** Number of overrides */
    private static final byte[] listOverrideCount = "listoverridecount".getBytes();
    
  /**
   * Text Style
   */
    
  /** Bold tag. */
    protected static final byte bold = (byte) 'b';
    
  /** Italic tag. */
    protected static final byte italic = (byte) 'i';
    
  /** Underline tag. */
    protected static final byte[] underline = "ul".getBytes();
    
  /** Strikethrough tag. */
    protected static final byte[] strikethrough = "strike".getBytes();
    
  /** Text alignment left tag. */
    public static final byte[] alignLeft = "ql".getBytes();
    
  /** Text alignment center tag. */
    private static final byte[] alignCenter = "qc".getBytes();
    
  /** Text alignment right tag. */
    private static final byte[] alignRight = "qr".getBytes();
    
  /** Text alignment justify tag. */
    private static final byte[] alignJustify = "qj".getBytes();
    
  /**
   * Colors
   */
    
  /** Begin colour table tag. */
    private static final byte[] colorTable = "colortbl".getBytes();

  /** Red value tag. */
    private static final byte[] colorRed = "red".getBytes();

  /** Green value tag. */
    private static final byte[] colorGreen = "green".getBytes();

  /** Blue value tag. */
    private static final byte[] colorBlue = "blue".getBytes();
    
  /**
   * Information Group
   */
    
  /** Begin the info group tag.*/
    private static final byte[] infoBegin = "info".getBytes();

  /** Author tag. */
    private static final byte[] metaAuthor = "author".getBytes();
    
  /** Subject tag. */
    private static final byte[] metaSubject = "subject".getBytes();
    
  /** Keywords tag. */
    private static final byte[] metaKeywords = "keywords".getBytes();
    
  /** Title tag. */
    private static final byte[] metaTitle = "title".getBytes();
    
  /** Producer tag. */
    private static final byte[] metaProducer = "operator".getBytes();

  /** Creation Date tag. */
    private static final byte[] metaCreationDate = "creationdate".getBytes();

  /** Year tag. */
    private static final byte[] year = "yr".getBytes();

  /** Month tag. */
    private static final byte[] month = "mo".getBytes();

  /** Day tag. */
    private static final byte[] day = "dy".getBytes();

  /** Hour tag. */
    private static final byte[] hour = "hr".getBytes();

  /** Minute tag. */
    private static final byte[] minute = "min".getBytes();

  /** Second tag. */
    private static final byte[] second = "sec".getBytes();

  /**
   * Header / Footer
   */

  /** Title Page tag */
    private static final byte[] titlePage = "titlepg".getBytes();

  /** Begin header group tag. */
    private static final byte[] headerBegin = "header".getBytes();

  /** Begin footer group tag. */
    private static final byte[] footerBegin = "footer".getBytes();

    // header footer 'left', 'right', 'first'
    private static final byte[] headerlBegin = "headerl".getBytes();

    private static final byte[] footerlBegin = "footerl".getBytes();

    private static final byte[] headerrBegin = "headerr".getBytes();

    private static final byte[] footerrBegin = "footerr".getBytes();

    private static final byte[] headerfBegin = "headerf".getBytes();

    private static final byte[] footerfBegin = "footerf".getBytes();

  /**
   * Paper Properties
   */
    
  /** Paper width tag. */
    private static final byte[] rtfPaperWidth = "paperw".getBytes();

  /** Paper height tag. */
    private static final byte[] rtfPaperHeight = "paperh".getBytes();

  /** Margin left tag. */
    private static final byte[] rtfMarginLeft = "margl".getBytes();
    
  /** Margin right tag. */
    private static final byte[] rtfMarginRight = "margr".getBytes();
    
  /** Margin top tag. */
    private static final byte[] rtfMarginTop = "margt".getBytes();
    
  /** Margin bottom tag. */
    private static final byte[] rtfMarginBottom = "margb".getBytes();

  /** New Page tag. */
    private static final byte[] newPage = "page".getBytes();
    
  /**
   * Annotations
   */
    
  /** Annotation ID tag. */
    private static final byte[] annotationID = "atnid".getBytes();
    
  /** Annotation Author tag. */
    private static final byte[] annotationAuthor = "atnauthor".getBytes();
    
  /** Annotation text tag. */
    private static final byte[] annotation = "annotation".getBytes();
    
  /**
   * Images
   */
    
  /** Begin the main Picture group tag */
    private static final byte[] pictureGroup = "shppict".getBytes();
    
  /** Begin the picture tag */
    private static final byte[] picture = "pict".getBytes();

  /** PNG Image */
    private static final byte[] picturePNG = "pngblip".getBytes();

  /** JPEG Image */
    private static final byte[] pictureJPEG = "jpegblip".getBytes();

  /** Picture width */
    private static final byte[] pictureWidth = "picw".getBytes();
    
  /** Picture height */
    private static final byte[] pictureHeight = "pich".getBytes();
    
  /** Picture width after scaling */
    private static final byte[] pictureIntendedWidth = "picwgoal".getBytes();

  /** Picture height after scaling */
    private static final byte[] pictureIntendedHeight = "pichgoal".getBytes();
    
  /** Picture scale horizontal percent */
    private static final byte[] pictureScaleX = "picscalex".getBytes();

  /** Picture scale vertical percent */
    private static final byte[] pictureScaleY = "picscaley".getBytes();
    
  /**
   * Fields (for page numbering)
   */
    
  /** Begin field tag */
    protected static final byte[] field = "field".getBytes();
    
  /** Content fo the field */
    protected static final byte[] fieldContent = "fldinst".getBytes();
    
  /** PAGE numbers */
    protected static final byte[] fieldPage = "PAGE".getBytes();
    
  /** HYPERLINK field */
    protected static final byte[] fieldHyperlink = "HYPERLINK".getBytes();
    
  /** Last page number (not used) */
    protected static final byte[] fieldDisplay = "fldrslt".getBytes();
    
    
  /** Class variables */
    
  /**
   * Because of the way RTF works and the way itext works, the text has to be
   * stored and is only written to the actual OutputStream at the end.
   */
    
  /** This <code>Vector</code> contains all fonts used in the document. */
    private Vector fontList = new Vector();
    
  /** This <code>Vector</code> contains all colours used in the document. */
    private Vector colorList = new Vector();
    
  /** This <code>ByteArrayOutputStream</code> contains the main body of the document. 
*/
    private ByteArrayOutputStream content = null;
    
  /** This <code>ByteArrayOutputStream</code> contains the information group. */
    private ByteArrayOutputStream info = null;
    
  /** This <code>ByteArrayOutputStream</code> contains the list table. */
    private ByteArrayOutputStream listtable = null;
    
  /** This <code>ByteArrayOutputStream</code> contains the list override table. */
    private ByteArrayOutputStream listoverride = null;
    
  /** Which font is currently being used. */
    private int listFont = 0;
    
  /** Document header. */
    private HeaderFooter header = null;
    
  /** Document footer. */
    private HeaderFooter footer = null;
    
  /** Left margin. */
    private int marginLeft = 1800;
    
  /** Right margin. */
    private int marginRight = 1800;
    
  /** Top margin. */
    private int marginTop = 1440;
    
  /** Bottom margin. */
    private int marginBottom = 1440;

  /** Page width. */
    private int pageWidth = 12240;
    
  /** Page height. */
    private int pageHeight = 15840;
    
  /** Factor to use when converting. */
    public final static double twipsFactor = 20.57140;
    
  /** Current annotation ID. */
    private int currentAnnotationID = 0;
    
  /** Current list ID. */
    private int currentListID = 1;
    
  /** List of current Lists. */
    private Vector listIds = null;

  /** Current List Level. */
    private int listLevel = 0;

  /** Current maximum List Level. */
    private int maxListLevel = 0;

  /** Write a TOC */
    private boolean writeTOC = false;

  /** Special title page */
    private boolean hasTitlePage = false;


  /** Protected Constructor */

  /**
   * Constructs a <CODE>RtfWriter</CODE>.
   *
   * @param document    The <CODE>Document</CODE> that is to be written as RTF
   * @param os          The <CODE>OutputStream</CODE> the writer has to write to.
   */

    protected RtfWriter(Document doc, OutputStream os)
    {
        super(doc, os);
        document.addDocListener(this);
        initDefaults();
    }

  /** Public functions special to the RtfWriter */

  /**
   * This method controls whether TOC entries are automatically generated
   *
   * @param writeTOC    boolean value indicating whether a TOC is to be generated
   */
  public void setGenerateTOCEntries(boolean writeTOC)
  {
    this.writeTOC = writeTOC;
  }

  /**
   * Gets the current setting of writeTOC
   *
   * @return    boolean value indicating whether a TOC is being generated
   */
  public boolean getGeneratingTOCEntries()
  {
    return writeTOC;
  }

  /**
   * This method controls whether the first page is a title page
   *
   * @param writeTOC    boolean value indicating whether the first page is a title page
   */
  public void setHasTitlePage(boolean hasTitlePage)
  {
    this.hasTitlePage = hasTitlePage;
  }

  /**
   * Gets the current setting of hasTitlePage
   *
   * @return    boolean value indicating whether the first page is a title page
   */
  public boolean getHasTitlePage()
  {
    return hasTitlePage;
  }

  /** Public functions from the DocWriter Interface */

  /**
   * Gets an instance of the <CODE>RtfWriter</CODE>.
   *
   * @param document    The <CODE>Document</CODE> that has to be written
   * @param os  The <CODE>OutputStream</CODE> the writer has to write to.
   * @return    a new <CODE>RtfWriter</CODE>
   */
    public static RtfWriter getInstance(Document document, OutputStream os)
    {
        return(new RtfWriter(document, os));
    }

  /**
   * Signals that the <CODE>Document</CODE> has been opened and that
   * <CODE>Elements</CODE> can be added.
   */
    public void open()
    {
        super.open();
    }
    
  /**
   * Signals that the <CODE>Document</CODE> was closed and that no other
   * <CODE>Elements</CODE> will be added.
   * <p>
   * The content of the font table, color table, information group, content, header, 
footer are merged into the final
   * <code>OutputStream</code>
   */
    public void close()
    {
        writeDocument();
        super.close();
    }
    
  /**
   * Adds the footer to the bottom of the <CODE>Document</CODE>.
   */
    public void setFooter(HeaderFooter footer)
    {
        this.footer = footer;
    }
    
  /**
   * Adds the header to the top of the <CODE>Document</CODE>.
   */
    public void setHeader(HeaderFooter header)
    {
        this.header = header;
    }
    
  /**
   * Resets the footer.
   */
    public void resetFooter()
    {
        setFooter(null);
    }
    
  /**
   * Resets the header.
   */
    public void resetHeader()
    {
        setHeader(null);
    }
    
  /**
   * Tells the <code>RtfWriter</code> that a new page is to be begun.
   *
   * @return <code>true</code> if a new Page was begun.
   * @throws DocumentException if the Document was not open or had been closed.
   */
    public boolean newPage() throws DocumentException
    {
        try
        {
            content.write(escape);
            content.write(newPage);
        }
        catch(IOException e)
        {
            return false;
        }
        return true;
    }
    
  /**
   * Sets the page margins
   *
   * @param marginLeft The left margin
   * @param marginRight The right margin
   * @param marginTop The top margin
   * @param marginBottom The bottom margin
   *
   * @return <code>true</code> if the page margins were set.
   */
    public boolean setMargins(float marginLeft, float marginRight, float marginTop, 
float marginBottom)
    {
        this.marginLeft = (int) (marginLeft * twipsFactor);
        this.marginRight = (int) (marginRight * twipsFactor);
        this.marginTop = (int) (marginTop * twipsFactor);
        this.marginBottom = (int) (marginBottom * twipsFactor);
        return true;
    }
    
  /**
   * Sets the page size
   *
   * @param pageSize A <code>Rectangle</code> specifying the page size
   *
   * @return <code>true</code> if the page size was set
   */
    public boolean setPageSize(Rectangle pageSize)
    {
        pageWidth = (int) (pageSize.width() * twipsFactor);
        pageHeight = (int) (pageSize.height() * twipsFactor);
        return true;
    }

  /**
   * Sets the page margins
   *
   * @param tocTitle The title that will be displayed above the TOC
   * @param titleFont The <code>Font</code> that will be used for the tocTitle
   * @param showTOCasEntry Set this to true if you want the TOC to appear as an entry 
in the TOC
   * @param showTOCEntryFont Use this <code>Font</code> to specify what Font to use 
when showTOCasEntry is true
   *
   * @return <code>true</code> if the TOC was added.
   */
  public boolean writeTOC(String tocTitle, Font titleFont, boolean showTOCasEntry, 
Font showTOCEntryFont)
  {
    try
      {
        RtfTOC toc = new RtfTOC(tocTitle, titleFont);
        if(showTOCasEntry) { toc.addTOCAsTOCEntry(tocTitle, showTOCEntryFont); }
        add(new Paragraph(toc));
      }
    catch(DocumentException de) { return false; }
    return true;
  }
    
  /**
   * Signals that an <CODE>Element</CODE> was added to the <CODE>Document</CODE>.
   *
   * @return    <CODE>true</CODE> if the element was added, <CODE>false</CODE> if not.
   * @throws    DocumentException   if a document isn't open yet, or has been closed
   */
    public boolean add(Element element) throws DocumentException
    {
        return addElement(element, content);
    }
    

  /** Private functions */
    
  /**
   * Adds an <CODE>Element</CODE> to the <CODE>Document</CODE>.
   * @return    <CODE>true</CODE> if the element was added, <CODE>false</CODE> if not.
   * @throws    DocumentException   if a document isn't open yet, or has been closed
   */
    private boolean addElement(Element element, ByteArrayOutputStream out) throws 
DocumentException
    {
        try
        {
            switch(element.type())
            {
                case Element.CHUNK        : writeChunk((Chunk) element, out);          
      break;
                case Element.PARAGRAPH    : writeParagraph((Paragraph) element, out);  
      break;
                case Element.ANCHOR       : writeAnchor((Anchor) element, out);        
      break;
                case Element.PHRASE       : writePhrase((Phrase) element, out);        
      break;
                case Element.CHAPTER      :
                case Element.SECTION      : writeSection((Section) element, out);      
      break;
                case Element.LIST         : writeList((com.lowagie.text.List) element, 
out); break;
                case Element.TABLE        : writeTable((Table) element, out);          
        break;
                case Element.ANNOTATION   : writeAnnotation((Annotation) element, 
out);      break;
                case Element.PNG          :
                case Element.JPEG         : writeImage((Image) element, out);          
      break;
                
                case Element.AUTHOR       : writeMeta(metaAuthor, (Meta) element);     
  break;
                case Element.SUBJECT      : writeMeta(metaSubject, (Meta) element);    
  break;
                case Element.KEYWORDS     : writeMeta(metaKeywords, (Meta) element);   
  break;
                case Element.TITLE        : writeMeta(metaTitle, (Meta) element);      
  break;
                case Element.PRODUCER     : writeMeta(metaProducer, (Meta) element);   
  break;
                case Element.CREATIONDATE : writeMeta(metaCreationDate, (Meta) 
element); break;
            }
        }
        catch(IOException e)
        {
            return false;
        }
        return true;
    }
    
  /**
   * Write the beginning of a new <code>Section</code>
   *
   * @param sectionElement The <code>Section</code> be written
   * @param out The <code>ByteArrayOutputStream</code> to write to
   *
   * @throws IOException
   */
  private void writeSection(Section sectionElement, ByteArrayOutputStream out) throws 
IOException, DocumentException
    {
        if(sectionElement.type() == Element.CHAPTER)
          {
            out.write(escape);
            out.write(sectionDefaults);
          }
        if(sectionElement.title() != null)
        {
            if(writeTOC)
              {
                StringBuffer title = new StringBuffer("");
                for(ListIterator li = 
sectionElement.title().getChunks().listIterator(); li.hasNext();)
                  {
                    title.append(((Chunk) li.next()).content());
                  }
                add(new RtfTOCEntry(title.toString(), sectionElement.title().font()));
              }
            else
              {
                sectionElement.title().process(this);
              }
            out.write(escape);
            out.write(paragraph);
        }
        sectionElement.process(this);
        if(sectionElement.type() == Element.CHAPTER)
          {
            out.write(escape);
            out.write(section);
          }
        if(sectionElement.type() == Element.SECTION)
          {
            out.write(escape);
            out.write(paragraph);
          }
    }
    
  /**
   * Write the beginning of a new <code>Paragraph</code>
   *
   * <<<<<<< RtfWriter.java
   * @param paragraphElement The <code>Paragraph</code> to be written
   * @param out The <code>ByteArrayOutputStream</code> to write to
   *
   * @throws IOException, DocumentExceptipn
   */
    private void writeParagraph(Paragraph paragraphElement, ByteArrayOutputStream out) 
throws IOException, DocumentException
    {
        out.write(escape);
        out.write(paragraphDefaults);
        switch(paragraphElement.alignment())
        {
            case Element.ALIGN_LEFT      : out.write(escape); out.write(alignLeft); 
break;
            case Element.ALIGN_RIGHT     : out.write(escape); out.write(alignRight); 
break;
            case Element.ALIGN_CENTER    : out.write(escape); out.write(alignCenter); 
break;
            case Element.ALIGN_JUSTIFIED : out.write(escape); out.write(alignJustify); 
break;
        }
        out.write(escape);
        out.write(listIndent);
        writeInt(out, (int) (paragraphElement.indentationLeft() * twipsFactor));
        Iterator chunks = paragraphElement.getChunks().iterator();
        while(chunks.hasNext())
        {
            Chunk ch = (Chunk) chunks.next();
            ch.setFont(ch.font().difference(paragraphElement.font()));
        }
    paragraphElement.process(this);
        out.write(escape);
        out.write(paragraph);
    }
    
  /**
   * Write a <code>Phrase</code>.
   *
   * @param chunk The <code>Phrase</code> item to be written
   * @param out The <code>ByteArrayOutputStream</code> to write to
   *
   * @throws IOException, DocumentException
   */
    private void writePhrase(Phrase phrase, ByteArrayOutputStream out) throws 
IOException, DocumentException
    {
        out.write(escape);
        out.write(paragraphDefaults);
        Iterator chunks = phrase.getChunks().iterator();
        while(chunks.hasNext())
        {
            Chunk ch = (Chunk) chunks.next();
            ch.setFont(ch.font().difference(phrase.font()));
        }
      phrase.process(this);
    }

  /**
   * Write an <code>Anchor</code>. Anchors are treated like Phrases.
   *
   * @param chunk The <code>Chunk</code> item to be written
   * @param out The <code>ByteArrayOutputStream</code> to write to
   *
   * @throws IOException
   */
    private void writeAnchor(Anchor anchor, ByteArrayOutputStream out) throws 
IOException, DocumentException
    {
        if (anchor.url() != null) {
            out.write(openGroup);
            out.write(escape);
            out.write(field);
            out.write(openGroup);
            out.write(extendedEscape);
            out.write(fieldContent);
            out.write(openGroup);
            out.write(fieldHyperlink);
            out.write(delimiter);
            out.write(anchor.url().toString().getBytes());
            out.write(closeGroup);
            out.write(closeGroup);
            out.write(openGroup);
            out.write(escape);
            out.write(fieldDisplay);
            out.write(delimiter);
            writePhrase(anchor, out);
            out.write(closeGroup);
            out.write(closeGroup);
        }
        else {
            writePhrase(anchor, out);
        }
    }
    
  /**
   * Write a <code>Chunk</code> and all its font properties.
   *
   * @param chunk The <code>Chunk</code> item to be written
   * @param out The <code>ByteArrayOutputStream</code> to write to
   *
   * @throws IOException
   */
  private void writeChunk(Chunk chunk, ByteArrayOutputStream out) throws IOException, 
DocumentException
    {
        if (chunk instanceof RtfField) {
            ((RtfField)chunk).write( this, out );
        } else {
          if(chunk.getImage() != null)
          {
            writeImage(chunk.getImage(), out);
          }
          else
          {
            writeInitialFontSignature( out, chunk.font() );
            out.write( filterSpecialChar( chunk.content() ).getBytes() );
            writeFinishingFontSignature( out, chunk.font() );
          }
        }
    }


    protected void writeInitialFontSignature( OutputStream out, Font font ) throws 
IOException {
        out.write(escape);
        out.write(fontNumber);
        if (!font.getFamilyname().equalsIgnoreCase("unknown")) {
            writeInt(out, addFont( font ));
        } else {
            writeInt(out, 0);
        }
        out.write(escape);
        out.write(fontSize);
        if (font.size() > 0) {
            writeInt( out, (int)(font.size() * 2) );
        } else {
            writeInt(out, 20);
        }
        out.write(escape);
        out.write(fontColor);
        writeInt(out, addColor( font.color() ) );
        if (font.isBold()) {
            out.write(escape);
            out.write(bold);
        }
        if (font.isItalic()) {
            out.write(escape);
            out.write(italic);
        }
        if (font.isUnderlined()) {
            out.write(escape);
            out.write(underline);
        }
        if (font.isStrikethru()) {
            out.write(escape);
            out.write(strikethrough);
        }
        out.write( delimiter );
    }


    protected void writeFinishingFontSignature( OutputStream out, Font font ) throws 
IOException {
        if (font.isBold()) {
            out.write(escape);
            out.write(bold);
            writeInt(out, 0);
        }
        if (font.isItalic()) {
            out.write(escape);
            out.write(italic);
            writeInt(out, 0);
        }
        if (font.isUnderlined()) {
            out.write(escape);
            out.write(underline);
            writeInt(out, 0);
        }
        if (font.isStrikethru()) {
            out.write(escape);
            out.write(strikethrough);
            writeInt(out, 0);
        }
    }
  /**
   * Write a <code>ListItem</code>
   *
   * @param listItem The <code>ListItem</code> to be written
   * @param out The <code>ByteArrayOutputStream</code> to write to
   *
   * @throws IOException
   */
    private void writeListElement(ListItem listItem, ByteArrayOutputStream out) throws 
IOException, DocumentException
    {
        Iterator chunks = listItem.getChunks().iterator();
        while(chunks.hasNext())
        {
            Chunk ch = (Chunk) chunks.next();
            addElement(ch, out);
        }
        out.write(escape);
        out.write(paragraph);
    }
    
  /**
   * Write a <code>List</code>
   *
   * @param list The <code>List</code> to be written
   * @param out The <code>ByteArrayOutputStream</code> to write to
   *
   * @throws IOException, DocumentException
   */
    private void writeList(com.lowagie.text.List list, ByteArrayOutputStream out) 
throws IOException, DocumentException
    {
        int type = 0;
        int align = 0;
        int fontNr = addFont(new Font(Font.SYMBOL, 10, Font.NORMAL, new Color(0, 0, 
0)));
        if(!list.isNumbered()) type = 23;
        if(listLevel == 0)
        {
            maxListLevel = 0;
            listtable.write(openGroup);
            listtable.write(escape);
            listtable.write(listDefinition);
            int i = getRandomInt();
            listtable.write(escape);
            listtable.write(listTemplateID);
            writeInt(listtable, i);
            listtable.write(escape);
            listtable.write(hybridList);
            listtable.write((byte) '\n');
        }
        if(listLevel >= maxListLevel)
        {
            maxListLevel++;
            listtable.write(openGroup);
            listtable.write(escape);
            listtable.write(listLevelDefinition);
            listtable.write(escape);
            listtable.write(listLevelTypeOld);
            writeInt(listtable, type);
            listtable.write(escape);
            listtable.write(listLevelTypeNew);
            writeInt(listtable, type);
            listtable.write(escape);
            listtable.write(listLevelAlignOld);
            writeInt(listtable, align);
            listtable.write(escape);
            listtable.write(listLevelAlignNew);
            writeInt(listtable, align);
            listtable.write(escape);
            listtable.write(listLevelStartAt);
            writeInt(listtable, 1);
            listtable.write(openGroup);
            listtable.write(escape);
            listtable.write(listLevelTextDefinition);
            listtable.write(escape);
            listtable.write(listLevelTextLength);
            if(list.isNumbered()) { writeInt(listtable, 2); } else { 
writeInt(listtable, 1); }
            listtable.write(escape);
            if(list.isNumbered()) { listtable.write(listLevelTextStyleNumbers); } else 
{ listtable.write(listLevelTextStyleBullet); }
            listtable.write(commaDelimiter);
            listtable.write(closeGroup);
            listtable.write(openGroup);
            listtable.write(escape);
            listtable.write(listLevelNumbersDefinition);
            if(list.isNumbered()) { listtable.write(delimiter); 
listtable.write(listLevelNumbers); writeInt(listtable, listLevel + 1); }
            listtable.write(commaDelimiter);
            listtable.write(closeGroup);
            if(!list.isNumbered()) { listtable.write(escape); 
listtable.write(fontNumber); writeInt(listtable, fontNr); }
            listtable.write(escape);
            listtable.write(firstIndent);
            writeInt(listtable, (int) (list.indentationLeft() * twipsFactor * -1));
            listtable.write(escape);
            listtable.write(listIndent);
            writeInt(listtable, (int) ((list.indentationLeft() + list.symbolIndent()) 
* twipsFactor));
            listtable.write(escape);
            listtable.write(tabStop);
            writeInt(listtable, (int) (list.symbolIndent() * twipsFactor));
            listtable.write(closeGroup);
            listtable.write((byte) '\n');
        }
        // Actual List Begin in Content
        out.write(escape);
        out.write(paragraphDefaults);
        out.write(escape);
        out.write(alignLeft);
        out.write(escape);
        out.write(firstIndent);
        writeInt(out, (int) (list.indentationLeft() * twipsFactor * -1));
        out.write(escape);
        out.write(listIndent);
        writeInt(out, (int) ((list.indentationLeft() + list.symbolIndent()) * 
twipsFactor));
        out.write(escape);
        out.write(fontSize);
        writeInt(out, 20);
        out.write(escape);
        out.write(listBegin);
        writeInt(out, currentListID);
        if(listLevel > 0)
        {
            out.write(escape);
            out.write(listCurrentLevel);
            writeInt(out, listLevel);
        }
        out.write(openGroup);
        ListIterator listItems = list.getItems().listIterator();
        Element listElem;
        int count = 1;
        while(listItems.hasNext())
        {
            listElem = (Element) listItems.next();
            if(listElem.type() == Element.CHUNK) { listElem = new ListItem((Chunk) 
listElem); }
            if(listElem.type() == Element.LISTITEM)
            {
                out.write(openGroup);
                out.write(escape);
                out.write(listTextOld);
                out.write(escape);
                out.write(paragraphDefaults);
                out.write(escape);
                out.write(fontNumber);
                if(list.isNumbered()) { writeInt(out, addFont(new 
Font(Font.TIMES_NEW_ROMAN, Font.NORMAL, 10, new Color(0, 0, 0)))); } else { 
writeInt(out, fontNr); }
                out.write(escape);
                out.write(firstIndent);
                writeInt(out, (int) (list.indentationLeft() * twipsFactor * -1));
                out.write(escape);
                out.write(listIndent);
                writeInt(out, (int) ((list.indentationLeft() + list.symbolIndent()) * 
twipsFactor));
                out.write(delimiter);
                if(list.isNumbered()) { writeInt(out, count); 
out.write(".".getBytes()); } else { out.write(escape); out.write( listBulletOld); }
                out.write(escape);
                out.write(tab);
                out.write(closeGroup);
                writeListElement((ListItem) listElem, out);
                count++;
            }
            else if(listElem.type() == Element.LIST)
            {
                listLevel++;
                writeList((com.lowagie.text.List) listElem, out);
                listLevel--;
                out.write(escape);
                out.write(paragraphDefaults);
                out.write(escape);
                out.write(alignLeft);
                out.write(escape);
                out.write(firstIndent);
                writeInt(out, (int) (list.indentationLeft() * twipsFactor * -1));
                out.write(escape);
                out.write(listIndent);
                writeInt(out, (int) ((list.indentationLeft() + list.symbolIndent()) * 
twipsFactor));
                out.write(escape);
                out.write(fontSize);
                writeInt(out, 20);
                out.write(escape);
                out.write(listBegin);
                writeInt(out, currentListID);
                if(listLevel > 0)
                {
                    out.write(escape);
                    out.write(listCurrentLevel);
                    writeInt(out, listLevel);
                }
            }
            out.write((byte)'\n');
        }
        out.write(closeGroup);
        if(listLevel == 0)
        {
            int i = getRandomInt();
            listtable.write(escape);
            listtable.write(listID);
            writeInt(listtable, i);
            listtable.write(closeGroup);
            listtable.write((byte) '\n');
            listoverride.write(openGroup);
            listoverride.write(escape);
            listoverride.write(listOverride);
            listoverride.write(escape);
            listoverride.write(listID);
            writeInt(listoverride, i);
            listoverride.write(escape);
            listoverride.write(listOverrideCount);
            writeInt(listoverride, 0);
            listoverride.write(escape);
            listoverride.write(listBegin);
            writeInt(listoverride, currentListID);
            currentListID++;
            listoverride.write(closeGroup);
            listoverride.write((byte) '\n');
        }
    }
    
  /**
   * Write a <code>Table</code>.
   *
   * @param table The <code>table</code> to be written
   * @param out The <code>ByteArrayOutputStream</code> to write to
   *
   * Currently no nesting of tables is supported. If a cell contains anything but a 
Cell Object it is ignored.
   *
   * @throws IOException, DocumentException
   */
    private void writeTable(Table table, ByteArrayOutputStream out) throws 
IOException, DocumentException
    {
        table.complete();
        RtfTable rtfTable = new RtfTable(this);
        rtfTable.importTable(table, 12239);
        rtfTable.writeTable(out);
    }
    
    
  /**
   * Write an <code>Image</code>.
   *
   * @param image The <code>image</code> to be written
   * @param out The <code>ByteArrayOutputStream</code> to write to
   *
   * At the moment only PNG and JPEG Images are supported.
   *
   * @throws IOException, DocumentException
   */
    private void writeImage(Image image, ByteArrayOutputStream out) throws 
IOException, DocumentException
    {
        if(!image.isPng() && !image.isJpeg()) throw new DocumentException("Only PNG 
and JPEG images are supported by the RTF Writer");
        switch(image.alignment())
        {
            case Element.ALIGN_LEFT      : out.write(escape); out.write(alignLeft); 
break;
            case Element.ALIGN_RIGHT     : out.write(escape); out.write(alignRight); 
break;
            case Element.ALIGN_CENTER    : out.write(escape); out.write(alignCenter); 
break;
            case Element.ALIGN_JUSTIFIED : out.write(escape); out.write(alignJustify); 
break;
        }
        out.write(openGroup);
        out.write(extendedEscape);
        out.write(pictureGroup);
        out.write(openGroup);
        out.write(escape);
        out.write(picture);
        out.write(escape);
        if(image.isPng()) out.write(picturePNG);
        if(image.isJpeg())  out.write(pictureJPEG);
        out.write(escape);
        out.write(pictureWidth);
        writeInt(out, (int) (image.width() * twipsFactor));
        out.write(escape);
        out.write(pictureHeight);
        writeInt(out, (int) (image.height() * twipsFactor));
        out.write(escape);
        out.write(pictureIntendedWidth);
        writeInt(out, (int) (image.plainWidth() * twipsFactor));
        out.write(escape);
        out.write(pictureIntendedHeight);
        writeInt(out, (int) (image.plainHeight() * twipsFactor));
        if(image.width() > 0)
        {
            out.write(escape);
            out.write(pictureScaleX);
            writeInt(out, (int) (100 / image.width() * image.plainWidth()));
        }
        if(image.height() > 0)
        {
            out.write(escape);
            out.write(pictureScaleY);
            writeInt(out, (int) (100 / image.height() * image.plainHeight()));
        }
        out.write(delimiter);
        InputStream imgIn;
        if(image.rawData() == null) { imgIn = image.url().openStream(); } else { imgIn 
= new ByteArrayInputStream(image.rawData()); }
        int buffer = -1;
        int count = 0;
        out.write((byte) '\n');
        while((buffer = imgIn.read()) != -1)
        {
            String helperStr = Integer.toHexString(buffer);
            if(helperStr.length() < 2) helperStr = "0" + helperStr;
            out.write(helperStr.getBytes());
            count++;
            if(count == 64) { out.write((byte) '\n'); count = 0; }
        }
        out.write(closeGroup);
        out.write(closeGroup);
        out.write((byte) '\n');
    }
    
  /**
   * Write an <code>Annotation</code>
   *
   * @param annotationElement The <code>Annotation</code> to be written
   * @param out The <code>ByteArrayOutputStream</code> to write to
   *
   * @throws IOException
   */
    private void writeAnnotation(Annotation annotationElement, ByteArrayOutputStream 
out) throws IOException, DocumentException
    {
        int id = getRandomInt();
        out.write(openGroup);
        out.write(extendedEscape);
        out.write(annotationID);
        out.write(delimiter);
        writeInt(out, id);
        out.write(closeGroup);
        out.write(openGroup);
        out.write(extendedEscape);
        out.write(annotationAuthor);
        out.write(delimiter);
        out.write(annotationElement.title().getBytes());
        out.write(closeGroup);
        out.write(openGroup);
        out.write(extendedEscape);
        out.write(annotation);
        out.write(escape);
        out.write(paragraphDefaults);
        out.write(delimiter);
        out.write(annotationElement.content().getBytes());
        out.write(closeGroup);
    }

  /**
   * Add a <code>Meta</code> element. It is written to the Inforamtion Group
   * and merged with the main <code>ByteArrayOutputStream</code> when the
   * Document is closed.
   *
   * @param metaName The type of <code>Meta</code> element to be added
   * @param meta The <code>Meta</code> element to be added
   *
   * Currently only the Meta Elements Author, Subject, Keywords, Title, Producer and 
CreationDate are supported.
   *
   * @throws IOException
   */
    private void writeMeta(byte[] metaName, Meta meta) throws IOException
    {
        info.write(openGroup);
        try
        {
            info.write(escape);
            info.write(metaName);
            info.write(delimiter);
            if(meta.type() == Meta.CREATIONDATE) { 
writeFormatedDateTime(meta.content()); } else { info.write(meta.content().getBytes()); 
}
        }
        finally
        {
            info.write(closeGroup);
        }
    }
    
  /**
   * Writes a date. The date is formated <strong>Year, Month, Day, Hour, Minute, 
Second</strong>
   *
   * @param date The date to be written
   *
   * @throws IOException
   */
    private void writeFormatedDateTime(String date) throws IOException
    {
        Calendar cal = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
        ParsePosition pp = new ParsePosition(0);
        Date d = sdf.parse(date, pp);
        if(d == null) { d = new Date(); }
        cal.setTime(d);
        info.write(escape);
        info.write(year);
        writeInt(info, cal.get(Calendar.YEAR));
        info.write(escape);
        info.write(month);
        writeInt(info, cal.get(Calendar.MONTH));
        info.write(escape);
        info.write(day);
        writeInt(info, cal.get(Calendar.DAY_OF_MONTH));
        info.write(escape);
        info.write(hour);
        writeInt(info, cal.get(Calendar.HOUR_OF_DAY));
        info.write(escape);
        info.write(minute);
        writeInt(info, cal.get(Calendar.MINUTE));
        info.write(escape);
        info.write(second);
        writeInt(info, cal.get(Calendar.SECOND));
    }
    
  /**
   * Add a new <code>Font</code> to the list of fonts. If the <code>Font</code>
   * already exists in the list of fonts, then it is not added again.
   *
   * @param newFont The <code>Font</code> to be added
   *
   * @return The index of the <code>Font</code> in the font list
   */
    protected int addFont(Font newFont)
    {
        int fn = -1;

        for(int i = 0; i < fontList.size(); i++)
        {
            
if(newFont.getFamilyname().equals(((Font)fontList.get(i)).getFamilyname())) { fn = i; }
        }
        if(fn == -1)
        {
            fontList.add(newFont);
            return fontList.size()-1;
        }
        return fn;
    }
    
  /**
   * Add a new <code>Color</code> to the list of colours. If the <code>Color</code>
   * already exists in the list of colours, then it is not added again.
   *
   * @param newColor The <code>Color</code> to be added
   *
   * @return The index of the <code>color</code> in the colour list
   */
    protected int addColor(Color newColor)
    {
        int cn = 0;
        if(newColor == null) { return cn; }
        cn = colorList.indexOf(newColor);
        if(cn == -1)
        {
            colorList.add(newColor);
            return colorList.size()-1;
        }
        return cn;
    }
    
  /**
   * Merge all the different <code>Vector</code>s and 
<code>ByteArrayOutputStream</code>s
   * to the final <code>ByteArrayOutputStream</code>
   *
   * @return <code>true</code> if all information was sucessfully written to the 
<code>ByteArrayOutputStream</code>
   */
    private boolean writeDocument()
    {
        try
        {
            writeDocumentIntro();
            os.write((byte)'\n');
            writeFontList();
            os.write((byte)'\n');
            writeColorList();
            os.write((byte)'\n');
            writeList();
            os.write((byte)'\n');
            writeInfoGroup();
            os.write((byte)'\n');
            writeDocumentFormat();
            os.write((byte)'\n');
            if(hasTitlePage)
            {
              os.write(escape);
              os.write(titlePage);
            }
            if (this.footer instanceof RtfHeaderFooters) {
                RtfHeaderFooters rtfHf = (RtfHeaderFooters)this.footer;
                HeaderFooter hf = rtfHf.get( RtfHeaderFooters.ALL_PAGES );
                if (hf != null) {
                    writeHeaderFooter( hf, footerBegin, os );
                }
                hf = rtfHf.get( RtfHeaderFooters.LEFT_PAGES );
                if (hf != null) {
                    writeHeaderFooter( hf, footerlBegin, os );
                }
                hf = rtfHf.get( RtfHeaderFooters.RIGHT_PAGES );
                if (hf != null) {
                    writeHeaderFooter( hf, footerrBegin, os );
                }
                hf = rtfHf.get( RtfHeaderFooters.FIRST_PAGE );
                if (hf != null) {
                    writeHeaderFooter( hf, footerfBegin, os );
                }
            } else {
                writeHeaderFooter(this.footer, footerBegin, os);
            }
            if (this.header instanceof RtfHeaderFooters) {
                RtfHeaderFooters rtfHf = (RtfHeaderFooters)this.header;
                HeaderFooter hf = rtfHf.get( RtfHeaderFooters.ALL_PAGES );
                if (hf != null) {
                    writeHeaderFooter( hf, headerBegin, os );
                }
                hf = rtfHf.get( RtfHeaderFooters.LEFT_PAGES );
                if (hf != null) {
                    writeHeaderFooter( hf, headerlBegin, os );
                }
                hf = rtfHf.get( RtfHeaderFooters.RIGHT_PAGES );
                if (hf != null) {
                    writeHeaderFooter( hf, headerrBegin, os );
                }
                hf = rtfHf.get( RtfHeaderFooters.FIRST_PAGE );
                if (hf != null) {
                    writeHeaderFooter( hf, headerfBegin, os );
                }
            } else {
                writeHeaderFooter(this.header, headerBegin, os);
            }

            content.writeTo(os);
            os.write(closeGroup);
            return true;
        }
        catch(IOException e)
        {
            System.err.println(e.getMessage());
            return false;
        }
        
    }
    
  /** Write the Rich Text file settings
   *
   * @return <code>true</code if the writing operation succeded
   */
    private void writeDocumentIntro() throws IOException
    {
        os.write(openGroup);
        os.write(escape);
        os.write(docBegin);
        os.write(escape);
        os.write(ansi);
        os.write(escape);
        os.write(ansiCodepage);
        writeInt(os, 1252);
        os.write(escape);
        os.write(defaultFont);
        writeInt(os, 0);
    }
    
  /**
   * Write the font list to the final <code>ByteArrayOutputStream</code>
   */
    private void writeFontList() throws IOException
    {
        Font fnt;

        os.write(openGroup);
        os.write(escape);
        os.write(fontTable);
        for(int i = 0; i < fontList.size(); i++)
        {
            fnt = (Font) fontList.get(i);
            os.write(openGroup);
            os.write(escape);
            os.write(fontNumber);
            writeInt(os, i);
            os.write(escape);
            switch(Font.getFamilyIndex(fnt.getFamilyname()))
            {
                case Font.COURIER:
                    os.write(fontModern);
                    os.write(escape);
                    os.write(fontCharset);
                    writeInt(os, 0);
                    os.write(delimiter);
                    os.write(fontCourier);
                    break;
                case Font.HELVETICA:
                    os.write(fontSwiss);
                    os.write(escape);
                    os.write(fontCharset);
                    writeInt(os, 0);
                    os.write(delimiter);
                    os.write(fontArial);
                    break;
                case Font.SYMBOL:
                    os.write(fontRoman);
                    os.write(escape);
                    os.write(fontCharset);
                    writeInt(os, 2);
                    os.write(delimiter);
                    os.write(fontSymbol);
                    break;
                case Font.TIMES_NEW_ROMAN:
                    os.write(fontRoman);
                    os.write(escape);
                    os.write(fontCharset);
                    writeInt(os, 0);
                    os.write(delimiter);
                    os.write(fontTimesNewRoman);
                    break;
                case Font.ZAPFDINGBATS:
                    os.write(fontTech);
                    os.write(escape);
                    os.write(fontCharset);
                    writeInt(os, 0);
                    os.write(delimiter);
                    os.write(fontWindings);
                    break;
            }
            os.write(commaDelimiter);
            os.write(closeGroup);
        }
        os.write(closeGroup);
    }
    
  /**
   * Write the colour list to the final <code>ByteArrayOutputStream</code>
   */
    private void writeColorList() throws IOException
    {
        Color color = null;
        
        os.write(openGroup);
        os.write(escape);
        os.write(colorTable);
        for(int i = 0; i < colorList.size(); i++)
        {
            color = (Color) colorList.get(i);
            os.write(escape);
            os.write(colorRed);
            writeInt(os, color.getRed());
            os.write(escape);
            os.write(colorGreen);
            writeInt(os, color.getGreen());
            os.write(escape);
            os.write(colorBlue);
            writeInt(os, color.getBlue());
            os.write(commaDelimiter);
        }
        os.write(closeGroup);
    }
    
  /**
   * Write the Information Group to the final <code>ByteArrayOutputStream</code>
   */
    private void writeInfoGroup() throws IOException
    {
        os.write(openGroup);
        os.write(escape);
        os.write(infoBegin);
        info.writeTo(os);
        os.write(closeGroup);
    }
    
  /**
   * Write the listtable and listoverridetable to the final 
<code>ByteArrayOutputStream</code>
   */
    private void writeList() throws IOException
    {
        listtable.write(closeGroup);
        listoverride.write(closeGroup);
        listtable.writeTo(os);
        os.write((byte)'\n');
        listoverride.writeTo(os);
    }
    
  /**
   * Write an integer
   *
   * @param out The <code>OuputStream</code> to which the <code>int</code> value is to 
be written
   * @param i The <code>int</code> value to be written
   */
    public final static void writeInt(OutputStream out, int i) throws IOException
    {
        out.write(Integer.toString(i).getBytes());
    }
    
  /**
   * Get a random integer.
   * This returns a <b>unique</b> random integer to be used with listids.
   *
   * @return Random <code>int</code> value.
   */
    private int getRandomInt()
    {
        boolean ok = false;
        Integer newInt = null;
        Integer oldInt = null;
        while(!ok)
        {
            newInt = new Integer((int) (Math.random() * Integer.MAX_VALUE));
            ok = true;
            for(int i = 0; i < listIds.size(); i++)
            {
                oldInt = (Integer) listIds.get(i);
                if(oldInt.equals(newInt)) { ok = true; }
            }
        }
        listIds.add(newInt);
        return newInt.intValue();
    }
    
  /**
   * Write the header to the final <code>ByteArrayOutputStream</code>
   */
    private void writeHeaderFooter(HeaderFooter headerFooter, byte[] hfType, 
BufferedOutputStream target) throws IOException
    {
        try
        {

            // XXX this is only a heack, because some method directly write to
            // the content output stream, but thats not what I want here
            ByteArrayOutputStream origContent = content;
            
            content = new ByteArrayOutputStream();
            content.write(openGroup);
            content.write(escape);
            content.write(hfType);
            if(headerFooter == null) {
                content.write(delimiter);
            }
            else
            {
                if (headerFooter instanceof RtfHeaderFooter 
                        && ((RtfHeaderFooter)headerFooter).content() != null) {
                    this.add( ((RtfHeaderFooter)headerFooter).content() );
                } else {
//                    Element[] headerElements = new Element[3];
                    java.util.List chunks = headerFooter.paragraph().getChunks();
                    int headerCount = chunks.size();
//                    if(headerCount >= 1) { headerElements[0] = (Element) 
headerFooter.paragraph().getChunks().get(0); }
//                    if(headerCount >= 2) { headerElements[1] = (Element) 
headerFooter.paragraph().getChunks().get(1); }
//                    if(headerCount >= 3) { headerElements[2] = (Element) 
headerFooter.paragraph().getChunks().get(2); }
                    if(headerCount >= 1) {
                        add( (Element)chunks.get( 0 ) );
                    }
                    if (headerCount >= 2) {
                        Element chunk = (Element)chunks.get(1);
                        if (chunk.type() == Element.CHUNK) {
                            try {
                                Integer.parseInt( ((Chunk)chunk).content() );
                                content.write(openGroup);
                                content.write(escape);
                                content.write(field);
                                content.write(openGroup);
                                content.write(extendedEscape);
                                content.write(fieldContent);
                                content.write(openGroup);
                                content.write(delimiter);
                                content.write(fieldPage);
                                content.write(delimiter);
                                content.write(closeGroup);
                                content.write(closeGroup);
                                content.write(openGroup);
                                content.write(escape);
                                content.write(fieldDisplay);
                                content.write(openGroup);
                                content.write(closeGroup);
                                content.write(closeGroup);
                                content.write(closeGroup);
                            }
                            catch(NumberFormatException nfe)
                            {
                                add( chunk );
                            }
                        } else {
                            add( chunk );
                        }
//                        if(headerElements[1].type() == Element.PHRASE) { 
writePhrase((Phrase) headerElements[1], content); }
                    }
                    if(headerCount >= 3) {
                        add( (Element)chunks.get( 2 ) );
//                        if(headerElements[2].type() == Element.CHUNK) { 
writeChunk((Chunk) headerElements[2], content); }
//                        if(headerElements[2].type() == Element.PHRASE) { 
writePhrase((Phrase) headerElements[2], content); }
                    }
                }
            }
            content.write(closeGroup);
            content.writeTo(target);
            // set the original
            content = origContent;
        }
        catch(DocumentException e)
        {
            throw new IOException("DocumentException - "+e.getMessage());
        }
    }
    
  /**
   *  Write the <code>Document</code>'s Paper and Margin Size
   *  to the final <code>ByteArrayOutputStream</code>
   */
    private void writeDocumentFormat() throws IOException
    {
//        os.write(openGroup);
        os.write(escape);
        os.write(rtfPaperWidth);
        writeInt(os, pageWidth);
        os.write(escape);
        os.write(rtfPaperHeight);
        writeInt(os, pageHeight);
        os.write(escape);
        os.write(rtfMarginLeft);
        writeInt(os, marginLeft);
        os.write(escape);
        os.write(rtfMarginRight);
        writeInt(os, marginRight);
        os.write(escape);
        os.write(rtfMarginTop);
        writeInt(os, marginTop);
        os.write(escape);
        os.write(rtfMarginBottom);
        writeInt(os, marginBottom);
//        os.write(closeGroup);
    }
    
  /**
   * Initialise all helper classes.
   * Clears alls lists, creates new <code>ByteArrayOutputStream</code>'s
   */
    private void initDefaults()
    {
        fontList.clear();
        colorList.clear();
        info = new ByteArrayOutputStream();
        content = new ByteArrayOutputStream();
        listtable = new ByteArrayOutputStream();
        listoverride = new ByteArrayOutputStream();
        document.addProducer();
        document.addCreationDate();
        addFont(new Font(Font.TIMES_NEW_ROMAN, 10, Font.NORMAL));
        addColor(new Color(0, 0, 0));
        addColor(new Color(255, 255, 255));
        listIds = new Vector();
        try
        {
            listtable.write(openGroup);
            listtable.write(extendedEscape);
            listtable.write(listtableGroup);
            listtable.write((byte) '\n');
            listoverride.write(openGroup);
            listoverride.write(extendedEscape);
            listoverride.write(listoverridetableGroup);
            listoverride.write((byte) '\n');
        }
        catch(IOException e)
        {
            System.err.println("InitDefaultsError" + e);
        }
    }

  /**
   * Replaces special characters with their unicode values
   *
   * @param str The original <code>String</code>
   * @return The converted String
   */
  public final static String filterSpecialChar(String str)
  {
       int length = str.length();
       int z = (int)'z';
       StringBuffer ret = new StringBuffer( length );
       for(int i = 0; i < length; i++) {
           char ch = str.charAt( i );
           if(ch == '\\')
             {
               ret.append("\\\\");
             }
           else if(ch == '\n')
             {
               ret.append("\\par ");
             }
           else if( ((int)ch) > z ) {
               ret.append( "\\u" ).append( (long)ch ).append( 'G' );
           } else {
               ret.append( ch );
           }
       }
       return ret.toString();
  }
}

Reply via email to