sboag       99/12/12 23:35:49

  Modified:    src/org/apache/xalan/xpath/xml FormatterToHTML.java
                        FormatterToXML.java
  Log:
  Major work for performance tuning, better whitespace handling.
  
  Revision  Changes    Path
  1.9       +569 -474  
xml-xalan/src/org/apache/xalan/xpath/xml/FormatterToHTML.java
  
  Index: FormatterToHTML.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/src/org/apache/xalan/xpath/xml/FormatterToHTML.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- FormatterToHTML.java      1999/12/10 18:42:29     1.8
  +++ FormatterToHTML.java      1999/12/13 07:35:49     1.9
  @@ -68,15 +68,26 @@
    */
   public class FormatterToHTML extends FormatterToXML 
   {  
  -  static   Hashtable  s_empties;
  -  static   Hashtable  s_attrempties;
  -  static   Hashtable  s_attruris;
  -  static   Hashtable  s_escapetb;
  -  static   Hashtable  s_nonblockelems;
  -  static   Hashtable  s_nonblockparents;
  - 
  -  Stack m_parents = new Stack();
  +  static char[]  s_escapetb = {'%', '<', '>', '{', '}', '[', ']', '|', '^', 
'"' /* , ' ', '#' '\\', '\'' */};
  +
  +  /**
  +   * Tell if the character should be escaped in a URL attribute.
  +   */
  +  boolean isURLEscapeChar(char c)
  +  {
  +    int n = s_escapetb.length;
  +    for(int i = 0; i < n; i++)
  +    {
  +      if(s_escapetb[i] == c)
  +        return true;
  +    }
  +    return false;
  +  }
     
  +  StringVector m_parents = new StringVector();
  +  BoolStack m_isRawStack = new BoolStack();
  +  boolean m_inBlockElem = false;
  +  
     static   String[]  s_HTMLlat1 =    
     {
       "nbsp",    "iexcl",    "cent",    "pound",    
  @@ -141,92 +152,187 @@
     //                                     "lceil",    "rceil",    "lfloor",   
 "rfloor",    
     //                                     "lang",    "rang",    "loz",    
"spades",    
     //                                      "clubs",    "hearts",    "diams"};
  +
  +  static Hashtable m_elementFlags = new Hashtable();
  +  
     static 
     {
  -    s_empties = new Hashtable();
  -    // HTML 4.0 strict DTD
  -    s_empties.put("AREA", "AREA");
  -    s_empties.put("BASE", "BASE");
  -    s_empties.put("BR", "BR");
  -    s_empties.put("COL", "COL");
  -    s_empties.put("HR", "HR");
  -    s_empties.put("IMG", "IMG");
  -    s_empties.put("INPUT", "INPUT");
  -    s_empties.put("LINK", "LINK");
  -    s_empties.put("META", "META");
  -    s_empties.put("PARAM", "PARAM");
       // HTML 4.0 loose DTD
  -    s_empties.put("BASEFONT", "BASEFONT");
  -    s_empties.put("FRAME", "FRAME");
  -    s_empties.put("ISINDEX", "ISINDEX");
  -    
  -    s_nonblockparents = new Hashtable();
  -    s_nonblockparents.put("P", "P");
  -    s_nonblockparents.put("SPAN", "SPAN");
  -    
  -    s_nonblockelems = new Hashtable();
  -    s_nonblockelems.put("FONT", "FONT");
  -    s_nonblockelems.put("A", "A");
  -    s_nonblockelems.put("TD", "TD");
  -    s_nonblockelems.put("IMG", "IMG");
  -    s_nonblockelems.put("B", "B");
  -    s_nonblockelems.put("I", "I");
  -    // s_nonblockelems.put("SPAN", "SPAN");
  -
  -    s_attrempties = new Hashtable();
  +    m_elementFlags.put("BASEFONT", new ElemDesc(0|ElemDesc.EMPTY));
  +    m_elementFlags.put("FRAME", new 
ElemDesc(0|ElemDesc.EMPTY|ElemDesc.BLOCK));
  +    m_elementFlags.put("FRAMESET", new ElemDesc(0|ElemDesc.BLOCK));
  +    m_elementFlags.put("NOFRAMES", new ElemDesc(0|ElemDesc.BLOCK));
  +    m_elementFlags.put("ISINDEX", new 
ElemDesc(0|ElemDesc.EMPTY|ElemDesc.BLOCK));
  +    m_elementFlags.put("APPLET", new 
ElemDesc(0|ElemDesc.WHITESPACESENSITIVE));
  +    m_elementFlags.put("CENTER", new ElemDesc(0|ElemDesc.BLOCK));
  +    m_elementFlags.put("DIR", new ElemDesc(0|ElemDesc.BLOCK));
  +    m_elementFlags.put("MENU", new ElemDesc(0|ElemDesc.BLOCK));
  +    
       // HTML 4.0 strict DTD
  -    s_attrempties.put("checked", "checked");
  -    s_attrempties.put("disabled", "disabled");
  -    s_attrempties.put("readonly", "readonly");
  -    s_attrempties.put("multiple", "multiple");
  -    s_attrempties.put("disabled", "disabled");
  -    s_attrempties.put("selected", "selected");
  -
  -    s_attruris = new Hashtable();   // used to catch URI attributes
  -    String[] URLAttrsHREFSingle = {"href"};
  -    String[] URLAttrsCITESingle = {"cite"};
  -    s_attruris.put("base", URLAttrsHREFSingle);
  -    s_attruris.put("link", URLAttrsHREFSingle);
  -    s_attruris.put("area", URLAttrsHREFSingle);
  -    // From the HTML 4.0 spec: Note. The same conversion based on UTF-8 
  -    // should be applied to values of the name attribute for the A element. 
  -    String[] URLAttrs_A = {"href", "name"};
  -    s_attruris.put("a", URLAttrs_A);
  -    String[] URLAttrs_INPUT = {"src", "usemap"};
  -    s_attruris.put("input", URLAttrs_INPUT);
  -    String[] URLAttrs_SCRIPT = {"src", "for"};
  -    s_attruris.put("script", URLAttrs_SCRIPT);
  -    String[] URLAttrs_IMG = {"src", "longdesc", "usemap"};
  -    s_attruris.put("img", URLAttrs_IMG);     
  -    String[] URLAttrs_OBJECT = {"classid", "codebase", "data", "archive", 
"usemap"};
  -    s_attruris.put("object", URLAttrs_OBJECT);
  -    s_attruris.put("q", URLAttrsCITESingle);
  -    s_attruris.put("blockquote", URLAttrsCITESingle);
  -    s_attruris.put("ins", URLAttrsCITESingle);
  -    s_attruris.put("del", URLAttrsCITESingle);
  -    String[] URLAttrs_FORM = {"action"};
  -    s_attruris.put("form", URLAttrs_FORM);
  -    String[] URLAttrs_HEAD = {"profile"};
  -    s_attruris.put("head", URLAttrs_HEAD);
  +    m_elementFlags.put("TT", new ElemDesc(0|ElemDesc.FONTSTYLE));
  +    m_elementFlags.put("I", new ElemDesc(0|ElemDesc.FONTSTYLE));
  +    m_elementFlags.put("B", new ElemDesc(0|ElemDesc.FONTSTYLE));
  +    m_elementFlags.put("BIG", new ElemDesc(0|ElemDesc.FONTSTYLE));
  +    m_elementFlags.put("SMALL", new ElemDesc(0|ElemDesc.FONTSTYLE));
  +    m_elementFlags.put("EM", new ElemDesc(0|ElemDesc.PHRASE));
  +    m_elementFlags.put("STRONG", new ElemDesc(0|ElemDesc.PHRASE));
  +    m_elementFlags.put("DFN", new ElemDesc(0|ElemDesc.PHRASE));
  +    m_elementFlags.put("CODE", new ElemDesc(0|ElemDesc.PHRASE));
  +    m_elementFlags.put("SAMP", new ElemDesc(0|ElemDesc.PHRASE));
  +    m_elementFlags.put("KBD", new ElemDesc(0|ElemDesc.PHRASE));
  +    m_elementFlags.put("VAR", new ElemDesc(0|ElemDesc.PHRASE));
  +    m_elementFlags.put("CITE", new ElemDesc(0|ElemDesc.PHRASE));
  +    m_elementFlags.put("ABBR", new ElemDesc(0|ElemDesc.PHRASE));
  +    m_elementFlags.put("ACRONYM", new ElemDesc(0|ElemDesc.PHRASE));
  +    m_elementFlags.put("SUP", new 
ElemDesc(0|ElemDesc.SPECIAL|ElemDesc.ASPECIAL));
  +    m_elementFlags.put("SUB", new 
ElemDesc(0|ElemDesc.SPECIAL|ElemDesc.ASPECIAL));
  +    m_elementFlags.put("SPAN", new 
ElemDesc(0|ElemDesc.SPECIAL|ElemDesc.ASPECIAL));
  +    m_elementFlags.put("BDO", new 
ElemDesc(0|ElemDesc.SPECIAL|ElemDesc.ASPECIAL));
  +    m_elementFlags.put("BR", new 
ElemDesc(0|ElemDesc.SPECIAL|ElemDesc.ASPECIAL|ElemDesc.EMPTY|ElemDesc.BLOCK));
  +    m_elementFlags.put("BODY", new ElemDesc(0|ElemDesc.BLOCK));
  +    m_elementFlags.put("ADDRESS", new 
ElemDesc(0|ElemDesc.BLOCK|ElemDesc.BLOCKFORM|ElemDesc.BLOCKFORMFIELDSET));
  +    m_elementFlags.put("DIV", new 
ElemDesc(0|ElemDesc.BLOCK|ElemDesc.BLOCKFORM|ElemDesc.BLOCKFORMFIELDSET));
  +    m_elementFlags.put("A", new ElemDesc(0|ElemDesc.SPECIAL));
  +    m_elementFlags.put("MAP", new 
ElemDesc(0|ElemDesc.SPECIAL|ElemDesc.ASPECIAL|ElemDesc.BLOCK));
  +    m_elementFlags.put("AREA", new 
ElemDesc(0|ElemDesc.EMPTY|ElemDesc.BLOCK));
  +    m_elementFlags.put("LINK", new 
ElemDesc(0|ElemDesc.HEADMISC|ElemDesc.EMPTY|ElemDesc.BLOCK));
  +    m_elementFlags.put("IMG", new 
ElemDesc(0|ElemDesc.SPECIAL|ElemDesc.ASPECIAL|ElemDesc.EMPTY|ElemDesc.WHITESPACESENSITIVE));
  +    m_elementFlags.put("OBJECT", new 
ElemDesc(0|ElemDesc.SPECIAL|ElemDesc.ASPECIAL|ElemDesc.HEADMISC|ElemDesc.WHITESPACESENSITIVE));
  +    m_elementFlags.put("PARAM", new ElemDesc(0|ElemDesc.EMPTY));
  +    m_elementFlags.put("HR", new 
ElemDesc(0|ElemDesc.BLOCK|ElemDesc.BLOCKFORM|ElemDesc.BLOCKFORMFIELDSET|ElemDesc.EMPTY));
  +    m_elementFlags.put("P", new 
ElemDesc(0|ElemDesc.BLOCK|ElemDesc.BLOCKFORM|ElemDesc.BLOCKFORMFIELDSET));
  +    m_elementFlags.put("H1", new ElemDesc(0|ElemDesc.HEAD|ElemDesc.BLOCK));
  +    m_elementFlags.put("H2", new ElemDesc(0|ElemDesc.HEAD|ElemDesc.BLOCK));
  +    m_elementFlags.put("H3", new ElemDesc(0|ElemDesc.HEAD|ElemDesc.BLOCK));
  +    m_elementFlags.put("H4", new ElemDesc(0|ElemDesc.HEAD|ElemDesc.BLOCK));
  +    m_elementFlags.put("H5", new ElemDesc(0|ElemDesc.HEAD|ElemDesc.BLOCK));
  +    m_elementFlags.put("H6", new ElemDesc(0|ElemDesc.HEAD|ElemDesc.BLOCK));
  +    m_elementFlags.put("PRE", new 
ElemDesc(0|ElemDesc.PREFORMATTED|ElemDesc.BLOCK));
  +    m_elementFlags.put("Q", new 
ElemDesc(0|ElemDesc.SPECIAL|ElemDesc.ASPECIAL));
  +    m_elementFlags.put("BLOCKQUOTE", new 
ElemDesc(0|ElemDesc.BLOCK|ElemDesc.BLOCKFORM|ElemDesc.BLOCKFORMFIELDSET));
  +    m_elementFlags.put("INS", new ElemDesc(0));
  +    m_elementFlags.put("DEL", new ElemDesc(0));
  +    m_elementFlags.put("DL", new 
ElemDesc(0|ElemDesc.BLOCK|ElemDesc.BLOCKFORM|ElemDesc.BLOCKFORMFIELDSET));
  +    m_elementFlags.put("DT", new ElemDesc(0|ElemDesc.BLOCK));
  +    m_elementFlags.put("DD", new ElemDesc(0|ElemDesc.BLOCK));
  +    m_elementFlags.put("OL", new ElemDesc(0|ElemDesc.LIST|ElemDesc.BLOCK));
  +    m_elementFlags.put("UL", new ElemDesc(0|ElemDesc.LIST|ElemDesc.BLOCK));
  +    m_elementFlags.put("LI", new ElemDesc(0|ElemDesc.BLOCK));
  +    m_elementFlags.put("FORM", new ElemDesc(0|ElemDesc.BLOCK));
  +    m_elementFlags.put("LABEL", new ElemDesc(0|ElemDesc.FORMCTRL));
  +    m_elementFlags.put("INPUT", new 
ElemDesc(0|ElemDesc.FORMCTRL|ElemDesc.INLINELABEL|ElemDesc.EMPTY));
  +    m_elementFlags.put("SELECT", new 
ElemDesc(0|ElemDesc.FORMCTRL|ElemDesc.INLINELABEL));
  +    m_elementFlags.put("OPTGROUP", new ElemDesc(0));
  +    m_elementFlags.put("OPTION", new ElemDesc(0));
  +    m_elementFlags.put("TEXTAREA", new 
ElemDesc(0|ElemDesc.FORMCTRL|ElemDesc.INLINELABEL));
  +    m_elementFlags.put("FIELDSET", new 
ElemDesc(0|ElemDesc.BLOCK|ElemDesc.BLOCKFORM));
  +    m_elementFlags.put("LEGEND", new ElemDesc(0));
  +    m_elementFlags.put("BUTTON", new 
ElemDesc(0|ElemDesc.FORMCTRL|ElemDesc.INLINELABEL));
  +    m_elementFlags.put("TABLE", new 
ElemDesc(0|ElemDesc.BLOCK|ElemDesc.BLOCKFORM|ElemDesc.BLOCKFORMFIELDSET));
  +    m_elementFlags.put("CAPTION", new ElemDesc(0|ElemDesc.BLOCK));
  +    m_elementFlags.put("THEAD", new ElemDesc(0|ElemDesc.BLOCK));
  +    m_elementFlags.put("TFOOT", new ElemDesc(0|ElemDesc.BLOCK));
  +    m_elementFlags.put("TBODY", new ElemDesc(0|ElemDesc.BLOCK));
  +    m_elementFlags.put("COLGROUP", new ElemDesc(0|ElemDesc.BLOCK));
  +    m_elementFlags.put("COL", new ElemDesc(0|ElemDesc.EMPTY|ElemDesc.BLOCK));
  +    m_elementFlags.put("TR", new ElemDesc(0|ElemDesc.BLOCK));
  +    m_elementFlags.put("TH", new ElemDesc(0));
  +    m_elementFlags.put("TD", new ElemDesc(0));
  +    m_elementFlags.put("HEAD", new ElemDesc(0|ElemDesc.BLOCK));
  +    m_elementFlags.put("TITLE", new ElemDesc(0|ElemDesc.BLOCK));
  +    m_elementFlags.put("BASE", new 
ElemDesc(0|ElemDesc.EMPTY|ElemDesc.BLOCK));
  +    m_elementFlags.put("META", new 
ElemDesc(0|ElemDesc.HEADMISC|ElemDesc.EMPTY|ElemDesc.BLOCK));
  +    m_elementFlags.put("STYLE", new 
ElemDesc(0|ElemDesc.HEADMISC|ElemDesc.RAW|ElemDesc.BLOCK));
  +    m_elementFlags.put("SCRIPT", new 
ElemDesc(0|ElemDesc.SPECIAL|ElemDesc.ASPECIAL|ElemDesc.HEADMISC|ElemDesc.RAW));
  +    m_elementFlags.put("NOSCRIPT", new 
ElemDesc(0|ElemDesc.BLOCK|ElemDesc.BLOCKFORM|ElemDesc.BLOCKFORMFIELDSET));
  +    m_elementFlags.put("HTML", new ElemDesc(0|ElemDesc.BLOCK));
  +    
  +    ElemDesc elemDesc;
  +    elemDesc = (ElemDesc)m_elementFlags.get("BASE");
  +    elemDesc.setAttr("HREF", ElemDesc.ATTRURL);
  +
  +    elemDesc = (ElemDesc)m_elementFlags.get("BLOCKQUOTE");
  +    elemDesc.setAttr("CITE", ElemDesc.ATTRURL);
  +
  +    elemDesc = (ElemDesc)m_elementFlags.get("INS");
  +    elemDesc.setAttr("CITE", ElemDesc.ATTRURL);
  +
  +    elemDesc = (ElemDesc)m_elementFlags.get("DEL");
  +    elemDesc.setAttr("CITE", ElemDesc.ATTRURL);
  +
  +    elemDesc = (ElemDesc)m_elementFlags.get("A");
  +    elemDesc.setAttr("HREF", ElemDesc.ATTRURL);
  +    elemDesc.setAttr("NAME", ElemDesc.ATTRURL);
  +
  +    elemDesc = (ElemDesc)m_elementFlags.get("INPUT");
  +    elemDesc.setAttr("SRC", ElemDesc.ATTRURL);
  +    elemDesc.setAttr("USEMAP", ElemDesc.ATTRURL);
  +    elemDesc.setAttr("CHECKED", ElemDesc.ATTREMPTY);
  +    elemDesc.setAttr("DISABLED", ElemDesc.ATTREMPTY);
  +    elemDesc.setAttr("READONLY", ElemDesc.ATTREMPTY);
  +
  +    elemDesc = (ElemDesc)m_elementFlags.get("SELECT");
  +    elemDesc.setAttr("READONLY", ElemDesc.ATTREMPTY);
  +    elemDesc.setAttr("MULTIPLE", ElemDesc.ATTREMPTY);
  +
  +    elemDesc = (ElemDesc)m_elementFlags.get("OPTGROUP");
  +    elemDesc.setAttr("DISABLED", ElemDesc.ATTREMPTY);
  +
  +    elemDesc = (ElemDesc)m_elementFlags.get("OPTION");
  +    elemDesc.setAttr("SELECTED", ElemDesc.ATTREMPTY);
  +    elemDesc.setAttr("DISABLED", ElemDesc.ATTREMPTY);
  +
  +    elemDesc = (ElemDesc)m_elementFlags.get("TEXTAREA");
  +    elemDesc.setAttr("DISABLED", ElemDesc.ATTREMPTY);
  +    elemDesc.setAttr("READONLY", ElemDesc.ATTREMPTY);
  +
  +    elemDesc = (ElemDesc)m_elementFlags.get("BUTTON");
  +    elemDesc.setAttr("DISABLED", ElemDesc.ATTREMPTY);
  +
  +    elemDesc = (ElemDesc)m_elementFlags.get("SCRIPT");
  +    elemDesc.setAttr("SRC", ElemDesc.ATTRURL);
  +    elemDesc.setAttr("FOR", ElemDesc.ATTRURL);
  +
  +    elemDesc = (ElemDesc)m_elementFlags.get("IMG");
  +    elemDesc.setAttr("SRC", ElemDesc.ATTRURL);
  +    elemDesc.setAttr("LONGDESC", ElemDesc.ATTRURL);
  +    elemDesc.setAttr("USEMAP", ElemDesc.ATTRURL);
  +
  +    elemDesc = (ElemDesc)m_elementFlags.get("OBJECT");
  +    elemDesc.setAttr("CLASSID", ElemDesc.ATTRURL);
  +    elemDesc.setAttr("CODEBASE", ElemDesc.ATTRURL);
  +    elemDesc.setAttr("DATA", ElemDesc.ATTRURL);
  +    elemDesc.setAttr("ARCHIVE", ElemDesc.ATTRURL);
  +    elemDesc.setAttr("USEMAP", ElemDesc.ATTRURL);
  +
  +    elemDesc = (ElemDesc)m_elementFlags.get("FORM");
  +    elemDesc.setAttr("ACTION", ElemDesc.ATTRURL);
  +
  +    elemDesc = (ElemDesc)m_elementFlags.get("HEAD");
  +    elemDesc.setAttr("PROFILE", ElemDesc.ATTRURL);
      
  -    s_escapetb = new Hashtable(); // other chars to escape 
  -    s_escapetb.put("%", "%");
  -    s_escapetb.put("<", "<");
  -    s_escapetb.put(">",">");
  -//    s_escapetb.put(" "," ");
  -//    s_escapetb.put("#", "#");
  -    s_escapetb.put("{", "{");
  -    s_escapetb.put("}", "}");
  -    s_escapetb.put("[", "[");
  -    s_escapetb.put("]", "]");
  -    // s_escapetb.put("\\","\\");
  -    s_escapetb.put("|", "|");
  -    s_escapetb.put("^", "^");
  -    s_escapetb.put("\"", "\"");
  -//    s_escapetb.put("'", "'");        
     }
     
     /**
  +   * Dummy element for elements not found.
  +   */
  +  static private ElemDesc m_dummy = new ElemDesc(0);
  +  
  +  /**
  +   * Get a description of the given element.
  +   */
  +  ElemDesc getElemDesc(String name)
  +  {
  +    if(null != name)
  +    {
  +      Object obj = m_elementFlags.get(name);
  +      if(null != obj)
  +        return (ElemDesc)obj;
  +    }
  +    return m_dummy;
  +  }
  +  
  +  /**
      * Default constructor.
      */
     public FormatterToHTML() 
  @@ -244,6 +350,56 @@
       initEncodings();
     }
     
  +  /**
  +   * Constructor using a writer.
  +   * @param writer        The character output stream to use.
  +   */
  +  public FormatterToHTML(FormatterToXML xmlListener) 
  +  {
  +    super(xmlListener);
  +    m_doIndent = true;  // TODO: But what if the user wants to set it???
  +  }
  +  
  +  /**
  +   * Set the attribute characters what will require special mapping.
  +   */
  +  protected void initAttrCharsMap()
  +  {
  +    super.initAttrCharsMap();
  +    m_attrCharsMap[(int)'\n'] = 'S';
  +    m_attrCharsMap[(int)10] = 'S';
  +  }
  +    
  +  /**
  +   * Set the characters what will require special mapping.
  +   */
  +  protected void initCharsMap()
  +  {
  +    initAttrCharsMap();
  +    int n = (m_maxCharacter > SPECIALSSIZE) ? SPECIALSSIZE : m_maxCharacter;
  +    for(int i = 0; i < n; i++)
  +    {
  +      m_charsMap[i] = '\0';
  +    }
  +    m_charsMap[(int)'\n'] = 'S';
  +    m_charsMap[(int)'<'] = 'S';
  +    m_charsMap[(int)'>'] = 'S';
  +    m_charsMap[(int)'&'] = 'S';
  +    for(int i = 0; i < 10; i++)
  +    {
  +      m_charsMap[i] = 'S';
  +    }
  +    n = (255 > SPECIALSSIZE) ? 255 : SPECIALSSIZE;
  +    for(int i = 160; i < n; i++)
  +    {
  +      m_charsMap[i] = 'S';
  +    }
  +    for(int i = m_maxCharacter; i < SPECIALSSIZE; i++)
  +    {
  +      m_charsMap[i] = 'S';
  +    }
  +  }
  +  
     String m_currentElementName = null;
   
     // protected boolean shouldIndent()
  @@ -259,40 +415,47 @@
      */
     public void startDocument ()
       throws SAXException
  -  {    
  +  {
       m_needToOutputDocTypeDecl = true;
  -    m_startNewLine = false;                 
  +    m_startNewLine = false;
  +    m_shouldNotWriteXMLHeader = true;
       
       if(true == m_needToOutputDocTypeDecl)
       {
  -      try
  +      if((null != m_doctypeSystem) || (null != m_doctypePublic))
         {
  -        if((null != m_doctypeSystem) || (null != m_doctypePublic))
  +        accum("<!DOCTYPE HTML ");          
  +        if(null != m_doctypePublic)
           {
  -          m_writer.write("<!DOCTYPE HTML ");          
             if(null != m_doctypePublic)
             {
  -            m_writer.write(" PUBLIC \"");
  -            m_writer.write(m_doctypePublic);
  -            m_writer.write("\"");
  +            accum(" PUBLIC \"");
  +            accum(m_doctypePublic);
  +            accum("\"");
             }
             if(null != m_doctypeSystem)
             {
               if(null == m_doctypePublic)
  -              m_writer.write(" SYSTEM \"");
  +              accum(" SYSTEM \"");
               else
  -              m_writer.write(" \"");
  -            m_writer.write(m_doctypeSystem);
  -            m_writer.write("\"");
  +              accum(" \"");
  +            accum(m_doctypeSystem);
  +            accum("\"");
             }
  -          m_writer.write(">");
  -          m_writer.write(m_lineSep);
  +          accum(">");
  +          accum(m_lineSep);
           }
  -    
  -      }
  -      catch(IOException ioe)
  -      {
  -        throw new SAXException("IO error", ioe);
  +        if(null != m_doctypeSystem)
  +        {
  +          if(null == m_doctypePublic)
  +            accum(" SYSTEM \"");
  +          else
  +            accum(" \"");
  +          accum(m_doctypeSystem);
  +          accum("\"");
  +        }
  +        accum(">");
  +        outputLineSep();
         }
       }
       m_needToOutputDocTypeDecl = false;
  @@ -311,55 +474,47 @@
     public void startElement (String name, AttributeList atts)
       throws SAXException
     {
  -    
       boolean savedDoIndent = m_doIndent;
       boolean noLineBreak;
  -    // If the previous element is a non-block element or the next 
  -    // element is a non-block element, then do not indent.
  -    m_doIndent = ((null != s_nonblockelems.get(name.toUpperCase())) ||
  -                  ((null != m_currentElementName) 
  -                   && ((null != 
s_nonblockelems.get(m_currentElementName.toUpperCase()) )
  -                       || (null != 
s_nonblockparents.get(m_currentElementName.toUpperCase()) )))) 
  -                 ? false : true;
  -
  -    // m_currentElementName = name.toUpperCase();
  -    m_currentElementName = name;
  -    m_parents.push(m_currentElementName.toUpperCase());
  -    // super.startElement(m_currentElementName, atts);
  -    try
  -    {      
  -      writeParentTagEnd();
  -      m_ispreserve = false;
  +    
  +    writeParentTagEnd();
   
  -      // m_doIndent = ( (!m_elemNames.isEmpty()) && (null != 
s_spanelems.get(m_elemNames.peek())))
  -      //             ? false : true;
  -      
  -      //  System.out.println(name+": m_doIndent = "+m_doIndent+", 
m_ispreserve = "+m_ispreserve+", m_isprevtext = "+m_isprevtext);
  -      if (shouldIndent() && !m_elemStack.isEmpty()) 
  -      {
  -        m_startNewLine = true;
  -        indent(this.m_writer, m_currentIndent);
  -      }
  +    String nameUpper = name.toUpperCase();
   
  -      this.m_writer.write('<');
  -      this.m_writer.write(name);
  -      
  -      int nAttrs = atts.getLength();
  -      for (int i = 0;  i < nAttrs ;  i++)
  -      {
  -        processAttribute(atts.getName(i), atts.getValue(i));
  -      }
  -      // Flag the current element as not yet having any children.
  -      openElementForChildren();
  -      
  -      m_currentIndent += this.indent;
  -      
  -      m_isprevtext = false;
  +    ElemDesc elemDesc = getElemDesc(nameUpper);
  +    // ElemDesc parentElemDesc = getElemDesc(m_currentElementName);
  +    
  +    boolean isBlockElement = elemDesc.is(ElemDesc.BLOCK);
  +    
  +    if(m_ispreserve)
  +      m_ispreserve = false;
  +    else if(m_doIndent && (null != m_currentElementName) && (!m_inBlockElem 
|| isBlockElement))
  +    {
  +      m_startNewLine = true;
  +      indent(m_currentIndent);
       }
  -    catch(IOException ioe)
  +    
  +    m_inBlockElem = !isBlockElement;
  +    
  +    m_isRawStack.push(elemDesc.is(ElemDesc.RAW));
  +
  +    m_currentElementName = nameUpper;
  +    m_parents.push(m_currentElementName);
  +
  +    this.accum('<');
  +    this.accum(name);
  +    
  +    int nAttrs = atts.getLength();
  +    for (int i = 0;  i < nAttrs ;  i++)
       {
  -      throw new SAXException("IO error", ioe);
  +      processAttribute(atts.getName(i), elemDesc, atts.getValue(i));
       }
  +    // Flag the current element as not yet having any children.
  +    openElementForChildren();
  +    
  +    m_currentIndent += this.indent;
  +    
  +    m_isprevtext = false;
   
       m_doIndent = savedDoIndent;
     }
  @@ -374,54 +529,72 @@
     public void endElement (String name)
       throws SAXException
     {
  -    try
  +    m_currentIndent -= this.indent;
  +    // name = name.toUpperCase();
  +    boolean hasChildNodes = childNodesWereAdded();
  +    // System.out.println(m_currentElementName);
  +    m_parents.pop();
  +    m_isRawStack.pop();
  +    
  +    String nameUpper = name.toUpperCase();
  +
  +    ElemDesc elemDesc = getElemDesc(nameUpper);
  +    // ElemDesc parentElemDesc = getElemDesc(m_currentElementName);
  +    
  +    boolean isBlockElement = elemDesc.is(ElemDesc.BLOCK);
  +    
  +    boolean shouldIndent = false;
  +    if(m_ispreserve)
       {
  -      m_currentIndent -= this.indent;
  -      // name = name.toUpperCase();
  -      boolean hasChildNodes = childNodesWereAdded();
  -      // System.out.println(m_currentElementName);
  -      m_parents.pop();
  -      boolean isWhitespaceSensitive 
  -        = (null != s_nonblockelems.get(name.toUpperCase())) || 
  -          (null != s_nonblockelems.get(m_currentElementName.toUpperCase())) 
||
  -          (!m_parents.isEmpty() && (null != 
s_nonblockparents.get(m_parents.peek()) ));
  -      
  -      if (hasChildNodes) 
  +      m_ispreserve = false;
  +    }
  +    else if(m_doIndent && (!m_inBlockElem || isBlockElement))
  +    {
  +      m_startNewLine = true;
  +      shouldIndent = true;
  +      // indent(m_currentIndent);
  +    }
  +    
  +    m_inBlockElem = !isBlockElement;
  +    
  +    if (hasChildNodes) 
  +    {
  +      if (shouldIndent)
  +        indent(m_currentIndent);
  +      this.accum("</");
  +      this.accum(name);
  +      this.accum('>');
  +      m_currentElementName = name;
  +    }
  +    else
  +    {
  +      if(!elemDesc.is(ElemDesc.EMPTY))
         {
  -        if (shouldIndent() && !isWhitespaceSensitive)  
  -          indent(this.m_writer, m_currentIndent);
  -        this.m_writer.write("</");
  -        this.m_writer.write(name);
  -        this.m_writer.write('>');
  -        m_currentElementName = name;
  +        this.accum('>');
  +        if (shouldIndent)
  +          indent(m_currentIndent);
  +        this.accum('<');
  +        this.accum('/');
  +        this.accum(name);
  +        this.accum('>');
         }
         else
         {
  -        if(s_empties.get(name.toUpperCase()) == null)
  -        {
  -          this.m_writer.write(">");
  -          // if (shouldIndent() && !isWhitespaceSensitive)
  -          //  indent(this.m_writer, m_currentIndent);
  -          this.m_writer.write("</");
  -          this.m_writer.write(name);
  -          this.m_writer.write('>');
  -        }
  -        else
  -        {
  -          this.m_writer.write('>');
  -        }
  -      }
  -      if (hasChildNodes) 
  -      {
  -        m_ispreserve = ((Boolean)m_preserves.pop()).booleanValue();
  +        this.accum('>');
         }
  -      m_isprevtext = false;
  -      // m_elemNames.pop();
       }
  -    catch(IOException ioe)
  +    
  +    if (elemDesc.is(ElemDesc.WHITESPACESENSITIVE))
  +      m_ispreserve = true;
  +
  +    /*
  +    if (hasChildNodes) 
       {
  -      throw new SAXException("IO error", ioe);
  +      m_ispreserve = m_preserves.pop();
       }
  +    */
  +    m_isprevtext = false;
  +    // m_elemNames.pop();
     }
     
     /**
  @@ -429,95 +602,52 @@
      * @param   name   The name of the attribute.
      * @param   value   The value of the attribute.
      */
  -  protected void processAttribute(String name, String value) 
  +  protected void processAttribute(String name, ElemDesc elemDesc, String 
value) 
       throws SAXException
     {
  -    try
  +    String nameUpper = name.toUpperCase();
  +    this.accum(' ');
  +    if(elemDesc.isAttrFlagSet(nameUpper, ElemDesc.ATTREMPTY) &&
  +       (value.length() == 0) || value.equalsIgnoreCase(name))
       {
  -      // String aname = name.toLowerCase();
  -      String aname = name;
  -      if(!aname.equals("xmlns") && !aname.startsWith("xmlns:"))
  -      {
  -        String pval = null;  
  -        if (aname.equals("xml:lang"))  aname = "lang";
  -        // qualify with an element??
  -        String val[] = 
(String[])(s_attruris.get(m_currentElementName.toLowerCase()));
  -        if(val != null)
  -        {
  -          int nAttrs = val.length;
  -          int i;
  -          String lowername = aname.toLowerCase();
  -          for(i = 0; i < nAttrs; i++)
  -          {
  -            if(val[i].equals(lowername))
  -            {
  -              pval = prepAttrURI(value, m_attrSpecialChars, this.m_encoding);
  -              break;
  -            }
  -          }
  -          if(i == nAttrs)
  -          {
  -            pval = prepAttrString(value, m_attrSpecialChars, 
this.m_encoding);
  -          }
  -        }    
  -        else
  -        {
  -          pval = prepAttrString(value, m_attrSpecialChars, this.m_encoding);
  -        }
  -        if(s_attrempties.get(aname.toLowerCase()) == null)
  -        {
  -          this.m_writer.write(' ');
  -          this.m_writer.write(aname);
  -          this.m_writer.write("=\"");
  -          this.m_writer.write(pval);
  -          this.m_writer.write('\"');
  -        }
  -        else
  -        {
  -          this.m_writer.write(' ');
  -          if((pval.length() == 0) || pval.equalsIgnoreCase(aname))
  -          {
  -            this.m_writer.write(aname);
  -          }
  -          else
  -          {
  -            this.m_writer.write(aname);
  -            this.m_writer.write("=\"");
  -            this.m_writer.write(pval);
  -            this.m_writer.write('\"');
  -          }
  -        }
  -      }
  +      this.accum(name);
       }
  -    catch(IOException ioe)
  +    else
       {
  -      throw new SAXException("IO error", ioe);
  +      this.accum(name);
  +      this.accum('=');
  +      this.accum('\"');
  +      if(elemDesc.isAttrFlagSet(nameUpper, ElemDesc.ATTRURL))
  +        writeAttrURI(value, this.m_encoding);
  +      else
  +        writeAttrString(value, this.m_encoding);
  +      this.accum('\"');
       }
     }
     
     /**
  -   * Returns the specified <var>string</var> after substituting non ASCII 
characters,
  +   * Write the specified <var>string</var> after substituting non ASCII 
characters,
      * with <CODE>%HH</CODE>, where HH is the hex of the byte value.
      *
      * @param   string      String to convert to XML format.
      * @param   specials    Chracters, should be represeted in chracter 
referenfces.
      * @param   encoding    CURRENTLY NOT IMPLEMENTED.
  -   * @return              XML-formatted string.
      * @see #backReference
      */
  -  public String prepAttrURI(String string, String specials, String encoding)
  +  public void writeAttrURI(String string, String encoding)
       throws SAXException
     {
  -    StringBuffer sb = new StringBuffer(string.length()*10);
  +    char[] stringArray = string.toCharArray();
  +    int len = stringArray.length;
   
  -    for (int i = 0;  i < string.length();  i ++)
  +    for (int i = 0;  i < len;  i ++)
       {
  -      char ch = string.charAt(i);
  +      char ch = stringArray[i];
         if(((ch > 0x1F) &&   // X'00 - 1F' not valid
            (ch < 0x7F)) &&   // X'7F' not valid
  -         (s_escapetb.get(String.valueOf(ch))== null)  ) // characters in the 
table
  +         !isURLEscapeChar(ch)  ) // characters in the table
         {
  -        sb.append(ch);   // valid character, append it
  +        accum(ch);   // valid character, append it
         }
         else
         {
  @@ -529,133 +659,124 @@
           // if first 8 bytes are 0, no need to append them.
           if (b1 != 0)
           {     
  -          sb.append("%");
  -          sb.append(Integer.toHexString(b1));
  +          accum("%");
  +          accum(Integer.toHexString(b1));
           }    
  -        sb.append("%");
  -        sb.append(Integer.toHexString(b2));          
  +        accum("%");
  +        accum(Integer.toHexString(b2));              
         }
       }
  -    return sb.toString();
     }
     
     /**
  -   * Returns the specified <var>string</var> after substituting 
<VAR>specials</VAR>,
  +   * Writes the specified <var>string</var> after substituting 
<VAR>specials</VAR>,
      * and UTF-16 surrogates for chracter references <CODE>&amp;#xnn</CODE>.
      *
      * @param   string      String to convert to XML format.
      * @param   specials    Chracters, should be represeted in chracter 
referenfces.
      * @param   encoding    CURRENTLY NOT IMPLEMENTED.
  -   * @return              XML-formatted string.
      * @see #backReference
      */
  -  public String prepAttrString(String string, String specials, String 
encoding)
  +  public void writeAttrString(String string, String encoding)
       throws SAXException
     {
  -    StringBuffer sb = new StringBuffer(string.length()*12/10);
       int strLen = string.length();
  -    for (int i = 0;  i < strLen;  i ++) 
  +    // char chars[] = string.toCharArray();
  +    for (int i = 0;  i < strLen;  i ++)
       {
  +      // char ch = chars[i];
         char ch = string.charAt(i);
  -      if(('&' == ch) && ((i+1) < string.length()) && ('{' == 
string.charAt(i+1)))
  +      if((ch < SPECIALSSIZE) && (m_attrCharsMap[ch] != 'S'))
  +      {
  +        accum(ch);
  +      }      
  +      else if(('&' == ch) && ((i+1) < strLen) && ('{' == string.charAt(i+1)))
         {
  -        sb.append(ch); // no escaping in this case, as specified in 15.2
  +        accum(ch); // no escaping in this case, as specified in 15.2
         }
  -      else
  +      else if (0xd800 <= ch && ch < 0xdc00) 
         {
  -        int chNum = (int)ch;
  -        int index = specials.indexOf(chNum);
  -        if ((index >= 0) || (chNum > m_maxCharacter)) 
  +        // UTF-16 surrogate
  +        int next;
  +        if (i+1 >= string.length()) 
           {
  -          /*
  -          if ('<' == ch) 
  -          {
  -            sb.append("&lt;");
  -          }
  -          else if ('>' == ch) 
  -          {
  -            sb.append("&gt;");
  -          }
  -          else 
  -          */
  -          if ('&' == ch) 
  -          {
  -            sb.append("&amp;");
  -          }
  -          else if ('"' == ch) 
  -          {
  -            sb.append("&quot;");
  -          }
  -          else if((chNum >= 9) && (chNum <= 126))
  -          {
  -            sb.append(ch);
  -          }
  -          else if((chNum >= 160) && (chNum <= 255))
  -          {
  -            sb.append("&");
  -            sb.append(s_HTMLlat1[((int)ch)-160]);
  -            sb.append(";");
  -          }
  -          else if((chNum >= 913) && (chNum <= 982))
  -          {
  -            sb.append("&");
  -            sb.append(HTMLsymbol1[((int)ch)-913]);
  -            sb.append(";");
  -          }
  -          else if (402 == ch) 
  -          {
  -            sb.append("&fnof;");
  -          }
  -          else
  -          {
  -            sb.append("&#x");
  -            sb.append(Integer.toHexString(chNum));
  -            sb.append(";");
  -          }
  +          throw new SAXException("Invalid UTF-16 surrogate detected: "
  +            +Integer.toHexString(ch)+ " ?");
           }
  -        else if (0xd800 <= chNum && chNum < 0xdc00) 
  +        else 
           {
  -          // UTF-16 surrogate
  -          int next;
  -          if (i+1 >= string.length()) 
  -          {
  +          next = string.charAt(++i);
  +          if (!(0xdc00 <= next && next < 0xe000))
               throw new SAXException("Invalid UTF-16 surrogate detected: "
  -              +Integer.toHexString(ch)+ " ?");
  -          }
  -          else 
  -          {
  -            next = string.charAt(++i);
  -            if (!(0xdc00 <= next && next < 0xe000))
  -              throw new SAXException("Invalid UTF-16 surrogate detected: "
  -                +Integer.toHexString(ch)+" "+Integer.toHexString(next));
  -            next = ((ch-0xd800)<<10)+next-0xdc00+0x00010000;
  -          }
  -          sb.append("&#x");
  -          sb.append(Integer.toHexString(next));
  -          sb.append(";");
  -          /*} else if (null != ctbc && !ctbc.canConvert(ch)) {
  -          sb.append("&#x");
  -          sb.append(Integer.toString((int)ch, 16));
  -          sb.append(";");*/
  +              +Integer.toHexString(ch)+" "+Integer.toHexString(next));
  +          next = ((ch-0xd800)<<10)+next-0xdc00+0x00010000;
           }
  -        else 
  +        accum("&#x");
  +        accum(Integer.toHexString(next));
  +        accum(";");
  +        /*} else if (null != ctbc && !ctbc.canConvert(ch)) {
  +        accum("&#x");
  +        accum(Integer.toString((int)ch, 16));
  +        accum(";");*/
  +      }
  +      else
  +      {
  +        if ('\n' == ch) 
  +        {
  +          outputLineSep();
  +        }
  +        else if (10 == ch) 
  +        {
  +          outputLineSep();
  +        }
  +        else if ('&' == ch) 
  +        {
  +          accum("&amp;");
  +        }
  +        else if ('"' == ch) 
           {
  -          sb.append(ch);
  +          accum("&quot;");
           }
  +        else if((ch >= 9) && (ch <= 126))
  +        {
  +          accum(ch);
  +        }
  +        else if((ch >= 160) && (ch <= 255))
  +        {
  +          accum("&");
  +          accum(s_HTMLlat1[((int)ch)-160]);
  +          accum(";");
  +        }
  +        else if((ch >= 913) && (ch <= 982))
  +        {
  +          accum("&");
  +          accum(HTMLsymbol1[((int)ch)-913]);
  +          accum(";");
  +        }
  +        else if (402 == ch) 
  +        {
  +          accum("&fnof;");
  +        }
  +        else
  +        {
  +          accum("&#x");
  +          accum(Integer.toHexString(ch));
  +          accum(";");
  +        }
         }
       }
  -    return sb.toString();
     }
     
     private int copyEntityIntoBuf(String s, int pos)
  +    throws SAXException
     {
       int l = s.length();
  -    m_charBuf[pos++] = '&';
  +    accum('&');
       for(int i= 0; i < l; i++)
       {
  -      m_charBuf[pos++] = s.charAt(i);
  +      accum(s.charAt(i));
       }
  -    m_charBuf[pos++] = ';';
  +    accum(';');
       return pos;
     }
     
  @@ -702,20 +823,18 @@
         return;
       }
       
  -    if((null != m_currentElementName) &&
  -       (m_currentElementName.equalsIgnoreCase("SCRIPT") ||
  -       m_currentElementName.equalsIgnoreCase("STYLE")))
  +    if(m_isRawStack.peek())
       {
         try
         {
           writeParentTagEnd();
           m_ispreserve = true;
           if (shouldIndent())
  -          indent(this.m_writer, m_currentIndent);
  -        // this.m_writer.write("<![CDATA[");
  -        // this.m_writer.write(chars, start, length);
  +          indent(m_currentIndent);
  +        // this.accum("<![CDATA[");
  +        // this.accum(chars, start, length);
           writeNormalizedChars(chars, start, length, false);
  -        // this.m_writer.write("]]>");
  +        // this.accum("]]>");
           return;
         }
         catch(IOException ioe)
  @@ -724,109 +843,98 @@
         }
       }
       
  -    try
  +    writeParentTagEnd();
  +    m_ispreserve = true;
  +    int pos = 0;
  +    int end = start+length;
  +    for (int i = start;  i < end;  i ++) 
       {
  -      writeParentTagEnd();
  -      m_ispreserve = true;
  -      int pos = 0;
  -      int end = start+length;
  -      for (int i = start;  i < end;  i ++) 
  +      char ch = chars[i];
  +      
  +      if((ch < SPECIALSSIZE) && (m_charsMap[ch] != 'S'))
         {
  -        char ch = chars[i];
  -        int chNum = (int)ch;
  -        if ('\n' == ch) 
  -        {
  -          for(int k = 0; k < m_lineSepLen; k++)
  -          {
  -            m_charBuf[pos++] = m_lineSep.charAt(k);
  -          }
  -        }
  -        else if ('<' == ch) 
  -        {
  -          pos = copyEntityIntoBuf("lt", pos);
  -        }
  -        else if ('>' == ch) 
  -        {
  -          pos = copyEntityIntoBuf("gt", pos);
  -        }
  -        else if ('&' == ch) 
  -        {
  -          pos = copyEntityIntoBuf("amp", pos);
  -        }
  -        else if((chNum >= 9) && (chNum <= 126))
  -        {
  -          m_charBuf[pos++] = ch;
  -        }
  -        else if((chNum >= 160) && (chNum <= 255))
  -        {
  -          pos = copyEntityIntoBuf(s_HTMLlat1[((int)ch)-160], pos);
  -        }
  -        else if((chNum >= 913) && (chNum <= 982))
  -        {
  -          pos = copyEntityIntoBuf(HTMLsymbol1[((int)ch)-913], pos);
  -        }
  -        else if (402 == ch) 
  +        accum(ch);
  +        continue;
  +      }
  +
  +      if ('\n' == ch) 
  +      {
  +        outputLineSep();
  +      }
  +      else if ('<' == ch) 
  +      {
  +        pos = copyEntityIntoBuf("lt", pos);
  +      }
  +      else if ('>' == ch) 
  +      {
  +        pos = copyEntityIntoBuf("gt", pos);
  +      }
  +      else if ('&' == ch) 
  +      {
  +        pos = copyEntityIntoBuf("amp", pos);
  +      }
  +      else if((ch >= 9) && (ch <= 126))
  +      {
  +        accum(ch);
  +      }
  +      else if((ch >= 160) && (ch <= 255))
  +      {
  +        pos = copyEntityIntoBuf(s_HTMLlat1[((int)ch)-160], pos);
  +      }
  +      else if((ch >= 913) && (ch <= 982))
  +      {
  +        pos = copyEntityIntoBuf(HTMLsymbol1[((int)ch)-913], pos);
  +      }
  +      else if (402 == ch) 
  +      {
  +        pos = copyEntityIntoBuf("fnof", pos);
  +      }
  +      else if (m_isUTF8 && (0xd800 <= ch && ch < 0xdc00)) 
  +      {
  +        // UTF-16 surrogate
  +        int next;
  +        if (i+1 >= length) 
           {
  -          pos = copyEntityIntoBuf("fnof", pos);
  +          throw new SAXException("Invalid UTF-16 surrogate detected: "
  +            +Integer.toHexString(ch)+ " ?");
           }
  -        else if (m_isUTF8 && (0xd800 <= chNum && chNum < 0xdc00)) 
  +        else 
           {
  -          // UTF-16 surrogate
  -          int next;
  -          if (i+1 >= length) 
  -          {
  +          next = chars[++i];
  +          if (!(0xdc00 <= next && next < 0xe000))
               throw new SAXException("Invalid UTF-16 surrogate detected: "
  -              +Integer.toHexString(ch)+ " ?");
  -          }
  -          else 
  -          {
  -            next = chars[++i];
  -            if (!(0xdc00 <= next && next < 0xe000))
  -              throw new SAXException("Invalid UTF-16 surrogate detected: "
  -                +Integer.toHexString(ch)+" "+Integer.toHexString(next));
  -            next = ((ch-0xd800)<<10)+next-0xdc00+0x00010000;
  -          }
  -          m_charBuf[pos++] = '&';
  -          m_charBuf[pos++] = '#';
  -          String intStr = Integer.toString(next);
  -          int nIntStr = intStr.length();
  -          for(int k = 0; k < nIntStr; k++)
  -          {
  -            m_charBuf[pos++] = intStr.charAt(k);
  -          }
  -          m_charBuf[pos++] = ';';
  -        }
  -        else if((ch >= '\u007F') && (ch <= m_maxCharacter))
  -        {
  -          // Hope this is right...
  -          m_charBuf[pos++] = ch;
  +              +Integer.toHexString(ch)+" "+Integer.toHexString(next));
  +          next = ((ch-0xd800)<<10)+next-0xdc00+0x00010000;
           }
  -        else
  +        accum('&');
  +        accum('#');
  +        String intStr = Integer.toString(next);
  +        int nIntStr = intStr.length();
  +        for(int k = 0; k < nIntStr; k++)
           {
  -          m_charBuf[pos++] = '&';
  -          m_charBuf[pos++] = '#';
  -          String intStr = Integer.toString(chNum);
  -          int nIntStr = intStr.length();
  -          for(int k = 0; k < nIntStr; k++)
  -          {
  -            m_charBuf[pos++] = intStr.charAt(k);
  -          }
  -          m_charBuf[pos++] = ';';
  +          accum(intStr.charAt(k));
           }
  -        // Use 80 as a best guess safe buffer
  -        if(pos > MAXSAFECHARBUF)
  +        accum(';');
  +      }
  +      else if((ch >= '\u007F') && (ch <= m_maxCharacter))
  +      {
  +        // Hope this is right...
  +        accum(ch);
  +      }
  +      else
  +      {
  +        accum('&');
  +        accum('#');
  +        String intStr = Integer.toString(ch);
  +        int nIntStr = intStr.length();
  +        for(int k = 0; k < nIntStr; k++)
           {
  -          this.m_writer.write(m_charBuf, 0, pos);
  -          pos = 0;
  +          accum(intStr.charAt(k));
           }
  +        accum(';');
         }
  -      this.m_writer.write(m_charBuf, 0, pos);
  -      m_isprevtext = true;
  -    }
  -    catch(IOException ioe)
  -    {
  -      throw new SAXException("IO error", ioe);
       }
  +    m_isprevtext = true;
     }
     
     /**
  @@ -866,8 +974,8 @@
           writeParentTagEnd();
           m_ispreserve = true;
           if (shouldIndent())
  -          indent(this.m_writer, m_currentIndent);
  -        // this.m_writer.write(ch, start, length);
  +          indent(m_currentIndent);
  +        // this.accum(ch, start, length);
           writeNormalizedChars(ch, start, length, true);
         }
         catch(IOException ioe)
  @@ -883,10 +991,10 @@
           writeParentTagEnd();
           m_ispreserve = true;
           if (shouldIndent())
  -          indent(this.m_writer, m_currentIndent);
  -        // this.m_writer.write("<![CDATA[");
  -        this.m_writer.write(ch, start, length);
  -        // this.m_writer.write("]]>");
  +          indent(m_currentIndent);
  +        // this.accum("<![CDATA[");
  +        this.accum(ch, start, length);
  +        // this.accum("]]>");
         }
         catch(IOException ioe)
         {
  @@ -912,29 +1020,22 @@
     public void processingInstruction (String target, String data)
       throws SAXException
     {
  -    try
  +    // Use a fairly nasty hack to tell if the next node is supposed to be 
  +    // unescaped text.
  +    if(target.equals("xslt-next-is-raw") && data.equals("formatter-to-dom"))
       {
  -      // Use a fairly nasty hack to tell if the next node is supposed to be 
  -      // unescaped text.
  -      if(target.equals("xslt-next-is-raw") && 
data.equals("formatter-to-dom"))
  -      {
  -        m_nextIsRaw = true;
  -      }
  -      else
  -      {
  -        writeParentTagEnd();
  -        if (shouldIndent())  
  -          indent(this.m_writer, m_currentIndent);
  -        this.m_writer.write("<?" + target);
  -        if (data.length() > 0 && !Character.isSpaceChar(data.charAt(0)))
  -          this.m_writer.write(" ");
  -        this.m_writer.write(data + ">"); // different from XML
  -        m_startNewLine = true;
  -      }
  +      m_nextIsRaw = true;
       }
  -    catch(IOException ioe)
  +    else
       {
  -      throw new SAXException("IO error", ioe);
  +      writeParentTagEnd();
  +      if (shouldIndent())  
  +        indent(m_currentIndent);
  +      this.accum("<?" + target);
  +      if (data.length() > 0 && !Character.isSpaceChar(data.charAt(0)))
  +        this.accum(" ");
  +      this.accum(data + ">"); // different from XML
  +      m_startNewLine = true;
       }
     }
   
  @@ -944,16 +1045,10 @@
     public void entityReference(String name)
       throws SAXException
     {
  -    try
  -    {
  -      this.m_writer.write("&");
  -      this.m_writer.write(name);
  -      this.m_writer.write(";");
  -    }
  -    catch(IOException ioe)
  -    {
  -      throw new SAXException("IO error", ioe);
  -    }
  +    this.accum("&");
  +    this.accum(name);
  +    this.accum(";");
     }
  +  
   }
   
  
  
  
  1.10      +496 -338  
xml-xalan/src/org/apache/xalan/xpath/xml/FormatterToXML.java
  
  Index: FormatterToXML.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/src/org/apache/xalan/xpath/xml/FormatterToXML.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- FormatterToXML.java       1999/12/03 08:43:13     1.9
  +++ FormatterToXML.java       1999/12/13 07:35:49     1.10
  @@ -79,6 +79,10 @@
      * The writer where the XML will be written.
      */
     protected  Writer m_writer      =   null;
  +  
  +  protected OutputStream m_outputStream = null;
  +  
  +  private boolean m_bytesEqualChars = false;
   
     /**
      * Return the Writer.
  @@ -125,7 +129,7 @@
      * A stack of Boolean objects that tell if the given element 
      * has children.
      */
  -  protected  Stack m_elemStack = new Stack();
  +  protected  BoolStack m_elemStack = new BoolStack();
     
     /**
      * Use the system line seperator to write line breaks.
  @@ -139,6 +143,18 @@
     protected final int m_lineSepLen = m_lineSep.length();
     
     /**
  +   * Output a system-dependent line break.
  +   */
  +  protected final void outputLineSep()
  +    throws SAXException
  +  {
  +    for(int z = 0; z < m_lineSepLen; z++)
  +    {
  +      accum(m_lineSep.charAt(z));
  +    }
  +  }
  +  
  +  /**
      * State flag to tell if preservation of whitespace 
      * is important.
      */
  @@ -148,7 +164,7 @@
      * Stack to keep track of whether or not we need to 
      * preserve whitespace.
      */
  -  protected Stack   m_preserves     =   new Stack();
  +  protected BoolStack   m_preserves     =   new BoolStack();
     
     /**
      * State flag that tells if the previous node processed 
  @@ -215,8 +231,60 @@
     
     /**
      * These are characters that will be escaped in the output.
  +   */
  +  // public char[] m_attrSpecialChars = {'<', '>', '&', '\"', '\r', '\n'};
  +  public char[] m_attrSpecialChars = {'<', '>', '&', '\"'};
  +  
  +  static final int SPECIALSSIZE = 256;
  +  
  +  public char[] m_attrCharsMap = new char[SPECIALSSIZE];
  +  
  +  public char[] m_charsMap = new char[SPECIALSSIZE];
  +  
  +  /**
  +   * Set the attribute characters what will require special mapping.
  +   */
  +  protected void initAttrCharsMap()
  +  {
  +    int n = (m_maxCharacter > SPECIALSSIZE) ? SPECIALSSIZE : m_maxCharacter;
  +    for(int i = 0; i < n; i++)
  +    {
  +      m_attrCharsMap[i] = '\0';
  +    }
  +    int nSpecials = m_attrSpecialChars.length;
  +    for(int i = 0; i < nSpecials; i++)
  +    {
  +      m_attrCharsMap[(int)i] = 'S';
  +    }
  +  }
  +
  +  /**
  +   * Set the characters what will require special mapping.
      */
  -  public String m_attrSpecialChars = "<>&\"\r\n";
  +  protected void initCharsMap()
  +  {
  +    initAttrCharsMap();
  +    int n = (m_maxCharacter > SPECIALSSIZE) ? SPECIALSSIZE : m_maxCharacter;
  +    for(int i = 0; i < n; i++)
  +    {
  +      m_charsMap[i] = '\0';
  +    }
  +    m_charsMap[(int)'\n'] = 'S';
  +    m_charsMap[(int)'<'] = 'S';
  +    m_charsMap[(int)'>'] = 'S';
  +    m_charsMap[(int)'&'] = 'S';
  +    for(int i = 0; i < 20; i++)
  +    {
  +      m_charsMap[i] = 'S';
  +    }
  +    m_charsMap[10] = '\0';
  +    m_charsMap[13] = '\0';
  +    m_charsMap[9] = '\0';
  +    for(int i = m_maxCharacter; i < SPECIALSSIZE; i++)
  +    {
  +      m_charsMap[i] = 'S';
  +    }
  +  }
     
     /**
      * Flag to quickly tell if the encoding is UTF8.
  @@ -252,7 +320,54 @@
     {
       m_writer = writer;
       initEncodings();
  +    throw new RuntimeException("Constructor not implemented!");
  +  }
  +  
  +  /**
  +   * Constructor using a writer.
  +   * @param writer        The character output stream to use.
  +   */
  +  public FormatterToXML(FormatterToXML xmlListener) 
  +  {
  +    m_writer = xmlListener.m_writer;
  +    m_outputStream = xmlListener.m_outputStream;
  +    m_bytesEqualChars = xmlListener.m_bytesEqualChars;
  +    m_stripCData = xmlListener.m_stripCData;
  +    m_escapeCData = xmlListener.m_escapeCData;
  +    m_encoding = xmlListener.m_encoding;
  +    javaEncodingIsISO = xmlListener.javaEncodingIsISO;
  +    m_shouldNotWriteXMLHeader = xmlListener.m_shouldNotWriteXMLHeader;
  +    m_shouldNotWriteXMLHeader = xmlListener.m_shouldNotWriteXMLHeader;
  +    m_elemStack = xmlListener.m_elemStack;
  +    // m_lineSep = xmlListener.m_lineSep;
  +    // m_lineSepLen = xmlListener.m_lineSepLen;
  +    m_ispreserve = xmlListener.m_ispreserve;
  +    m_preserves = xmlListener.m_preserves;
  +    m_isprevtext = xmlListener.m_isprevtext;
  +    m_doIndent = xmlListener.m_doIndent;
  +    m_currentIndent = xmlListener.m_currentIndent;
  +    indent = xmlListener.indent;
  +    level = xmlListener.level;
  +    m_startNewLine = xmlListener.m_startNewLine;
  +    m_needToOutputDocTypeDecl = xmlListener.m_needToOutputDocTypeDecl;
  +    m_nextIsRaw = xmlListener.m_nextIsRaw;
  +    m_doctypeSystem = xmlListener.m_doctypeSystem;
  +    m_doctypePublic = xmlListener.m_doctypePublic;
  +    m_standalone = xmlListener.m_standalone;
  +    m_mediatype = xmlListener.m_mediatype;
  +    m_attrSpecialChars = xmlListener.m_attrSpecialChars;
  +    m_attrCharsMap = xmlListener.m_attrCharsMap;
  +    m_charsMap = xmlListener.m_charsMap;
  +    m_maxCharacter = xmlListener.m_maxCharacter;
  +    m_spaceBeforeClose = xmlListener.m_spaceBeforeClose;
  +    m_inCData = xmlListener.m_inCData;
  +    m_charBuf = xmlListener.m_charBuf;
  +    m_byteBuf = xmlListener.m_byteBuf;
  +    // m_pos = xmlListener.m_pos;
  +    m_pos = 0;
  +    initCharsMap();
     }
  +
     
     /**
      * Initialize the serializer with the specified writer and output format.
  @@ -279,6 +394,7 @@
       }
       // Determine the last printable character based on the output format
       m_maxCharacter = format.getLastPrintable();
  +    initCharsMap();
       
       if(null == this.m_encoding)
         this.m_encoding = getMimeEncoding(format.getEncoding());
  @@ -290,6 +406,7 @@
       {
         Character maxChar = (Character)maxCharObj;
         m_maxCharacter = maxChar.charValue();
  +      initCharsMap();
       }
   
     }
  @@ -309,9 +426,21 @@
     {    
       this.m_encoding = getMimeEncoding(format.getEncoding());
       
  -    String javaEncoding = this.convertMime2JavaEncoding(this.m_encoding);
  -    
  -    init( new OutputStreamWriter( output, javaEncoding ), format );
  +    if(this.m_encoding.equals(DEFAULT_MIME_ENCODING) || 
  +       this.m_encoding.equals("WINDOWS-1250") ||
  +       this.m_encoding.equals("US-ASCII") ||
  +       this.m_encoding.equals("US-ASCII"))
  +    {
  +      m_bytesEqualChars = true;
  +      m_outputStream = output;
  +      init( (Writer)null, format );
  +    }
  +    else
  +    {
  +      String javaEncoding = this.convertMime2JavaEncoding(this.m_encoding);
  +      
  +      init( new OutputStreamWriter( output, javaEncoding ), format );
  +    }
     }
     
     /**
  @@ -335,50 +464,36 @@
     public void startDocument ()
       throws SAXException
     {
  -    try
  +    m_needToOutputDocTypeDecl = true;
  +    m_startNewLine = false;
  +    
  +    if(m_shouldNotWriteXMLHeader == false)
       {
  -      m_needToOutputDocTypeDecl = true;
  -      m_startNewLine = false;
  +      String encoding = getMimeEncoding(this.m_encoding);
         
  -      if(m_shouldNotWriteXMLHeader == false)
  -      {
  -        String encoding = getMimeEncoding(this.m_encoding);
  -        
  -        String version = (null == m_version) ? "1.0" : m_version;
  -
  -        m_writer.write("<?xml version=\""+version+"\" encoding=\""+
  -                       encoding + "\"?>");
  -        m_writer.write(m_lineSep);
  -      }      
  -    }
  -    catch(IOException ioe)
  -    {
  -      throw new SAXException("IO error", ioe);
  -    }
  +      String version = (null == m_version) ? "1.0" : m_version;
  +
  +      accum("<?xml version=\""+version+"\" encoding=\""+
  +            encoding + "\"?>");
  +      outputLineSep();
  +    }      
       if((true == m_needToOutputDocTypeDecl) && (null != m_doctypeSystem))
       {
  -      try
  -      {
  -        m_writer.write("<!DOCTYPE ");
  -        
  -        if(null != m_doctypePublic)
  -        {
  -          m_writer.write(" PUBLIC \"");
  -          m_writer.write(m_doctypePublic);
  -          m_writer.write("\"");
  -        }
  -        if(null == m_doctypePublic)
  -          m_writer.write(" SYSTEM \"");
  -        else
  -          m_writer.write(" \"");
  -        m_writer.write(m_doctypeSystem);
  -        m_writer.write("\">");
  -        m_writer.write(m_lineSep);
  -      }
  -      catch(IOException ioe)
  +      accum("<!DOCTYPE ");
  +      
  +      if(null != m_doctypePublic)
         {
  -        throw new SAXException("IO error", ioe);
  +        accum(" PUBLIC \"");
  +        accum(m_doctypePublic);
  +        accum("\"");
         }
  +      if(null == m_doctypePublic)
  +        accum(" SYSTEM \"");
  +      else
  +        accum(" \"");
  +      accum(m_doctypeSystem);
  +      accum("\">");
  +      outputLineSep();
       }  
       m_needToOutputDocTypeDecl = false;
     }
  @@ -392,18 +507,11 @@
     public void endDocument ()
       throws SAXException
     {
  -    try
  +    if(m_doIndent && !m_isprevtext)
       {
  -      if(m_doIndent && !m_isprevtext)
  -      {
  -        this.m_writer.write(m_lineSep);
  -      }
  -      this.m_writer.flush();
  +      outputLineSep();
       }
  -    catch(IOException ioe)
  -    {
  -      throw new SAXException("IO error", ioe);
  -    }
  +    flush();
     }
     
     /**
  @@ -454,36 +562,29 @@
     public void startElement (String name, AttributeList atts)
       throws SAXException
     {
  -    try
  -    {      
  -      writeParentTagEnd();
  -      m_ispreserve = false;
  -      //  System.out.println(name+": m_doIndent = "+m_doIndent+", 
m_ispreserve = "+m_ispreserve+", m_isprevtext = "+m_isprevtext);
  -      if (shouldIndent() && !m_elemStack.isEmpty()) 
  -      {
  -        m_startNewLine = true;
  -        indent(this.m_writer, m_currentIndent);
  -      }
  -
  -      this.m_writer.write('<');
  -      this.m_writer.write(name);
  -      
  -      int nAttrs = atts.getLength();
  -      for (int i = 0;  i < nAttrs ;  i++)
  -      {
  -        processAttribute(atts.getName(i), atts.getValue(i));
  -      }
  -      // Flag the current element as not yet having any children.
  -      openElementForChildren();
  -      
  -      m_currentIndent += this.indent;
  -      
  -      m_isprevtext = false;
  +    writeParentTagEnd();
  +    m_ispreserve = false;
  +    //  System.out.println(name+": m_doIndent = "+m_doIndent+", m_ispreserve 
= "+m_ispreserve+", m_isprevtext = "+m_isprevtext);
  +    if (shouldIndent() && !m_elemStack.isEmpty()) 
  +    {
  +      m_startNewLine = true;
  +      indent(m_currentIndent);
       }
  -    catch(IOException ioe)
  +
  +    accum('<');
  +    accum(name);
  +    
  +    int nAttrs = atts.getLength();
  +    for (int i = 0;  i < nAttrs ;  i++)
       {
  -      throw new SAXException("IO error", ioe);
  +      processAttribute(atts.getName(i), atts.getValue(i));
       }
  +    // Flag the current element as not yet having any children.
  +    openElementForChildren();
  +    
  +    m_currentIndent += this.indent;
  +    
  +    m_isprevtext = false;
     }
     
     /**
  @@ -493,25 +594,18 @@
     protected void writeParentTagEnd()
       throws SAXException
     {
  -    try
  +    if(!m_elemStack.isEmpty())
       {
  -      if(!m_elemStack.empty())
  +      // See if the parent element has already been flagged as having 
children.
  +      if((false == m_elemStack.peek()))
         {
  -        // See if the parent element has already been flagged as having 
children.
  -        if(false == ((Boolean)m_elemStack.peek()).booleanValue())
  -        {
  -          this.m_writer.write('>');
  -          m_isprevtext = false;
  -          m_elemStack.pop();
  -          m_elemStack.push(new Boolean(true));
  -          m_preserves.push(new Boolean(m_ispreserve));
  -        }
  +        accum('>');
  +        m_isprevtext = false;
  +        m_elemStack.pop();
  +        m_elemStack.push(true);
  +        m_preserves.push(m_ispreserve);
         }
       }
  -    catch(IOException ioe)
  -    {
  -      throw new SAXException("IO error", ioe);
  -    }
     }
     
     /**
  @@ -521,7 +615,7 @@
     protected void openElementForChildren()
     {
       // Flag the current element as not yet having any children.
  -    m_elemStack.push(new Boolean(false));
  +    m_elemStack.push(false);
     }
     
     /**
  @@ -531,7 +625,7 @@
     protected boolean childNodesWereAdded()
     { 
       return m_elemStack.isEmpty() ? 
  -           false : ((Boolean)m_elemStack.pop()).booleanValue();
  +           false : m_elemStack.pop();
     }
   
     /**
  @@ -544,36 +638,30 @@
     public void endElement (String name)
       throws SAXException
     {
  -    try
  +    m_currentIndent -= this.indent;
  +    boolean hasChildNodes = childNodesWereAdded();
  +    if (hasChildNodes) 
  +    {
  +      if (shouldIndent()) 
  +        indent(m_currentIndent);
  +      accum('<');
  +      accum('/');
  +      accum(name);
  +      accum('>');
  +    }
  +    else
       {
  -      m_currentIndent -= this.indent;
  -      boolean hasChildNodes = childNodesWereAdded();
  -      if (hasChildNodes) 
  -      {
  -        if (shouldIndent()) 
  -          indent(this.m_writer, m_currentIndent);
  -        this.m_writer.write("</");
  -        this.m_writer.write(name);
  -        this.m_writer.write('>');
  -      }
  +      if(m_spaceBeforeClose)
  +        accum(" />");
         else
  -      {
  -        if(m_spaceBeforeClose)
  -          this.m_writer.write(" />");
  -        else
  -          this.m_writer.write("/>");
  -      }
  -      if (hasChildNodes) 
  -      {
  -        m_ispreserve = m_preserves.isEmpty() 
  -                       ? false : ((Boolean)m_preserves.pop()).booleanValue();
  -      }
  -      m_isprevtext = false;
  +        accum("/>");
       }
  -    catch(IOException ioe)
  +    if (hasChildNodes) 
       {
  -      throw new SAXException("IO error", ioe);
  +      m_ispreserve = m_preserves.isEmpty() 
  +                     ? false : m_preserves.pop();
       }
  +    m_isprevtext = false;
     }
   
     /**
  @@ -584,18 +672,11 @@
     protected void processAttribute(String name, String value) 
       throws SAXException
     {
  -    try
  -    {
  -      this.m_writer.write(' ');
  -      this.m_writer.write(name);
  -      this.m_writer.write("=\"");
  -      this.m_writer.write(prepAttrString(value, m_attrSpecialChars, 
this.m_encoding));
  -      this.m_writer.write('\"');
  -    }
  -    catch(IOException ioe)
  -    {
  -      throw new SAXException("IO error", ioe);
  -    }
  +    accum(' ');
  +    accum(name);
  +    accum("=\"");
  +    writeAttrString(value, this.m_encoding);
  +    accum('\"');
     }
   
     /**
  @@ -610,29 +691,25 @@
     public void processingInstruction (String target, String data)
       throws SAXException
     {
  -    try
  +    // Use a fairly nasty hack to tell if the next node is supposed to be 
  +    // unescaped text.
  +    if(target.equals("xslt-next-is-raw") && data.equals("formatter-to-dom"))
       {
  -      // Use a fairly nasty hack to tell if the next node is supposed to be 
  -      // unescaped text.
  -      if(target.equals("xslt-next-is-raw") && 
data.equals("formatter-to-dom"))
  -      {
  -        m_nextIsRaw = true;
  -      }
  -      else
  -      {
  -        writeParentTagEnd();
  -        if (shouldIndent())  
  -          indent(this.m_writer, m_currentIndent);
  -        this.m_writer.write("<?" + target);
  -        if (data.length() > 0 && !Character.isSpaceChar(data.charAt(0)))
  -          this.m_writer.write(" ");
  -        this.m_writer.write(data + "?>");
  -        m_startNewLine = true;
  -      }
  +      m_nextIsRaw = true;
       }
  -    catch(IOException ioe)
  +    else
       {
  -      throw new SAXException("IO error", ioe);
  +      writeParentTagEnd();
  +      if (shouldIndent())  
  +        indent(m_currentIndent);
  +      accum('<');
  +      accum('?');
  +      accum(target);
  +      if (data.length() > 0 && !Character.isSpaceChar(data.charAt(0)))
  +        accum(' ');
  +      accum('?');
  +      accum('>');
  +      m_startNewLine = true;
       }
     }
     
  @@ -651,20 +728,13 @@
     public void comment (char ch[], int start, int length)  
       throws SAXException
     {
  -    try
  -    {
  -      writeParentTagEnd();
  -      if (shouldIndent())  
  -        indent(this.m_writer, m_currentIndent);
  -      this.m_writer.write("<!--");
  -      this.m_writer.write(ch, start, length);
  -      this.m_writer.write("-->");
  -      m_startNewLine = true;
  -    }
  -    catch(IOException ioe)
  -    {
  -      throw new SAXException(ioe);
  -    }
  +    writeParentTagEnd();
  +    if (shouldIndent())  
  +      indent(m_currentIndent);
  +    accum("<!--");
  +    accum(ch, start, length);
  +    accum("-->");
  +    m_startNewLine = true;
     }
     
     protected boolean m_inCData = false;
  @@ -738,21 +808,21 @@
           writeParentTagEnd();
           m_ispreserve = true;
           if (shouldIndent())
  -          indent(this.m_writer, m_currentIndent);
  +          indent(m_currentIndent);
           if(!m_stripCData)
           {
             if(((length >= 1) && (ch[start] <= m_maxCharacter)))
             {
  -            this.m_writer.write("<![CDATA[");
  +            accum("<![CDATA[");
             }
           }
  -        // this.m_writer.write(ch, start, length);
  +        // accum(ch, start, length);
           writeNormalizedChars(ch, start, length, !m_stripCData);
           if(!m_stripCData)
           {
             if(((length >= 1) && (ch[(start+length)-1] <= m_maxCharacter)))
             {
  -            this.m_writer.write("]]>");
  +            accum("]]>");
             }
           }
         }
  @@ -763,11 +833,151 @@
       }
     }
     
  -  static final int MAXCHARBUF = 4096;
  -  static final int MAXSAFECHARBUF = MAXCHARBUF-256;
  -  char[] m_charBuf = new char[MAXCHARBUF];
  +  static final int MAXCHARBUF = (8*1024);
  +  protected char[] m_charBuf = new char[MAXCHARBUF];
  +  protected byte[] m_byteBuf = new byte[MAXCHARBUF];
  +  protected int m_pos = 0;
     
     /**
  +   * Append a byte to the buffer.
  +   */
  +  protected final void accum(byte b)
  +    throws SAXException
  +  {
  +    if(m_bytesEqualChars)
  +    {
  +      m_byteBuf[m_pos++] = b;
  +      if(m_pos >= MAXCHARBUF)
  +        flushBytes();
  +    }
  +    else
  +    {
  +      m_charBuf[m_pos++] = (char)b;
  +      if(m_pos >= MAXCHARBUF)
  +        flushChars();
  +    }
  +  }
  +
  +  /**
  +   * Append a character to the buffer.
  +   */
  +  protected final void accum(char b)
  +    throws SAXException
  +  {
  +    if(m_bytesEqualChars)
  +    {
  +      m_byteBuf[m_pos++] = (byte)b;
  +      if(m_pos >= MAXCHARBUF)
  +        flushBytes();
  +    }
  +    else
  +    {
  +      m_charBuf[m_pos++] = b;
  +      if(m_pos >= MAXCHARBUF)
  +        flushChars();
  +    }
  +  }
  +  
  +  /**
  +   * Append a character to the buffer.
  +   */
  +  protected final void accum(char chars[], int start, int length)
  +    throws SAXException
  +  {
  +    int n = start+length;
  +    if(m_bytesEqualChars)
  +    {
  +      for(int i = start; i < n; i++)
  +      {
  +        m_byteBuf[m_pos++] = (byte)chars[i];
  +        if(m_pos >= MAXCHARBUF)
  +          flushBytes();
  +      }
  +    }
  +    else
  +    {
  +      for(int i = start; i < n; i++)
  +      {
  +        m_charBuf[m_pos++] = chars[i];
  +        if(m_pos >= MAXCHARBUF)
  +          flushChars();
  +      }
  +    }
  +  }
  +
  +  /**
  +   * Append a character to the buffer.
  +   */
  +  protected final void accum(String s)
  +    throws SAXException
  +  {
  +    int n = s.length();
  +    
  +    if(m_bytesEqualChars)
  +    {
  +      char[] chars = s.toCharArray();
  +      for(int i = 0; i < n; i++)
  +      {
  +        m_byteBuf[m_pos++] = (byte)chars[i];;
  +        if(m_pos >= MAXCHARBUF)
  +          flushBytes();
  +      }
  +    }
  +    else
  +    {
  +      for(int i = 0; i < n; i++)
  +      {
  +        m_charBuf[m_pos++] = s.charAt(i);;
  +        if(m_pos >= MAXCHARBUF)
  +          flushChars();
  +      }
  +    }
  +  }
  +
  +  private final void flushBytes()
  +    throws SAXException
  +  {
  +    try
  +    {
  +      // System.out.println("Flushing bytes...");
  +      this.m_outputStream.write(m_byteBuf, 0, m_pos);
  +      m_pos = 0;
  +    }
  +    catch(IOException ioe)
  +    {
  +      throw new SAXException(ioe);
  +    }
  +  }
  +
  +  private final void flushChars()
  +    throws SAXException
  +  {
  +    try
  +    {
  +      // System.out.println("Flushing chars...");
  +      this.m_writer.write(m_charBuf, 0, m_pos);
  +      m_pos = 0;
  +    }
  +    catch(IOException ioe)
  +    {
  +      throw new SAXException(ioe);
  +    }
  +  }
  +  
  +  protected final void flush()
  +    throws SAXException
  +  {
  +    if(m_bytesEqualChars)
  +    {
  +      flushBytes();
  +    }
  +    else
  +    {
  +      flushChars();
  +    }
  +  }
  +
  +  /**
      * Receive notification of character data.
      *
      * <p>The Parser will call this method to report each chunk of
  @@ -811,44 +1021,45 @@
         return;
       }
       
  -    try
  +    writeParentTagEnd();
  +    m_ispreserve = true;
  +
  +    int pos = 0;
  +    int end = start+length;
  +    for (int i = start;  i < end;  i ++) 
       {
  -      writeParentTagEnd();
  -      m_ispreserve = true;
  -      int pos = 0;
  -      int end = start+length;
  -      for (int i = start;  i < end;  i ++) 
  +      char ch = chars[i];
  +      if((ch < SPECIALSSIZE) && (m_charsMap[ch] != 'S'))
         {
  -        char ch = chars[i];
  -        int chNum = (int)ch;
  +        accum(ch);
  +      }
  +      else
  +      {
           if ('\n' == ch) 
           {
  -          for(int k = 0; k < m_lineSepLen; k++)
  -          {
  -            m_charBuf[pos++] = m_lineSep.charAt(k);
  -          }
  +          outputLineSep();
           }
           else if ('<' == ch) 
           {
  -          m_charBuf[pos++] = '&';
  -          m_charBuf[pos++] = 'l';
  -          m_charBuf[pos++] = 't';
  -          m_charBuf[pos++] = ';';
  +          accum('&');
  +          accum('l');
  +          accum('t');
  +          accum(';');
           }
           else if ('>' == ch) 
           {
  -          m_charBuf[pos++] = '&';
  -          m_charBuf[pos++] = 'g';
  -          m_charBuf[pos++] = 't';
  -          m_charBuf[pos++] = ';';
  +          accum('&');
  +          accum('g');
  +          accum('t');
  +          accum(';');
           }
           else if ('&' == ch) 
           {
  -          m_charBuf[pos++] = '&';
  -          m_charBuf[pos++] = 'a';
  -          m_charBuf[pos++] = 'm';
  -          m_charBuf[pos++] = 'p';
  -          m_charBuf[pos++] = ';';
  +          accum('&');
  +          accum('a');
  +          accum('m');
  +          accum('p');
  +          accum(';');
             /**
             } else if ('"' == ch) {
             sb.append("&quot;");
  @@ -856,7 +1067,7 @@
             sb.append("&apos;");
             */
           }
  -        else if (m_isUTF8 && (0xd800 <= chNum && chNum < 0xdc00)) 
  +        else if (m_isUTF8 && (0xd800 <= ch && ch < 0xdc00)) 
           {
             // UTF-16 surrogate
             int next;
  @@ -873,63 +1084,37 @@
                   +Integer.toHexString(ch)+" "+Integer.toHexString(next));
               next = ((ch-0xd800)<<10)+next-0xdc00+0x00010000;
             }
  -          m_charBuf[pos++] = '&';
  -          m_charBuf[pos++] = '#';
  -          m_charBuf[pos++] = 'x';
  +          accum('&');
  +          accum('#');
  +          accum('x');
             String intStr = Integer.toHexString(next);
             int nIntStr = intStr.length();
             for(int k = 0; k < nIntStr; k++)
             {
  -            m_charBuf[pos++] = intStr.charAt(k);
  +            accum(intStr.charAt(k));
             }
  -          m_charBuf[pos++] = ';';
  +          accum(';');
             /*} else if (null != ctbc && !ctbc.canConvert(ch)) {
             sb.append("&#x");
             sb.append(Integer.toString((int)ch, 16));
             sb.append(";");*/
           }
  -        else if((((chNum >= 20) && (chNum <= 126)) 
  -                              || (chNum == 10)
  -                              || (chNum == 13)
  -                              || (chNum == 9)))
  -        {
  -          // System.out.println("ch: "+ch);
  -          m_charBuf[pos++] = ch;
  -        }
  -        else if((chNum >= 20) && (ch <= m_maxCharacter))
  -        {
  -          // System.out.println("ch(2): "+ch);
  -          // Hope this is right...
  -          m_charBuf[pos++] = ch;
  -        }
           else
           {
  -          m_charBuf[pos++] = '&';
  -          m_charBuf[pos++] = '#';
  -          String intStr = Integer.toString(chNum);
  +          accum('&');
  +          accum('#');
  +          String intStr = Integer.toString(ch);
             int nIntStr = intStr.length();
             for(int k = 0; k < nIntStr; k++)
             {
  -            m_charBuf[pos++] = intStr.charAt(k);
  +            accum(intStr.charAt(k));
             }
  -          m_charBuf[pos++] = ';';
  +          accum(';');
           }
  -        // Use 80 as a best guess safe buffer
  -        if(pos > MAXSAFECHARBUF)
  -        {
  -          this.m_writer.write(m_charBuf, 0, pos);
  -          pos = 0;
  -        }
         }
  -      
  -      // System.out.println(new String(m_charBuf, 0, pos));
  -      this.m_writer.write(m_charBuf, 0, pos);
  -      m_isprevtext = true;
  -    }
  -    catch(IOException ioe)
  -    {
  -      throw new SAXException("FormatterToXML.characters io error", ioe);
       }
  +    
  +    m_isprevtext = true;
     }
     
     /**
  @@ -939,17 +1124,9 @@
     public void charactersRaw (char ch[], int start, int length)
       throws SAXException
     {
  -    try
  -    {
  -      writeParentTagEnd();
  -      m_ispreserve = true;
  -      m_writer.write(ch, start, length);
  -      m_writer.flush();
  -    }
  -    catch(IOException ioe)
  -    {
  -      throw new SAXException("FormatterToXML.charactersRaw io error", ioe);
  -    }
  +    writeParentTagEnd();
  +    m_ispreserve = true;
  +    accum(ch, start, length);
     }
     
     /**
  @@ -964,12 +1141,12 @@
         char c = ch[i];
         if('\n' == c)
         {
  -        this.m_writer.write(m_lineSep);
  +        outputLineSep();
         }
         else if(isCData && (c > m_maxCharacter))
         {
           if(i != 0)
  -          this.m_writer.write("]]>");
  +          accum("]]>");
           // This needs to go into a function... 
           if (0xd800 <= ((int)c) && ((int)c) < 0xdc00) 
           {
  @@ -988,31 +1165,33 @@
                   +Integer.toHexString((int)c)+" "+Integer.toHexString(next));
               next = ((c-0xd800)<<10)+next-0xdc00+0x00010000;
             }
  -          this.m_writer.write("&#x");
  -          this.m_writer.write(Integer.toHexString(next));
  -          this.m_writer.write(";");
  +          accum('&');
  +          accum('#');
  +          accum('x');
  +          accum(Integer.toHexString(next));
  +          accum(';');
           }
           else
           {
  -          this.m_writer.write("&#");
  +          accum("&#");
             String intStr = Integer.toString((int)c);
  -          this.m_writer.write(intStr);
  -          this.m_writer.write(';');
  +          accum(intStr);
  +          accum(';');
           }
           if((i != 0) && (i < (end-1)))
  -          this.m_writer.write("<![CDATA[");
  +          accum("<![CDATA[");
         }
         else if(isCData && ((i < (end-2)) && (']' == c) && 
                             (']' == ch[i+1]) && ('>' == ch[i+2])))
         {
  -        this.m_writer.write("]]]]><![CDATA[>");
  +        accum("]]]]><![CDATA[>");
           i+=2;
         }
         else
         {
           if(c <= m_maxCharacter)
           {
  -          this.m_writer.write(c);
  +          accum(c);
           }
           // This needs to go into a function... 
           else if (0xd800 <= ((int)c) && ((int)c) < 0xdc00) 
  @@ -1032,16 +1211,16 @@
                   +Integer.toHexString((int)c)+" "+Integer.toHexString(next));
               next = ((c-0xd800)<<10)+next-0xdc00+0x00010000;
             }
  -          this.m_writer.write("&#x");
  -          this.m_writer.write(Integer.toHexString(next));
  -          this.m_writer.write(";");
  +          accum("&#x");
  +          accum(Integer.toHexString(next));
  +          accum(";");
           }
           else
           {
  -          this.m_writer.write("&#");
  +          accum("&#");
             String intStr = Integer.toString((int)c);
  -          this.m_writer.write(intStr);
  -          this.m_writer.write(';');
  +          accum(intStr);
  +          accum(';');
           }
         }
       }
  @@ -1108,19 +1287,12 @@
     public void entityReference(String name)
       throws SAXException
     {
  -    try
  -    {
  -      writeParentTagEnd();
  -      if (shouldIndent())  
  -        indent(this.m_writer, m_currentIndent);
  -      this.m_writer.write("&");
  -      this.m_writer.write(name);
  -      this.m_writer.write(";");
  -    }
  -    catch(IOException ioe)
  -    {
  -      throw new SAXException("FormatterToXML.entityReference io error", ioe);
  -    }
  +    writeParentTagEnd();
  +    if (shouldIndent())  
  +      indent(m_currentIndent);
  +    accum("&");
  +    accum(name);
  +    accum(";");
     }
   
     /**
  @@ -1133,53 +1305,53 @@
      * @return              XML-formatted string.
      * @see #backReference
      */
  -  public String prepAttrString(String string, String specials, String 
encoding)
  +  public void writeAttrString(String string, String encoding)
       throws SAXException
     {
  -    StringBuffer sb = new StringBuffer(string.length()*12/10);
  -
  -    for (int i = 0;  i < string.length();  i ++) 
  +    char[] stringChars = string.toCharArray();
  +    int len = stringChars.length;
  +    for (int i = 0;  i < len;  i ++) 
       {
  -      char ch = string.charAt(i);
  -      int chNum = (int)ch;
  -      int index = specials.indexOf(chNum);
  -      if (index >= 0) 
  +      char ch = stringChars[i];
  +      if((ch < SPECIALSSIZE) && (m_attrCharsMap[ch] != 'S'))
         {
  -        sb.append("&#");
  -        sb.append(Integer.toString(ch));
  -        sb.append(";");
  +        accum(ch);
         }
  -      else if (0xd800 <= chNum && chNum < 0xdc00) 
  +      else
         {
  -        // UTF-16 surrogate
  -        int next;
  -        if (i+1 >= string.length()) 
  +        if (0xd800 <= ch && ch < 0xdc00) 
           {
  -          throw new SAXException("Invalid UTF-16 surrogate detected: "
  -            +Integer.toHexString(ch)+ " ?");
  +          // UTF-16 surrogate
  +          int next;
  +          if (i+1 >= string.length()) 
  +          {
  +            throw new SAXException("Invalid UTF-16 surrogate detected: "
  +              +Integer.toHexString(ch)+ " ?");
  +          }
  +          else 
  +          {
  +            next = string.charAt(++i);
  +            if (!(0xdc00 <= next && next < 0xe000))
  +              throw new SAXException("Invalid UTF-16 surrogate detected: "
  +                +Integer.toHexString(ch)+" "+Integer.toHexString(next));
  +            next = ((ch-0xd800)<<10)+next-0xdc00+0x00010000;
  +          }
  +          accum("&#x");
  +          accum(Integer.toHexString(next));
  +          accum(";");
  +          /*} else if (null != ctbc && !ctbc.canConvert(ch)) {
  +          sb.append("&#x");
  +          sb.append(Integer.toString((int)ch, 16));
  +          sb.append(";");*/
           }
           else 
           {
  -          next = string.charAt(++i);
  -          if (!(0xdc00 <= next && next < 0xe000))
  -            throw new SAXException("Invalid UTF-16 surrogate detected: "
  -              +Integer.toHexString(ch)+" "+Integer.toHexString(next));
  -          next = ((ch-0xd800)<<10)+next-0xdc00+0x00010000;
  +          accum("&#");
  +          accum(Integer.toString(ch));
  +          accum(";");
           }
  -        sb.append("&#x");
  -        sb.append(Integer.toHexString(next));
  -        sb.append(";");
  -        /*} else if (null != ctbc && !ctbc.canConvert(ch)) {
  -        sb.append("&#x");
  -        sb.append(Integer.toString((int)ch, 16));
  -        sb.append(";");*/
  -      }
  -      else 
  -      {
  -        sb.append(ch);
         }
       }
  -    return sb.toString();
     }
     
     protected boolean shouldIndent()
  @@ -1193,17 +1365,10 @@
      * @param n         Number of spaces to print.
      * @exception IOException   Thrown if <var>pw</var> is invalid.
      */
  -  public static void printSpace(java.io.Writer pw, int n) throws 
SAXException 
  +  public void printSpace(int n) throws SAXException 
     {
  -    try
  -    {
  -      for (int i = 0;  i < n;  i ++)
  -        pw.write(" ");
  -    }
  -    catch(IOException ioe)
  -    {
  -      throw new SAXException("FormatterToXML.printSpace error", ioe);
  -    }
  +    for (int i = 0;  i < n;  i ++)
  +      accum(' ');
     }
   
     /**
  @@ -1212,21 +1377,14 @@
      * @param n         Number of spaces to print.
      * @exception IOException   Thrown if <var>pw</var> is invalid.
      */
  -  public void indent(java.io.Writer pw, int n) throws SAXException 
  +  public void indent(int n) throws SAXException 
     {
  -    try
  -    {
  -      if(m_startNewLine)
  -        pw.write(m_lineSep);
  -      
  -      if(m_doIndent)
  -      {
  -        printSpace(pw, n);
  -      }
  -    }
  -    catch(IOException ioe)
  +    if(m_startNewLine)
  +      outputLineSep();
  +    
  +    if(m_doIndent)
       {
  -      throw new SAXException("FormatterToXML.indent error", ioe);
  +      printSpace(n);
       }
     }
     
  
  
  

Reply via email to