You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by sb...@apache.org on 2001/05/18 09:17:30 UTC

cvs commit: xml-xalan/java/src/org/apache/xpath/objects XMLStringFactoryImpl.java XStringForChars.java XStringForFSB.java XBoolean.java XBooleanStatic.java XNodeSet.java XNumber.java XObject.java XRTreeFrag.java XString.java

sboag       01/05/18 00:17:29

  Modified:    java/src/org/apache/xalan/stree Tag: DTM_EXP
                        StreeDTMManager.java
               java/src/org/apache/xalan/templates Tag: DTM_EXP
                        FuncDocument.java FuncKey.java
               java/src/org/apache/xalan/transformer Tag: DTM_EXP
                        ClonerToResultTree.java KeyIterator.java
                        KeyManager.java KeyRefIterator.java KeyTable.java
                        KeyWalker.java ResultTreeHandler.java
                        TransformerHandlerImpl.java
               java/src/org/apache/xml/dtm Tag: DTM_EXP DTM.java
                        DTMDefaultBase.java DTMDocumentImpl.java
                        DTMManager.java DTMManagerDefault.java
                        DTMTreeWalker.java TestDTM.java
               java/src/org/apache/xml/dtm/dom2dtm Tag: DTM_EXP
                        DOM2DTM.java UnitTest.java
               java/src/org/apache/xml/dtm/sax2dtm Tag: DTM_EXP
                        SAX2DTM.java
               java/src/org/apache/xml/utils Tag: DTM_EXP
                        FastStringBuffer.java
               java/src/org/apache/xpath Tag: DTM_EXP
                        SourceTreeManager.java XPathContext.java
               java/src/org/apache/xpath/axes Tag: DTM_EXP AxesWalker.java
               java/src/org/apache/xpath/functions Tag: DTM_EXP FuncId.java
                        FuncLang.java FuncNormalizeSpace.java
                        FuncString.java FuncSubstringAfter.java
                        FuncSum.java FunctionDef1Arg.java
               java/src/org/apache/xpath/objects Tag: DTM_EXP XBoolean.java
                        XBooleanStatic.java XNodeSet.java XNumber.java
                        XObject.java XRTreeFrag.java XString.java
  Added:       java/src/org/apache/xml/utils Tag: DTM_EXP XMLString.java
                        XMLStringFactory.java
                        XMLStringWrapperForString.java
               java/src/org/apache/xpath/objects Tag: DTM_EXP
                        XMLStringFactoryImpl.java XStringForChars.java
                        XStringForFSB.java
  Log:
  I have implemented the basic XMLString architecture.  Only getStringValue
  returns an XMLString.  getNodeValue continues to return a string,
  especially since this is usually used with attribute values, which
  are already strings from SAX.
  
  An XMLStringFactory is set on the DTMManager.  This factory is
  passed to the DTM implementations.  The factory implemented by
  Xalan is in org.apache.xpath.objects.XMLStringFactoryImpl.  This
  creates XString objects which implement the XMLString interface.
  
  The XStringForFSB and XStringForChars classes subclass
  XString.  Any methods not implemented by those classes will
  fall back to the XString class, which will cause a conversion
  to string by calling the str() method.  If str() is called on these
  classes, they will cache the string they create.  Still, there may
  be some circumstances where more strings are created than
  before.  We'll have to address this during performance tuning.
  In general, many less strings should be created, and this should
  help a lot with performance.
  
  There is a XMLStringWrapperForString in org.apache.xml.utils,
  but it isn't used... I may or may not delete it at some point.
  
  I also added a couple of methods to the FastStringBuffer.  After
  we get past this next release, I have some requests for Joe for
  this class.  Also, Joe needs to review my implementation of the
  charAt function.
  
  I also fixed the SAX2DOM charactersFlush method, which,
  ahem, Joe broke with his last check in.  Simple fix to do with the
  m_data setting, which he did have a flag that it needed review.
  
  All stream-based conformance tests pass (with the exception
  of the excluded tests).
  
  Revision  Changes    Path
  No                   revision
  
  
  No                   revision
  
  
  1.1.2.4   +2 -1      xml-xalan/java/src/org/apache/xalan/stree/Attic/StreeDTMManager.java
  
  Index: StreeDTMManager.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/stree/Attic/StreeDTMManager.java,v
  retrieving revision 1.1.2.3
  retrieving revision 1.1.2.4
  diff -u -r1.1.2.3 -r1.1.2.4
  --- StreeDTMManager.java	2001/05/16 14:15:40	1.1.2.3
  +++ StreeDTMManager.java	2001/05/18 07:16:16	1.1.2.4
  @@ -155,7 +155,8 @@
   
         int documentID = m_dtms.size() << 20;
         DOMSource ds = new DOMSource(sth.getRoot(), xmlSource.getSystemId());
  -      DTM dtm = new DOM2DTM(this, ds, documentID, whiteSpaceFilter);
  +      DTM dtm = new DOM2DTM(this, ds, documentID, whiteSpaceFilter, 
  +                      org.apache.xpath.objects.XMLStringFactoryImpl.getFactory());
         int doc = sth.getDTMRoot();
         m_dtms.add(dtm);
         reader.setContentHandler(sth);
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.19.2.7  +6 -9      xml-xalan/java/src/org/apache/xalan/templates/FuncDocument.java
  
  Index: FuncDocument.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/templates/FuncDocument.java,v
  retrieving revision 1.19.2.6
  retrieving revision 1.19.2.7
  diff -u -r1.19.2.6 -r1.19.2.7
  --- FuncDocument.java	2001/05/17 05:38:46	1.19.2.6
  +++ FuncDocument.java	2001/05/18 07:16:19	1.19.2.7
  @@ -62,10 +62,6 @@
   import java.io.PrintWriter;
   import java.io.IOException;
   
  -//import org.w3c.dom.Document;
  -//import org.w3c.dom.Node;
  -//import org.w3c.dom.traversal.NodeIterator;
  -
   import org.apache.xml.dtm.DTM;
   import org.apache.xml.dtm.DTMIterator;
   import org.apache.xml.dtm.DTMManager;
  @@ -78,7 +74,6 @@
   import org.apache.xpath.objects.XNodeSet;
   import org.apache.xpath.XPath;
   import org.apache.xpath.XPathContext;
  -//import org.apache.xpath.DOMHelper;
   import org.apache.xpath.SourceTreeManager;
   import org.apache.xpath.Expression;
   import org.apache.xpath.XPathContext;
  @@ -93,9 +88,11 @@
   import javax.xml.transform.TransformerException;
   import javax.xml.transform.SourceLocator;
   import javax.xml.transform.ErrorListener;
  -import org.apache.xml.utils.SAXSourceLocator;
   import javax.xml.transform.Source;
   
  +import org.apache.xml.utils.SAXSourceLocator;
  +import org.apache.xml.utils.XMLString;
  +
   /**
    * <meta name="usage" content="advanced"/>
    * Execute the Doc() function.
  @@ -193,8 +190,8 @@
   
       while ((null == iterator) || (DTM.NULL != (pos = iterator.nextNode())))
       {
  -      String ref = (null != iterator)
  -                   ? xctxt.getDTM(pos).getStringValue(pos) : arg.str();
  +      XMLString ref = (null != iterator)
  +                   ? xctxt.getDTM(pos).getStringValue(pos) : arg.xstr();
   
         if (null == ref)
           continue;
  @@ -221,7 +218,7 @@
           base = null;
         }
   
  -      int newDoc = getDoc(xctxt, context, ref, base);
  +      int newDoc = getDoc(xctxt, context, ref.toString(), base);
   
         // nodes.mutableNodeset().addNode(newDoc);  
         if (DTM.NULL != newDoc)
  
  
  
  1.8.2.2   +4 -7      xml-xalan/java/src/org/apache/xalan/templates/FuncKey.java
  
  Index: FuncKey.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/templates/FuncKey.java,v
  retrieving revision 1.8.2.1
  retrieving revision 1.8.2.2
  diff -u -r1.8.2.1 -r1.8.2.2
  --- FuncKey.java	2001/04/10 18:44:52	1.8.2.1
  +++ FuncKey.java	2001/05/18 07:16:19	1.8.2.2
  @@ -64,7 +64,6 @@
   import org.apache.xpath.XPath;
   import org.apache.xpath.objects.XObject;
   import org.apache.xpath.objects.XNodeSet;
  -//import org.apache.xpath.DOMHelper;
   import org.apache.xpath.XPathContext;
   import org.apache.xpath.axes.LocPathIterator;
   import org.apache.xpath.axes.UnionPathIterator;
  @@ -74,13 +73,11 @@
   import org.apache.xpath.res.XPATHErrorResources;
   import org.apache.xpath.XPathContext;
   
  -//import org.w3c.dom.Node;
  -//import org.w3c.dom.Document;
  -//import org.w3c.dom.NodeList;
  -//import org.w3c.dom.traversal.NodeIterator;
   import org.apache.xml.dtm.DTM;
   import org.apache.xml.dtm.DTMIterator;
   
  +import org.apache.xml.utils.XMLString;
  +
   /**
    * <meta name="usage" content="advanced"/>
    * Execute the Key() function.
  @@ -131,7 +128,7 @@
         while (DTM.NULL != (pos = ni.nextNode()))
         {
           dtm = xctxt.getDTM(pos);
  -        String ref = dtm.getStringValue(pos);
  +        XMLString ref = dtm.getStringValue(pos);
   
           if (null == ref)
             continue;
  @@ -171,7 +168,7 @@
       }
       else
       {
  -      String ref = arg.str();
  +      XMLString ref = arg.xstr();
         LocPathIterator nl = kmgr.getNodeSetByKey(xctxt, docContext, keyname,
                                                   ref,
                                                   xctxt.getNamespaceContext());
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.9.2.3   +9 -11     xml-xalan/java/src/org/apache/xalan/transformer/ClonerToResultTree.java
  
  Index: ClonerToResultTree.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/transformer/ClonerToResultTree.java,v
  retrieving revision 1.9.2.2
  retrieving revision 1.9.2.3
  diff -u -r1.9.2.2 -r1.9.2.3
  --- ClonerToResultTree.java	2001/05/07 13:15:03	1.9.2.2
  +++ ClonerToResultTree.java	2001/05/18 07:16:22	1.9.2.3
  @@ -58,16 +58,10 @@
   
   import org.apache.xalan.templates.Stylesheet;
   
  -//import org.w3c.dom.Node;
  -//import org.w3c.dom.Text;
  -//import org.w3c.dom.Attr;
  -//import org.w3c.dom.Comment;
  -//import org.w3c.dom.CDATASection;
  -//import org.w3c.dom.ProcessingInstruction;
  -//import org.w3c.dom.EntityReference;
   import org.apache.xml.dtm.DTM;
   import org.apache.xml.dtm.DTMIterator;
   import org.apache.xml.dtm.DTMFilter;
  +import org.apache.xml.utils.XMLString;
   
   import javax.xml.transform.TransformerException;
   import org.xml.sax.Attributes;
  @@ -160,7 +154,8 @@
           m_rth.addAttribute(node);
           break;
         case DTM.COMMENT_NODE :
  -        m_rth.comment(dtm.getStringValue (node));
  +        XMLString xstr = dtm.getStringValue (node);
  +        xstr.dispatchAsComment(m_rth);
           break;
         case DTM.ENTITY_REFERENCE_NODE :
           m_rth.entityReference(dtm.getNodeNameX(node));
  @@ -168,12 +163,15 @@
         case DTM.PROCESSING_INSTRUCTION_NODE :
           {
             // %REVIEW% Is the node name the same as the "target"?
  -          m_rth.processingInstruction(dtm.getNodeNameX(node), dtm.getStringValue(node));
  +          m_rth.processingInstruction(dtm.getNodeNameX(node), 
  +                                      dtm.getNodeValue(node));
           }
           break;
         default :
  -        m_transformer.getMsgMgr().error(null, XSLTErrorResources.ER_CANT_CREATE_ITEM,
  -                                        new Object[]{ dtm.getNodeName(node) });  //"Can not create item in result tree: "+node.getNodeName());
  +        //"Can not create item in result tree: "+node.getNodeName());
  +        m_transformer.getMsgMgr().error(null, 
  +                         XSLTErrorResources.ER_CANT_CREATE_ITEM,
  +                         new Object[]{ dtm.getNodeName(node) });  
         }
       }
       catch(org.xml.sax.SAXException se)
  
  
  
  1.9.2.2   +3 -2      xml-xalan/java/src/org/apache/xalan/transformer/KeyIterator.java
  
  Index: KeyIterator.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/transformer/KeyIterator.java,v
  retrieving revision 1.9.2.1
  retrieving revision 1.9.2.2
  diff -u -r1.9.2.1 -r1.9.2.2
  --- KeyIterator.java	2001/04/10 18:45:02	1.9.2.1
  +++ KeyIterator.java	2001/05/18 07:16:24	1.9.2.2
  @@ -60,6 +60,7 @@
   
   import org.apache.xpath.axes.LocPathIterator;
   import org.apache.xml.utils.PrefixResolver;
  +import org.apache.xml.utils.XMLString;
   import org.apache.xml.utils.QName;
   import org.apache.xalan.templates.KeyDeclaration;
   import org.apache.xpath.XPathContext;
  @@ -176,7 +177,7 @@
      *
      * @param lookupKey value of the key to look for
      */
  -  public void setLookupKey(String lookupKey)
  +  public void setLookupKey(XMLString lookupKey)
     {
   
       // System.out.println("setLookupKey - lookupKey: "+lookupKey);
  @@ -207,7 +208,7 @@
      * @param ref Key value(ref)(from key use field)
      * @param node Node matching that ref 
      */
  -  void addRefNode(String ref, int node)
  +  void addRefNode(XMLString ref, int node)
     {
       m_keyTable.addRefNode(ref, node);
     }
  
  
  
  1.10.2.2  +2 -1      xml-xalan/java/src/org/apache/xalan/transformer/KeyManager.java
  
  Index: KeyManager.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/transformer/KeyManager.java,v
  retrieving revision 1.10.2.1
  retrieving revision 1.10.2.2
  diff -u -r1.10.2.1 -r1.10.2.2
  --- KeyManager.java	2001/04/10 18:45:02	1.10.2.1
  +++ KeyManager.java	2001/05/18 07:16:24	1.10.2.2
  @@ -65,6 +65,7 @@
   import org.apache.xalan.templates.ElemTemplateElement;
   import org.apache.xml.utils.QName;
   import org.apache.xml.utils.PrefixResolver;
  +import org.apache.xml.utils.XMLString;
   import org.apache.xpath.XPathContext;
   import org.apache.xpath.axes.LocPathIterator;
   
  @@ -94,7 +95,7 @@
      * @throws javax.xml.transform.TransformerException
      */
     public LocPathIterator getNodeSetByKey(
  -          XPathContext xctxt, int doc, QName name, String ref, PrefixResolver nscontext)
  +          XPathContext xctxt, int doc, QName name, XMLString ref, PrefixResolver nscontext)
               throws javax.xml.transform.TransformerException
     {
   
  
  
  
  1.6.2.2   +3 -2      xml-xalan/java/src/org/apache/xalan/transformer/KeyRefIterator.java
  
  Index: KeyRefIterator.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/transformer/KeyRefIterator.java,v
  retrieving revision 1.6.2.1
  retrieving revision 1.6.2.2
  diff -u -r1.6.2.1 -r1.6.2.2
  --- KeyRefIterator.java	2001/04/10 18:45:02	1.6.2.1
  +++ KeyRefIterator.java	2001/05/18 07:16:25	1.6.2.2
  @@ -60,6 +60,7 @@
   
   import org.apache.xpath.axes.LocPathIterator;
   import org.apache.xml.utils.QName;
  +import org.apache.xml.utils.XMLString;
   import org.apache.xalan.templates.KeyDeclaration;
   import org.apache.xpath.NodeSet;
   
  @@ -85,7 +86,7 @@
     
     /** Use field of key function.
      *  @serial         */
  -  private String m_lookupKey;  
  +  private XMLString m_lookupKey;  
     
     /** Main Key iterator for this iterator.
      *  @serial    */
  @@ -111,7 +112,7 @@
      * @param ref Key value to match
      * @param ki The main key iterator used to walk the source tree 
      */
  -  public KeyRefIterator(String ref, KeyIterator ki)
  +  public KeyRefIterator(XMLString ref, KeyIterator ki)
     {
   
       super(ki.getPrefixResolver());
  
  
  
  1.8.2.2   +3 -2      xml-xalan/java/src/org/apache/xalan/transformer/KeyTable.java
  
  Index: KeyTable.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/transformer/KeyTable.java,v
  retrieving revision 1.8.2.1
  retrieving revision 1.8.2.2
  diff -u -r1.8.2.1 -r1.8.2.2
  --- KeyTable.java	2001/04/10 18:45:02	1.8.2.1
  +++ KeyTable.java	2001/05/18 07:16:25	1.8.2.2
  @@ -75,6 +75,7 @@
   import org.apache.xalan.templates.KeyDeclaration;
   import org.apache.xpath.XPathContext;
   import org.apache.xml.utils.PrefixResolver;
  +import org.apache.xml.utils.XMLString;
   import org.apache.xpath.axes.LocPathIterator;
   
   // import org.apache.xalan.dtm.*;
  @@ -151,7 +152,7 @@
      * if the identifier is not found, it will return null,
      * otherwise it will return a LocPathIterator instance.
      */
  -  public LocPathIterator getNodeSetByKey(QName name, String ref)
  +  public LocPathIterator getNodeSetByKey(QName name, XMLString ref)
     {
   
       KeyIterator ki;
  @@ -221,7 +222,7 @@
      * @param ref Key ref(from key use field)
      * @param node Node matching that ref 
      */
  -  void addRefNode(String ref, int node)
  +  void addRefNode(XMLString ref, int node)
     {
       KeyRefIterator kiRef = null;
       Hashtable refsTable = null;
  
  
  
  1.12.2.2  +5 -9      xml-xalan/java/src/org/apache/xalan/transformer/KeyWalker.java
  
  Index: KeyWalker.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/transformer/KeyWalker.java,v
  retrieving revision 1.12.2.1
  retrieving revision 1.12.2.2
  diff -u -r1.12.2.1 -r1.12.2.2
  --- KeyWalker.java	2001/04/10 18:45:02	1.12.2.1
  +++ KeyWalker.java	2001/05/18 07:16:26	1.12.2.2
  @@ -61,6 +61,7 @@
   import org.apache.xpath.axes.LocPathIterator;
   import org.apache.xml.utils.PrefixResolver;
   import org.apache.xml.utils.QName;
  +import org.apache.xml.utils.XMLString;
   import org.apache.xalan.templates.KeyDeclaration;
   import org.apache.xalan.res.XSLMessages;
   import org.apache.xalan.res.XSLTErrorResources;
  @@ -69,11 +70,6 @@
   import org.apache.xpath.objects.XObject;
   import org.apache.xpath.XPath;
   
  -//import org.w3c.dom.Node;
  -//import org.w3c.dom.DOMException;
  -//import org.w3c.dom.NamedNodeMap;
  -//import org.w3c.dom.traversal.NodeFilter;
  -//import org.w3c.dom.traversal.NodeIterator;
   import org.apache.xml.dtm.DTM;
   import org.apache.xml.dtm.DTMIterator;
   import org.apache.xml.dtm.DTMFilter;
  @@ -119,7 +115,7 @@
   
     /** Key value that this is looking for.
      *  @serial           */
  -  String m_lookupKey;
  +  XMLString m_lookupKey;
   
     /**
      * Get the next node in document order on the axes.
  @@ -173,7 +169,7 @@
       QName name = ki.getName();
       try
       {
  -      String lookupKey = m_lookupKey;
  +      XMLString lookupKey = m_lookupKey;
   
         // System.out.println("lookupKey: "+lookupKey);
         int nDeclarations = keys.size();
  @@ -206,7 +202,7 @@
   
           if (xuse.getType() != xuse.CLASS_NODESET)
           {
  -          String exprResult = xuse.str();
  +          XMLString exprResult = xuse.xstr();
             ((KeyIterator)m_lpi).addRefNode(exprResult, testNode);
             
             if (lookupKey.equals(exprResult))
  @@ -232,7 +228,7 @@
             while (DTM.NULL != (useNode = nl.nextNode()))
             {
               DTM dtm = getDTM(useNode);
  -            String exprResult = dtm.getStringValue(useNode);
  +            XMLString exprResult = dtm.getStringValue(useNode);
               ((KeyIterator)m_lpi).addRefNode(exprResult, testNode); 
               
               if ((null != exprResult) && lookupKey.equals(exprResult))
  
  
  
  1.37.2.6  +2 -2      xml-xalan/java/src/org/apache/xalan/transformer/ResultTreeHandler.java
  
  Index: ResultTreeHandler.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/transformer/ResultTreeHandler.java,v
  retrieving revision 1.37.2.5
  retrieving revision 1.37.2.6
  diff -u -r1.37.2.5 -r1.37.2.6
  --- ResultTreeHandler.java	2001/05/14 23:03:59	1.37.2.5
  +++ ResultTreeHandler.java	2001/05/18 07:16:27	1.37.2.6
  @@ -1051,7 +1051,7 @@
             // String prefix = dtm.getPrefix(namespace);
             String prefix = dtm.getNodeNameX(namespace);
             String desturi = getURI(prefix);
  -          String srcURI = dtm.getStringValue(namespace);
  +          String srcURI = dtm.getNodeValue(namespace);
   
             if (!srcURI.equalsIgnoreCase(desturi))
             {
  @@ -1353,7 +1353,7 @@
       // %OPT% ...can I just store the node handle?    
       addAttribute(ns,
                    dtm.getLocalName(attr), dtm.getNodeName(attr),
  -                 "CDATA", dtm.getStringValue(attr));
  +                 "CDATA", dtm.getNodeValue(attr));
     }  // end copyAttributeToTarget method
   
     /**
  
  
  
  1.1.2.4   +2 -0      xml-xalan/java/src/org/apache/xalan/transformer/Attic/TransformerHandlerImpl.java
  
  Index: TransformerHandlerImpl.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/transformer/Attic/TransformerHandlerImpl.java,v
  retrieving revision 1.1.2.3
  retrieving revision 1.1.2.4
  diff -u -r1.1.2.3 -r1.1.2.4
  --- TransformerHandlerImpl.java	2001/05/16 23:28:38	1.1.2.3
  +++ TransformerHandlerImpl.java	2001/05/18 07:16:28	1.1.2.4
  @@ -74,6 +74,8 @@
   import org.xml.sax.SAXNotRecognizedException;
   import org.xml.sax.ext.LexicalHandler;
   
  +import org.apache.xpath.objects.XString;
  +
   // import org.xml.sax.ext.DeclHandler;
   import javax.xml.transform.sax.TransformerHandler;
   import javax.xml.transform.Transformer;
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.1.2.16  +3 -1      xml-xalan/java/src/org/apache/xml/dtm/Attic/DTM.java
  
  Index: DTM.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xml/dtm/Attic/DTM.java,v
  retrieving revision 1.1.2.15
  retrieving revision 1.1.2.16
  diff -u -r1.1.2.15 -r1.1.2.16
  --- DTM.java	2001/05/17 05:29:37	1.1.2.15
  +++ DTM.java	2001/05/18 07:16:35	1.1.2.16
  @@ -56,6 +56,8 @@
    */
   package org.apache.xml.dtm;
   
  +import org.apache.xml.utils.XMLString;
  +
   /**
    * <code>DTM</code> is an XML document model expressed as a table
    * rather than an object tree. It attempts to provide an interface to
  @@ -342,7 +344,7 @@
      *
      * @return A string object that represents the string-value of the given node.
      */
  -  public String getStringValue(int nodeHandle);
  +  public XMLString getStringValue(int nodeHandle);
   
     /**
      * Get number of character array chunks in
  
  
  
  1.1.2.7   +10 -2     xml-xalan/java/src/org/apache/xml/dtm/Attic/DTMDefaultBase.java
  
  Index: DTMDefaultBase.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xml/dtm/Attic/DTMDefaultBase.java,v
  retrieving revision 1.1.2.6
  retrieving revision 1.1.2.7
  diff -u -r1.1.2.6 -r1.1.2.7
  --- DTMDefaultBase.java	2001/05/17 05:29:37	1.1.2.6
  +++ DTMDefaultBase.java	2001/05/18 07:16:36	1.1.2.7
  @@ -74,6 +74,9 @@
   
   import javax.xml.transform.Source;
   
  +import org.apache.xml.utils.XMLString;
  +import org.apache.xml.utils.XMLStringFactory;
  +
   /**
    * The <code>DTMDefaultBase</code> class serves as a helper base for DTMs.
    * It sets up structures for navigation and type, while leaving data
  @@ -151,6 +154,9 @@
   
     /** Stack of flags indicating whether to strip whitespace nodes */
     protected BoolStack m_shouldStripWhitespaceStack;
  +  
  +  /** The XMLString factory for creating XMLStrings. */
  +  protected XMLStringFactory m_xstrf;
   
     /**
      * Construct a DTMDefaultBase object from a DOM node.
  @@ -163,7 +169,8 @@
      *                         be null.
      */
     public DTMDefaultBase(DTMManager mgr, Source source, int dtmIdentity,
  -                        DTMWSFilter whiteSpaceFilter)
  +                        DTMWSFilter whiteSpaceFilter,
  +                        XMLStringFactory xstringfactory)
     {
   
       m_mgr = mgr;
  @@ -171,6 +178,7 @@
       m_dtmIdent = dtmIdentity;
       m_mask = mgr.getNodeIdentityMask();
       m_wsfilter = whiteSpaceFilter;
  +    m_xstrf = xstringfactory;
   
       if (null != whiteSpaceFilter)
       {
  @@ -873,7 +881,7 @@
      *
      * @return A string object that represents the string-value of the given node.
      */
  -  public abstract String getStringValue(int nodeHandle);
  +  public abstract XMLString getStringValue(int nodeHandle);
   
     /**
      * Get number of character array chunks in
  
  
  
  1.1.2.19  +11 -4     xml-xalan/java/src/org/apache/xml/dtm/Attic/DTMDocumentImpl.java
  
  Index: DTMDocumentImpl.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xml/dtm/Attic/DTMDocumentImpl.java,v
  retrieving revision 1.1.2.18
  retrieving revision 1.1.2.19
  diff -u -r1.1.2.18 -r1.1.2.19
  --- DTMDocumentImpl.java	2001/05/17 05:29:37	1.1.2.18
  +++ DTMDocumentImpl.java	2001/05/18 07:16:37	1.1.2.19
  @@ -68,6 +68,9 @@
   import org.xml.sax.Attributes;
   import org.xml.sax.ext.LexicalHandler;
   
  +import org.apache.xml.utils.XMLString;
  +import org.apache.xml.utils.XMLStringFactory;
  +
   /**
    * This is the implementation of the DTM document interface.  It receives
    * requests from an XML content handler similar to that of an XML DOM or SAX parser
  @@ -188,6 +191,8 @@
           // an interface _implemented_ by this class... which might be simplest!
           private ExpandedNameTable m_expandedNames=
                   new ExpandedNameTable(m_localNames,m_nsNames);
  +                
  +        private XMLStringFactory m_xsf;
     
   
           /**
  @@ -201,8 +206,10 @@
            * document.
            */
           public DTMDocumentImpl(DTMManager mgr, int documentNumber, 
  -                               DTMWSFilter whiteSpaceFilter){
  +                               DTMWSFilter whiteSpaceFilter,
  +                               XMLStringFactory xstringfactory){
                   initDocument(documentNumber);	 // clear nodes and document handle
  +                m_xsf = xstringfactory;
           }
   
     /** Bind a CoroutineParser to this DTM. If we discover we need nodes
  @@ -1453,7 +1460,7 @@
            *
            * @return A string object that represents the string-value of the given node.
            */
  -        public String getStringValue(int nodeHandle) {
  +        public XMLString getStringValue(int nodeHandle) {
           // ###zaj - researching 
           nodes.readSlot(nodeHandle, gotslot);
           int nodetype=gotslot[0] & 0xFF;		
  @@ -1463,7 +1470,7 @@
           case TEXT_NODE:   
           case COMMENT_NODE:
           case CDATA_SECTION_NODE: 
  -                value=m_char.getString(gotslot[2], gotslot[3]);		
  +                value= m_char.getString(gotslot[2], gotslot[3]);		
                   break;
           case PROCESSING_INSTRUCTION_NODE:
           case ATTRIBUTE_NODE:	
  @@ -1472,7 +1479,7 @@
           default:
                   break;
           }
  -        return value; 
  +        return m_xsf.newstr( value ); 
                  
           }
   
  
  
  
  1.1.2.12  +337 -262  xml-xalan/java/src/org/apache/xml/dtm/Attic/DTMManager.java
  
  Index: DTMManager.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xml/dtm/Attic/DTMManager.java,v
  retrieving revision 1.1.2.11
  retrieving revision 1.1.2.12
  diff -u -r1.1.2.11 -r1.1.2.12
  --- DTMManager.java	2001/05/17 05:29:37	1.1.2.11
  +++ DTMManager.java	2001/05/18 07:16:37	1.1.2.12
  @@ -62,12 +62,13 @@
   import java.io.InputStream;
   import java.io.InputStreamReader;
   import java.io.BufferedReader;
  - 
  +
   import java.util.Properties;
   import java.util.Enumeration;
   
  - 
   import org.apache.xml.utils.PrefixResolver;
  +import org.apache.xml.utils.XMLString;
  +import org.apache.xml.utils.XMLStringFactory;
   
   /**
    * A DTMManager instance can be used to create DTM and
  @@ -77,103 +78,140 @@
    * to create is named "org.apache.xml.utils.DTMFactory". This
    * property names a concrete subclass of the DTMFactory abstract
    *  class. If the property is not defined, a platform default is be used.</p>
  - *  
  - * <p>An instance of this class <emph>must</emph> be safe to use across 
  - * thread instances.  It is expected that a client will create a single instance 
  - * of a DTMManager to use across multiple threads.  This will allow sharing 
  + *
  + * <p>An instance of this class <emph>must</emph> be safe to use across
  + * thread instances.  It is expected that a client will create a single instance
  + * of a DTMManager to use across multiple threads.  This will allow sharing
    * of DTMs across multiple processes.</p>
  - *  
  - * <p>Note: this class is incomplete right now.  It will be pretty much 
  - * modeled after javax.xml.transform.TransformerFactory in terms of its 
  + *
  + * <p>Note: this class is incomplete right now.  It will be pretty much
  + * modeled after javax.xml.transform.TransformerFactory in terms of its
    * factory support.</p>
  - * 
  + *
    * <p>State: In progress!!</p>
    */
   public abstract class DTMManager
   {
  +
  +  /** The default property name according to the JAXP spec. */
  +  private static final String defaultPropName =
  +    "org.apache.xml.dtm.DTMManager";
  +
  +  /**
  +   * The default table for exandedNameID lookups.
  +   */
  +  private static ExpandedNameTable m_expandedNameTable =
  +    new ExpandedNameTable();
   
  -   /** The default property name according to the JAXP spec. */
  -   private static final String defaultPropName =
  -       "org.apache.xml.dtm.DTMManager";
  -      
  -   /**
  -    * The default table for exandedNameID lookups.
  -    */ 
  -   private static ExpandedNameTable m_expandedNameTable = new ExpandedNameTable();
  +  /**
  +   * Factory for creating XMLString objects.
  +   *  %TBD% Make this set by the caller.
  +   */
  +  protected XMLStringFactory m_xsf = null;
   
     /**
      * Default constructor is protected on purpose.
      */
     protected DTMManager(){}
  +
  +  /**
  +   * Get the XMLStringFactory used for the DTMs.
  +   *
  +   *
  +   * @return a valid XMLStringFactory object, or null if it hasn't been set yet.
  +   */
  +  public XMLStringFactory getXMLStringFactory()
  +  {
  +    return m_xsf;
  +  }
   
  -     /**
  -      * Obtain a new instance of a <code>DTMManager</code>.
  -      * This static method creates a new factory instance 
  -      * This method uses the following ordered lookup procedure to determine
  -      * the <code>DTMManager</code> implementation class to
  -      * load:
  -      * <ul>
  -      * <li>
  -      * Use the <code>javax.xml.parsers.DocumentBuilderFactory</code> system
  -      * property.
  -      * </li>
  -      * <li>
  -      * Use the JAVA_HOME(the parent directory where jdk is
  -      * installed)/lib/jaxp.properties for a property file that contains the
  -      * name of the implementation class keyed on the same value as the
  -      * system property defined above.
  -      * </li>
  -      * <li>
  -      * Use the Services API (as detailed in teh JAR specification), if
  -      * available, to determine the classname. The Services API will look
  -      * for a classname in the file
  -      * <code>META-INF/services/javax.xml.parsers.DTMManager</code>
  -      * in jars available to the runtime.
  -      * </li>
  -      * <li>
  -      * Platform default <code>DTMManager</code> instance.
  -      * </li>
  -      * </ul>
  -      *
  -      * Once an application has obtained a reference to a <code>
  -      * DTMManager</code> it can use the factory to configure
  -      * and obtain parser instances.
  -      *
  -      * @return new DTMManager instance, never null.
  -      *
  -      * @throws DTMConfigurationException
  -      * if the implmentation is not available or cannot be instantiated.
  -      */
  -     public static DTMManager newInstance()
  -             throws DTMConfigurationException {
  - 
  -         String classname =
  -             findFactory(defaultPropName,
  -                         "org.apache.xml.dtm.DTMManagerDefault");
  - 
  -         if (classname == null) {
  -             throw new DTMConfigurationException(
  -                 "No default implementation found");
  -         }
  - 
  -         DTMManager factoryImpl;
  - 
  -         try {
  -             Class clazz = Class.forName(classname);
  - 
  -             factoryImpl = (DTMManager) clazz.newInstance();
  -         } catch (ClassNotFoundException cnfe) {
  -             throw new DTMConfigurationException(cnfe);
  -         } catch (IllegalAccessException iae) {
  -             throw new DTMConfigurationException(iae);
  -         } catch (InstantiationException ie) {
  -             throw new DTMConfigurationException(ie);
  -         }
  - 
  -         return factoryImpl;
  -     }
  +  /**
  +   * Set the XMLStringFactory used for the DTMs.
  +   *
  +   *
  +   * @param xsf a valid XMLStringFactory object, should not be null.
  +   */
  +  public void setXMLStringFactory(XMLStringFactory xsf)
  +  {
  +    m_xsf = xsf;
  +  }
   
     /**
  +   * Obtain a new instance of a <code>DTMManager</code>.
  +   * This static method creates a new factory instance
  +   * This method uses the following ordered lookup procedure to determine
  +   * the <code>DTMManager</code> implementation class to
  +   * load:
  +   * <ul>
  +   * <li>
  +   * Use the <code>javax.xml.parsers.DocumentBuilderFactory</code> system
  +   * property.
  +   * </li>
  +   * <li>
  +   * Use the JAVA_HOME(the parent directory where jdk is
  +   * installed)/lib/jaxp.properties for a property file that contains the
  +   * name of the implementation class keyed on the same value as the
  +   * system property defined above.
  +   * </li>
  +   * <li>
  +   * Use the Services API (as detailed in teh JAR specification), if
  +   * available, to determine the classname. The Services API will look
  +   * for a classname in the file
  +   * <code>META-INF/services/javax.xml.parsers.DTMManager</code>
  +   * in jars available to the runtime.
  +   * </li>
  +   * <li>
  +   * Platform default <code>DTMManager</code> instance.
  +   * </li>
  +   * </ul>
  +   *
  +   * Once an application has obtained a reference to a <code>
  +   * DTMManager</code> it can use the factory to configure
  +   * and obtain parser instances.
  +   *
  +   * @return new DTMManager instance, never null.
  +   *
  +   * @throws DTMConfigurationException
  +   * if the implmentation is not available or cannot be instantiated.
  +   */
  +  public static DTMManager newInstance(XMLStringFactory xsf) 
  +           throws DTMConfigurationException
  +  {
  +
  +    String classname = findFactory(defaultPropName,
  +                                   "org.apache.xml.dtm.DTMManagerDefault");
  +
  +    if (classname == null)
  +    {
  +      throw new DTMConfigurationException("No default implementation found");
  +    }
  +
  +    DTMManager factoryImpl;
  +
  +    try
  +    {
  +      Class clazz = Class.forName(classname);
  +
  +      factoryImpl = (DTMManager) clazz.newInstance();
  +    }
  +    catch (ClassNotFoundException cnfe)
  +    {
  +      throw new DTMConfigurationException(cnfe);
  +    }
  +    catch (IllegalAccessException iae)
  +    {
  +      throw new DTMConfigurationException(iae);
  +    }
  +    catch (InstantiationException ie)
  +    {
  +      throw new DTMConfigurationException(ie);
  +    }
  +    factoryImpl.setXMLStringFactory(xsf);
  +
  +    return factoryImpl;
  +  }
  +
  +  /**
      * Get an instance of a DTM, loaded with the content from the
      * specified source.  If the unique flag is true, a new instance will
      * always be returned.  Otherwise it is up to the DTMManager to return a
  @@ -182,21 +220,22 @@
      * (I think more parameters will need to be added for error handling, and entity
      * resolution).
      *
  -   * @param source the specification of the source object, which may be null, 
  -   *               in which case it is assumed that node construction will take 
  +   * @param source the specification of the source object, which may be null,
  +   *               in which case it is assumed that node construction will take
      *               by some other means.
      * @param unique true if the returned DTM must be unique, probably because it
      * is going to be mutated.
  -   * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may 
  +   * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
      *                         be null.
  -   * @param incremental true if the construction should try and be incremental.
  +   * @param incremental true if the DTM should be built incrementally, if
  +   *                    possible.
      *
      * @return a non-null DTM reference.
      */
     public abstract DTM getDTM(javax.xml.transform.Source source,
                                boolean unique, DTMWSFilter whiteSpaceFilter,
                                boolean incremental);
  -                             
  +
     /**
      * Get the instance of DTM that "owns" a node handle.
      *
  @@ -205,34 +244,34 @@
      * @return a non-null DTM reference.
      */
     public abstract DTM getDTM(int nodeHandle);
  -  
  +
     /**
      * Given a W3C DOM node, try and return a DTM handle.
      * Note: calling this may be non-optimal.
  -   * 
  +   *
      * @param node Non-null reference to a DOM node.
  -   * 
  +   *
      * @return a valid DTM handle.
      */
     public abstract int getDTMHandleFromNode(org.w3c.dom.Node node);
  -  
  +
     /**
  -   * Creates a DTM representing an empty <code>DocumentFragment</code> object. 
  +   * Creates a DTM representing an empty <code>DocumentFragment</code> object.
      * @return a non-null DTM reference.
      */
     public abstract DTM createDocumentFragment();
  -  
  +
     /**
      * Release a DTM either to a lru pool, or completely remove reference.
      * DTMs without system IDs are always hard deleted.
      * State: experimental.
  -   * 
  +   *
      * @param dtm The DTM to be released.
      * @param shouldHardDelete True if the DTM should be removed no matter what.
      * @return true if the DTM was removed, false if it was put back in a lru pool.
      */
     public abstract boolean release(DTM dtm, boolean shouldHardDelete);
  -  
  +
     /**
      * Create a new <code>DTMIterator</code> based on an XPath
      * <a href="http://www.w3.org/TR/xpath#NT-LocationPath>LocationPath</a> or
  @@ -267,9 +306,9 @@
     /**
      * Create a new <code>DTMIterator</code> based only on a whatToShow
      * and a DTMFilter.  The traversal semantics are defined as the
  -   * descendant access. 
  +   * descendant access.
      * <p>
  -   * Note that DTMIterators may not be an exact match to DOM 
  +   * Note that DTMIterators may not be an exact match to DOM
      * NodeIterators. They are initialized and used in much the same way
      * as a NodeIterator, but their response to document mutation is not
      * currently defined.
  @@ -285,10 +324,10 @@
      *   whether entity reference nodes are expanded.
      *
      * @return The newly created <code>DTMIterator</code>.
  -   * */
  +   */
     public abstract DTMIterator createDTMIterator(int whatToShow,
             DTMFilter filter, boolean entityReferenceExpansion);
  -          
  +
     /**
      * Create a new <code>DTMIterator</code> that holds exactly one node.
      *
  @@ -297,166 +336,202 @@
      * @return The newly created <code>DTMIterator</code>.
      */
     public abstract DTMIterator createDTMIterator(int node);
  +
  +  // -------------------- private methods --------------------
  +
  +  /**
  +   * Avoid reading all the files when the findFactory
  +   * method is called the second time (cache the result of
  +   * finding the default impl).
  +   */
  +  private static String foundFactory = null;
  +
  +  /**
  +   * Temp debug code - this will be removed after we test everything
  +   */
  +  private static boolean debug;
   
  -   
  -     // -------------------- private methods --------------------
  - 
  -     /**
  -      * Avoid reading all the files when the findFactory
  -      * method is called the second time (cache the result of
  -      * finding the default impl).
  -      */
  -     private static String foundFactory = null;
  -     
  -     /**
  -      * Temp debug code - this will be removed after we test everything
  -      */
  -     private static boolean debug;
  -     static {
  -         try {
  -             debug = System.getProperty("dtm.debug") != null;
  -         } catch( SecurityException ex ) {}
  -     }
  - 
  -     /**
  -      * Private implementation method - will find the implementation
  -      * class in the specified order.
  -      *
  -      * @param factoryId   Name of the factory interface.
  -      * @param xmlProperties Name of the properties file based on JAVA/lib.
  -      * @param defaultFactory Default implementation, if nothing else is found.
  -      *
  -      * @return The factory class name.
  -      */
  -     private static String findFactory(String factoryId,
  -                                       String defaultFactory) {
  - 
  -         // Use the system property first
  -         try {
  -             String systemProp = null;
  -             try {
  -                 systemProp = System.getProperty(factoryId);
  -             } catch( SecurityException se ) {}
  - 
  -             if (systemProp != null) {
  -                 if (debug) {
  -                     System.err.println("DTM: found system property"
  -                                        + systemProp);
  -                 }
  - 
  -                 return systemProp;
  -             }
  -         } catch (SecurityException se) {}
  - 
  -         if (foundFactory != null) {
  -             return foundFactory;
  -         }
  - 
  -         // try to read from $java.home/lib/jaxp.properties
  -         try {
  -             String javah      = System.getProperty("java.home");
  -             String configFile = javah + File.separator + "lib"
  -                                 + File.separator + "jaxp.properties";
  -             File   f          = new File(configFile);
  - 
  -             if (f.exists()) {
  -                 Properties props = new Properties();
  - 
  -                 props.load(new FileInputStream(f));
  - 
  -                 foundFactory = props.getProperty(factoryId);
  - 
  -                 if (debug) {
  -                     System.err.println("DTM: found java.home property "
  -                                        + foundFactory);
  -                 }
  - 
  -                 if (foundFactory != null) {
  -                     return foundFactory;
  -                 }
  -             }
  -         } catch (Exception ex) {
  -             if (debug) {
  -                 ex.printStackTrace();
  -             }
  -         }
  - 
  -         String serviceId = "META-INF/services/" + factoryId;
  - 
  -         // try to find services in CLASSPATH
  -         try {
  -             ClassLoader cl = DTMManager.class.getClassLoader();
  -             InputStream is = null;
  - 
  -             if (cl == null) {
  -                 is = ClassLoader.getSystemResourceAsStream(serviceId);
  -             } else {
  -                 is = cl.getResourceAsStream(serviceId);
  -             }
  - 
  -             if (is != null) {
  -                 if (debug) {
  -                     System.err.println("DTM: found  " + serviceId);
  -                 }
  - 
  -                 BufferedReader rd =
  -                     new BufferedReader(new InputStreamReader(is));
  - 
  -                 foundFactory = rd.readLine();
  - 
  -                 rd.close();
  - 
  -                 if (debug) {
  -                     System.err.println("DTM: loaded from services: "
  -                                        + foundFactory);
  -                 }
  - 
  -                 if ((foundFactory != null) &&!"".equals(foundFactory)) {
  -                     return foundFactory;
  -                 }
  -             }
  -         } catch (Exception ex) {
  -             if (debug) {
  -                 ex.printStackTrace();
  -             }
  -         }
  - 
  -         return defaultFactory;
  -     }
  -     
  -     /** %TBD% Doc */
  -     static final int IDENT_DTM_DEFAULT = 0xFFF00000;
  -     
  -     /** %TBD% Doc */
  -     static final int IDENT_NODE_DEFAULT = 0x000FFFFF;
  -     
  -     /**
  -      * %TBD% Doc
  -      */
  -     public abstract int getDTMIdentity(DTM dtm);
  -     
  -     /**
  -      * %TBD% Doc
  -      */
  -     public int getDTMIdentityMask()
  -     {
  -       return IDENT_DTM_DEFAULT;
  -     }
  - 
  -     /**
  -      * %TBD% Doc
  -      */
  -     public int getNodeIdentityMask()
  -     {
  -       return IDENT_NODE_DEFAULT;
  -     }
  -     
  -     /**
  -      * return the expanded name table.
  -      */
  -     public ExpandedNameTable getExpandedNameTable(DTM dtm)
  -     {
  -       return m_expandedNameTable;
  -     }
  -          
  +  static
  +  {
  +    try
  +    {
  +      debug = System.getProperty("dtm.debug") != null;
  +    }
  +    catch (SecurityException ex){}
  +  }
  +
  +  /**
  +   * Private implementation method - will find the implementation
  +   * class in the specified order.
  +   *
  +   * @param factoryId   Name of the factory interface.
  +   * @param xmlProperties Name of the properties file based on JAVA/lib.
  +   * @param defaultFactory Default implementation, if nothing else is found.
  +   *
  +   * @return The factory class name.
  +   */
  +  private static String findFactory(String factoryId, String defaultFactory)
  +  {
  +
  +    // Use the system property first
  +    try
  +    {
  +      String systemProp = null;
  +
  +      try
  +      {
  +        systemProp = System.getProperty(factoryId);
  +      }
  +      catch (SecurityException se){}
  +
  +      if (systemProp != null)
  +      {
  +        if (debug)
  +        {
  +          System.err.println("DTM: found system property" + systemProp);
  +        }
  +
  +        return systemProp;
  +      }
  +    }
  +    catch (SecurityException se){}
  +
  +    if (foundFactory != null)
  +    {
  +      return foundFactory;
  +    }
  +
  +    // try to read from $java.home/lib/jaxp.properties
  +    try
  +    {
  +      String javah = System.getProperty("java.home");
  +      String configFile = javah + File.separator + "lib" + File.separator
  +                          + "jaxp.properties";
  +      File f = new File(configFile);
  +
  +      if (f.exists())
  +      {
  +        Properties props = new Properties();
  +
  +        props.load(new FileInputStream(f));
  +
  +        foundFactory = props.getProperty(factoryId);
  +
  +        if (debug)
  +        {
  +          System.err.println("DTM: found java.home property " + foundFactory);
  +        }
  +
  +        if (foundFactory != null)
  +        {
  +          return foundFactory;
  +        }
  +      }
  +    }
  +    catch (Exception ex)
  +    {
  +      if (debug)
  +      {
  +        ex.printStackTrace();
  +      }
  +    }
  +
  +    String serviceId = "META-INF/services/" + factoryId;
  +
  +    // try to find services in CLASSPATH
  +    try
  +    {
  +      ClassLoader cl = DTMManager.class.getClassLoader();
  +      InputStream is = null;
  +
  +      if (cl == null)
  +      {
  +        is = ClassLoader.getSystemResourceAsStream(serviceId);
  +      }
  +      else
  +      {
  +        is = cl.getResourceAsStream(serviceId);
  +      }
  +
  +      if (is != null)
  +      {
  +        if (debug)
  +        {
  +          System.err.println("DTM: found  " + serviceId);
  +        }
  +
  +        BufferedReader rd = new BufferedReader(new InputStreamReader(is));
  +
  +        foundFactory = rd.readLine();
  +
  +        rd.close();
  +
  +        if (debug)
  +        {
  +          System.err.println("DTM: loaded from services: " + foundFactory);
  +        }
  +
  +        if ((foundFactory != null) &&!"".equals(foundFactory))
  +        {
  +          return foundFactory;
  +        }
  +      }
  +    }
  +    catch (Exception ex)
  +    {
  +      if (debug)
  +      {
  +        ex.printStackTrace();
  +      }
  +    }
  +
  +    return defaultFactory;
  +  }
  +
  +  /** %TBD% Doc */
  +  static final int IDENT_DTM_DEFAULT = 0xFFF00000;
  +
  +  /** %TBD% Doc */
  +  static final int IDENT_NODE_DEFAULT = 0x000FFFFF;
  +
  +  /**
  +   * %TBD% Doc
  +   *
  +   * NEEDSDOC @param dtm
  +   *
  +   * NEEDSDOC ($objectName$) @return
  +   */
  +  public abstract int getDTMIdentity(DTM dtm);
  +
  +  /**
  +   * %TBD% Doc
  +   *
  +   * NEEDSDOC ($objectName$) @return
  +   */
  +  public int getDTMIdentityMask()
  +  {
  +    return IDENT_DTM_DEFAULT;
  +  }
  +
  +  /**
  +   * %TBD% Doc
  +   *
  +   * NEEDSDOC ($objectName$) @return
  +   */
  +  public int getNodeIdentityMask()
  +  {
  +    return IDENT_NODE_DEFAULT;
  +  }
  +
  +  /**
  +   * return the expanded name table.
  +   *
  +   * NEEDSDOC @param dtm
  +   *
  +   * NEEDSDOC ($objectName$) @return
  +   */
  +  public ExpandedNameTable getExpandedNameTable(DTM dtm)
  +  {
  +    return m_expandedNameTable;
  +  }
   }
  
  
  
  1.1.2.16  +45 -31    xml-xalan/java/src/org/apache/xml/dtm/Attic/DTMManagerDefault.java
  
  Index: DTMManagerDefault.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xml/dtm/Attic/DTMManagerDefault.java,v
  retrieving revision 1.1.2.15
  retrieving revision 1.1.2.16
  diff -u -r1.1.2.15 -r1.1.2.16
  --- DTMManagerDefault.java	2001/05/17 05:29:37	1.1.2.15
  +++ DTMManagerDefault.java	2001/05/18 07:16:38	1.1.2.16
  @@ -88,6 +88,9 @@
   import org.xml.sax.ext.DeclHandler;
   import org.xml.sax.ext.LexicalHandler;
   
  +import org.apache.xml.utils.XMLString;
  +import org.apache.xml.utils.XMLStringFactory;
  +
   /**
    * The default implementation for the DTMManager.
    */
  @@ -103,7 +106,7 @@
      */
     public DTMManagerDefault(){}
   
  -  /** NEEDSDOC Field DUMPTREE */
  +  /** Set this to true if you want a dump of the DTM after creation. */
     private static final boolean DUMPTREE = false;
   
     /**
  @@ -120,7 +123,8 @@
      * is going to be mutated.
      * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
      *                         be null.
  -   * NEEDSDOC @param incremental
  +   * @param incremental true if the DTM should be built incrementally, if
  +   *                    possible.
      *
      * @return a non-null DTM reference.
      */
  @@ -128,12 +132,13 @@
                       DTMWSFilter whiteSpaceFilter, boolean incremental)
     {
   
  +    XMLStringFactory xstringFactory = m_xsf;
       int documentID = m_dtms.size() << 20;
   
       if ((null != source) && source instanceof DOMSource)
       {
         DOM2DTM dtm = new DOM2DTM(this, (DOMSource) source, documentID,
  -                                whiteSpaceFilter);
  +                                whiteSpaceFilter, xstringFactory);
   
         m_dtms.add(dtm);
   
  @@ -147,8 +152,10 @@
       }
       else
       {
  -      boolean isSAXSource = (null != source) ? (source instanceof SAXSource) : true;
  -      boolean isStreamSource = (null != source) ? (source instanceof StreamSource) : false;
  +      boolean isSAXSource = (null != source)
  +                            ? (source instanceof SAXSource) : true;
  +      boolean isStreamSource = (null != source)
  +                               ? (source instanceof StreamSource) : false;
   
         if (isSAXSource || isStreamSource)
         {
  @@ -185,16 +192,18 @@
           }
   
           // Create the basic SAX2DTM.
  -        SAX2DTM dtm = new SAX2DTM(this, source, documentID, whiteSpaceFilter);
  +        SAX2DTM dtm = new SAX2DTM(this, source, documentID, whiteSpaceFilter,
  +                                  xstringFactory);
   
           // Go ahead and add the DTM to the lookup table.  This needs to be 
           // done before any parsing occurs.
           m_dtms.add(dtm);
  -        
  -        boolean haveXercesParser = null != reader && 
  -                        reader instanceof org.apache.xerces.parsers.SAXParser;
  -                        
  -        if(haveXercesParser)
  +
  +        boolean haveXercesParser =
  +          null != reader
  +          && reader instanceof org.apache.xerces.parsers.SAXParser;
  +
  +        if (haveXercesParser)
             incremental = true;  // No matter what.  %REVIEW%
   
           if (incremental)
  @@ -209,24 +218,25 @@
             int appCoroutine = coroutineManager.co_joinCoroutineSet(-1);
             CoroutineParser coParser;
   
  -           if(haveXercesParser)
  +          if (haveXercesParser)
             {
  +
               // CoroutineSAXParser_Xerces to avoid threading.
               // System.out.println("Using CoroutineSAXParser_Xerces to avoid threading");
  -            coParser = 
  -              new CoroutineSAXParser_Xerces(
  -                              (org.apache.xerces.parsers.SAXParser)reader,
  -                              coroutineManager, appCoroutine);
  +            coParser = new CoroutineSAXParser_Xerces(
  +              (org.apache.xerces.parsers.SAXParser) reader, coroutineManager,
  +              appCoroutine);
             }
             else
             {
   
               // Create a CoroutineSAXParser that will run on the secondary thread.
  -            if(null == reader)
  -              coParser = new CoroutineSAXParser(coroutineManager, appCoroutine);
  +            if (null == reader)
  +              coParser = new CoroutineSAXParser(coroutineManager,
  +                                                appCoroutine);
               else
  -              coParser = new CoroutineSAXParser(coroutineManager, appCoroutine,
  -                                                reader);
  +              coParser = new CoroutineSAXParser(coroutineManager,
  +                                                appCoroutine, reader);
             }
   
             // Have the DTM set itself up as the CoroutineSAXParser's listener.
  @@ -237,7 +247,7 @@
   
             if (null == xmlSource)
             {
  -  
  +
               // Then the user will construct it themselves.
               return dtm;
             }
  @@ -251,7 +261,7 @@
             // pass the registration through to the reader if that's the Right Thng
             reader.setDTDHandler(dtm);
             reader.setErrorHandler(dtm);
  -          
  +
             try
             {
   
  @@ -290,8 +300,9 @@
           }
           else
           {
  -          if(null == reader)
  +          if (null == reader)
             {
  +
               // Then the user will construct it themselves.
               return dtm;
             }
  @@ -348,25 +359,28 @@
         }
       }
     }
  -  
  +
     /**
      * Given a W3C DOM node, try and return a DTM handle.
      * Note: calling this may be non-optimal.
  -   * 
  +   *
      * @param node Non-null reference to a DOM node.
  -   * 
  +   *
      * @return a valid DTM handle.
      */
     public int getDTMHandleFromNode(org.w3c.dom.Node node)
     {
  -    if(node instanceof org.apache.xml.dtm.DTMNodeProxy)
  -      return ((org.apache.xml.dtm.DTMNodeProxy)node).getDTMNodeNumber();
  +
  +    if (node instanceof org.apache.xml.dtm.DTMNodeProxy)
  +      return ((org.apache.xml.dtm.DTMNodeProxy) node).getDTMNodeNumber();
       else
       {
  +
         // %REVIEW% Maybe the best I can do??
         // Or should I first search all the DTMs??
  -      DTM dtm = getDTM(new javax.xml.transform.dom.DOMSource(node), false, 
  -                   null, true);
  +      DTM dtm = getDTM(new javax.xml.transform.dom.DOMSource(node), false,
  +                       null, true);
  +
         return dtm.getDocument();
       }
     }
  @@ -522,7 +536,7 @@
     }
   
     /**
  -   * NEEDSDOC Method createDocumentFragment
  +   * Method createDocumentFragment
      *
      *
      * NEEDSDOC (createDocumentFragment) @return
  
  
  
  1.1.2.6   +5 -6      xml-xalan/java/src/org/apache/xml/dtm/Attic/DTMTreeWalker.java
  
  Index: DTMTreeWalker.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xml/dtm/Attic/DTMTreeWalker.java,v
  retrieving revision 1.1.2.5
  retrieving revision 1.1.2.6
  diff -u -r1.1.2.5 -r1.1.2.6
  --- DTMTreeWalker.java	2001/05/16 05:33:20	1.1.2.5
  +++ DTMTreeWalker.java	2001/05/18 07:16:38	1.1.2.6
  @@ -62,6 +62,7 @@
   import org.xml.sax.ext.LexicalHandler;
   
   import org.apache.xml.utils.NodeConsumer;
  +import org.apache.xml.utils.XMLString;
   
   /**
    * <meta name="usage" content="advanced"/>
  @@ -253,13 +254,12 @@
       {
       case DTM.COMMENT_NODE :
       {
  -      String data = m_dtm.getStringValue(node);
  +      XMLString data = m_dtm.getStringValue(node);
   
         if (m_contentHandler instanceof LexicalHandler)
         {
           LexicalHandler lh = ((LexicalHandler) this.m_contentHandler);
  -
  -        lh.comment(data.toCharArray(), 0, data.length());
  +        data.dispatchAsComment(lh);
         }
       }
       break;
  @@ -279,8 +279,7 @@
           // String prefix = dtm.getPrefix(nsn);
           String prefix = dtm.getNodeNameX(nsn);
   
  -        this.m_contentHandler.startPrefixMapping(prefix,
  -                                                 dtm.getStringValue(nsn));
  +        this.m_contentHandler.startPrefixMapping(prefix, dtm.getNodeValue(nsn));
           
         }
   
  @@ -323,7 +322,7 @@
         else
         {
           this.m_contentHandler.processingInstruction(name,
  -                                                    m_dtm.getStringValue(node));
  +                                                    m_dtm.getNodeValue(node));
         }
       }
       break;
  
  
  
  1.1.2.9   +2 -1      xml-xalan/java/src/org/apache/xml/dtm/Attic/TestDTM.java
  
  Index: TestDTM.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xml/dtm/Attic/TestDTM.java,v
  retrieving revision 1.1.2.8
  retrieving revision 1.1.2.9
  diff -u -r1.1.2.8 -r1.1.2.9
  --- TestDTM.java	2001/05/11 03:11:36	1.1.2.8
  +++ TestDTM.java	2001/05/18 07:16:39	1.1.2.9
  @@ -28,7 +28,8 @@
        *   <C>My Anaconda<D/>Words</C>
        *  </top> */
   
  -    DTMDocumentImpl doc = new DTMDocumentImpl(null, 0, null);
  +    DTMDocumentImpl doc = new DTMDocumentImpl(null, 0, null, 
  +                    org.apache.xpath.objects.XMLStringFactoryImpl.getFactory());
   
       try
         {
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.1.2.15  +11 -6     xml-xalan/java/src/org/apache/xml/dtm/dom2dtm/Attic/DOM2DTM.java
  
  Index: DOM2DTM.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xml/dtm/dom2dtm/Attic/DOM2DTM.java,v
  retrieving revision 1.1.2.14
  retrieving revision 1.1.2.15
  diff -u -r1.1.2.14 -r1.1.2.15
  --- DOM2DTM.java	2001/05/17 05:38:47	1.1.2.14
  +++ DOM2DTM.java	2001/05/18 07:16:46	1.1.2.15
  @@ -75,6 +75,9 @@
   
   import org.apache.xml.utils.NodeVector;
   
  +import org.apache.xml.utils.XMLString;
  +import org.apache.xml.utils.XMLStringFactory;
  +
   /**
    * The <code>DOM2DTM</code> class serves up a DOM via a DTM API.
    */
  @@ -144,9 +147,10 @@
      *                         be null.
      */
     public DOM2DTM(DTMManager mgr, DOMSource domSource, 
  -                 int dtmIdentity, DTMWSFilter whiteSpaceFilter)
  +                 int dtmIdentity, DTMWSFilter whiteSpaceFilter,
  +                 XMLStringFactory xstringfactory)
     {
  -    super(mgr, domSource, dtmIdentity, whiteSpaceFilter);
  +    super(mgr, domSource, dtmIdentity, whiteSpaceFilter, xstringfactory);
   
       m_root = domSource.getNode();
       m_pos = null;
  @@ -577,12 +581,13 @@
      *
      * @return A string object that represents the string-value of the given node.
      */
  -  public String getStringValue(int nodeHandle)
  +  public XMLString getStringValue(int nodeHandle)
     {
   
       int type = getNodeType(nodeHandle);
       Node node = getNode(nodeHandle);
  -    // %REVIEW%
  +    // %TBD% If an element only has one text node, we should just use it 
  +    // directly.
       if(DTM.ELEMENT_NODE == type || DTM.DOCUMENT_NODE == type 
       || DTM.DOCUMENT_FRAGMENT_NODE == type)
       {
  @@ -600,10 +605,10 @@
           StringBufferPool.free(buf);
         }
     
  -      return s;
  +      return m_xstrf.newstr( s );
   
       }
  -    return node.getNodeValue();
  +    return m_xstrf.newstr( node.getNodeValue() );
     }
     
     /**
  
  
  
  1.1.2.5   +2 -1      xml-xalan/java/src/org/apache/xml/dtm/dom2dtm/Attic/UnitTest.java
  
  Index: UnitTest.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xml/dtm/dom2dtm/Attic/UnitTest.java,v
  retrieving revision 1.1.2.4
  retrieving revision 1.1.2.5
  diff -u -r1.1.2.4 -r1.1.2.5
  --- UnitTest.java	2001/05/16 05:33:21	1.1.2.4
  +++ UnitTest.java	2001/05/18 07:16:46	1.1.2.5
  @@ -121,7 +121,8 @@
       
       Document doc = db.parse(new InputSource(sr));
       
  -    DTMManager dtmMgr = DTMManager.newInstance();
  +    DTMManager dtmMgr = DTMManager.newInstance(
  +                 org.apache.xpath.objects.XMLStringFactoryImpl.getFactory());
       DTM dtm = dtmMgr.getDTM(new DOMSource(doc), true, null, true);
       
       int docHandle = dtm.getDocument();
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.1.2.14  +79 -70    xml-xalan/java/src/org/apache/xml/dtm/sax2dtm/Attic/SAX2DTM.java
  
  Index: SAX2DTM.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xml/dtm/sax2dtm/Attic/SAX2DTM.java,v
  retrieving revision 1.1.2.13
  retrieving revision 1.1.2.14
  diff -u -r1.1.2.13 -r1.1.2.14
  --- SAX2DTM.java	2001/05/17 21:43:55	1.1.2.13
  +++ SAX2DTM.java	2001/05/18 07:16:50	1.1.2.14
  @@ -70,6 +70,8 @@
   import org.apache.xml.utils.XMLCharacterRecognizer;
   import org.apache.xml.utils.SystemIDResolver;
   import org.apache.xml.dtm.*;
  +import org.apache.xml.utils.XMLString;
  +import org.apache.xml.utils.XMLStringFactory;
   
   /**
    * This class implements a DTM that tends to be optimized more for speed than
  @@ -149,9 +151,10 @@
     /** Type of next characters() event within text block in prgress. */
     transient private int m_textType = DTM.TEXT_NODE;
   
  -  /** Type of coalesced text block. See logic in the characters()
  +  /**
  +   * Type of coalesced text block. See logic in the characters()
      * method.
  -   * */
  +   */
     transient private int m_coalescedTextType = DTM.TEXT_NODE;
   
     /** The SAX Document locator */
  @@ -162,7 +165,7 @@
   
     /** pool of string values that come as strings. */
     private DTMStringPool m_valuesOrPrefixes = new DTMStringPool();
  -  
  +
     /** End document has been reached. */
     private boolean m_endDocumentOccured = false;
   
  @@ -237,12 +240,14 @@
      * @param dtmIdentity The DTM identity ID for this DTM.
      * @param whiteSpaceFilter The white space filter for this DTM, which may
      *                         be null.
  +   * @param xstringfactory XMLString factory for creating character content.
      */
     public SAX2DTM(DTMManager mgr, Source source, int dtmIdentity,
  -                 DTMWSFilter whiteSpaceFilter)
  +                 DTMWSFilter whiteSpaceFilter,
  +                 XMLStringFactory xstringfactory)
     {
   
  -    super(mgr, source, dtmIdentity, whiteSpaceFilter);
  +    super(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory);
   
       m_ent = mgr.getExpandedNameTable(this);
   
  @@ -269,7 +274,7 @@
     {
       return m_appCoroutineID;
     }
  -  
  +
     /**
      * Ask the CoRoutine parser to doTerminate and clear the reference.
      */
  @@ -277,16 +282,22 @@
     {
       clearCoRoutine(true);
     }
  -  
  +
     /**
  -   * Ask the CoRoutine parser to doTerminate and clear the reference.
  +   * Ask the CoRoutine parser to doTerminate and clear the reference. If 
  +   * the CoRoutine parser has already been cleared, this will have no effect.
  +   *
  +   * @param callDoTerminate true of doTerminate should be called on the 
  +   * coRoutine parser.
      */
     public void clearCoRoutine(boolean callDoTerminate)
     {
  -    if(null != m_coroutineParser)
  +
  +    if (null != m_coroutineParser)
       {
  -      if(callDoTerminate)
  +      if (callDoTerminate)
           m_coroutineParser.doTerminate(m_appCoroutineID);
  +
         m_coroutineParser = null;
       }
     }
  @@ -331,7 +342,7 @@
       //coroutineParser.setDTDHandler(this);
       //coroutineParser.setDeclHandler(this);
     }
  -  
  +
     /**
      * getContentHandler returns "our SAX builder" -- the thing that
      * someone else should send SAX events to in order to extend this
  @@ -352,7 +363,7 @@
       else
         return this;
     }
  -  
  +
     /**
      * Return this DTM's lexical handler.
      *
  @@ -371,7 +382,7 @@
       else
         return this;
     }
  -  
  +
     /**
      * Return this DTM's EntityResolver.
      *
  @@ -379,10 +390,9 @@
      */
     public EntityResolver getEntityResolver()
     {
  -
       return this;
     }
  -  
  +
     /**
      * Return this DTM's DTDHandler.
      *
  @@ -390,7 +400,6 @@
      */
     public DTDHandler getDTDHandler()
     {
  -
       return this;
     }
   
  @@ -401,10 +410,9 @@
      */
     public ErrorHandler getErrorHandler()
     {
  -
       return this;
     }
  -  
  +
     /**
      * Return this DTM's DeclHandler.
      *
  @@ -412,10 +420,8 @@
      */
     public DeclHandler getDeclHandler()
     {
  -
       return this;
  -  }  
  -  
  +  }
   
     /**
      * @return true iff we're building this model incrementally (eg
  @@ -648,8 +654,9 @@
   
       while (identity >= m_size)
       {
  -      if(null == m_coroutineParser)
  +      if (null == m_coroutineParser)
           return DTM.NULL;
  +
         nextNode();
       }
   
  @@ -675,7 +682,7 @@
       {
         treeWalker = new DTMTreeWalker();
       }
  -    
  +
       treeWalker.setcontentHandler(ch);
       treeWalker.setDTM(this);
   
  @@ -720,8 +727,8 @@
   
       if (null == m_coroutineParser)
         return false;
  -    
  -    if(m_endDocumentOccured)
  +
  +    if (m_endDocumentOccured)
       {
         clearCoRoutine();
   
  @@ -729,7 +736,7 @@
       }
   
       Object gotMore = m_coroutineParser.doMore(true, m_appCoroutineID);
  -   
  +
       // gotMore may be a Boolean (TRUE if still parsing, FALSE if
       // EOF) or an exception if CoroutineParser malfunctioned
       // (code error rather than user error).
  @@ -1103,7 +1110,7 @@
      *
      * @return A string object that represents the string-value of the given node.
      */
  -  public String getStringValue(int nodeHandle)
  +  public XMLString getStringValue(int nodeHandle)
     {
   
       int identity = nodeHandle & m_mask;
  @@ -1115,8 +1122,7 @@
         int offset = m_data.elementAt(dataIndex);
         int length = m_data.elementAt(dataIndex + 1);
   
  -      // %OPT% We should cache this, I guess.
  -      return m_chars.getString(offset, length);
  +      return m_xstrf.newstr(m_chars, offset, length);
       }
       else
       {
  @@ -1152,9 +1158,7 @@
   
           if (length > 0)
           {
  -
  -          // %OPT% We should cache this, I guess.
  -          return m_chars.getString(offset, length);
  +          return m_xstrf.newstr(m_chars, offset, length);
           }
         }
         else
  @@ -1167,11 +1171,11 @@
             dataIndex = m_data.elementAt(dataIndex + 1);
           }
   
  -        return m_valuesOrPrefixes.indexToString(dataIndex);
  +        return m_xstrf.newstr(m_valuesOrPrefixes.indexToString(dataIndex));
         }
       }
   
  -    return "";
  +    return m_xstrf.emptystr();
     }
   
     /**
  @@ -1196,20 +1200,21 @@
   
       Integer intObj;
       boolean isMore = true;
  +
       do
       {
         intObj = (Integer) m_idAttributes.get(elementId);
  -  
  +
         if (null != intObj)
           return intObj.intValue();
  -        
  -      if(!isMore || m_endDocumentOccured)
  +
  +      if (!isMore || m_endDocumentOccured)
           break;
  -      
  +
         isMore = nextNode();
       }
  -      while(null == intObj);
  -    
  +    while (null == intObj);
  +
       return DTM.NULL;
     }
   
  @@ -1288,32 +1293,34 @@
      */
     protected void charactersFlush()
     {
  -    if (m_textPendingStart >= 0 ) // -1 indicates no-text-in-progress
  -    {
  -      int length=m_chars.size()-m_textPendingStart;
   
  +    if (m_textPendingStart >= 0)  // -1 indicates no-text-in-progress
  +    {
  +      int length = m_chars.size() - m_textPendingStart;
         boolean doStrip = false;
  +
         if (getShouldStripWhitespace())
  -	{
  -	  doStrip=m_chars.isWhitespace(m_textPendingStart, length);
  -	}
  +      {
  +        doStrip = m_chars.isWhitespace(m_textPendingStart, length);
  +      }
   
  -      if(doStrip)
  -	m_chars.setLength(m_textPendingStart); // Discard accumulated text
  +      if (doStrip)
  +        m_chars.setLength(m_textPendingStart);  // Discard accumulated text
         else
  -	{
  -	  int exName = m_ent.getExpandedNameID(DTM.TEXT_NODE);
  +      {
  +        int exName = m_ent.getExpandedNameID(DTM.TEXT_NODE);
  +        int dataIndex = m_data.size();
  +
  +        m_previous = addNode(m_coalescedTextType, exName, m_level,
  +                             m_parents.peek(), m_previous, dataIndex, false);
   
  -	  int nodeIndex= addNode(m_coalescedTextType,exName,m_level,
  -				 m_parents.peek(),m_previous,
  -				 m_textPendingStart,false);
  -	  // %REVIEW% I _think_ I've got this right...
  -	  m_data.setElementAt(nodeIndex,length);
  -	}
  -      
  +        m_data.addElement(m_textPendingStart);
  +        m_data.addElement(length);
  +      }
  +
         // Reset for next text block
  -      m_textPendingStart=-1;
  -      m_textType=m_coalescedTextType=DTM.TEXT_NODE;
  +      m_textPendingStart = -1;
  +      m_textType = m_coalescedTextType = DTM.TEXT_NODE;
       }
     }
   
  @@ -1406,7 +1413,8 @@
   
       try
       {
  -      systemId = SystemIDResolver.getAbsoluteURI(systemId, getDocumentBaseURI());
  +      systemId = SystemIDResolver.getAbsoluteURI(systemId,
  +                                                 getDocumentBaseURI());
       }
       catch (Exception e)
       {
  @@ -1495,9 +1503,8 @@
       m_contextIndexes = null;
   
       m_level--;
  -    
  +
       m_endDocumentOccured = true;
  -    
     }
   
     /**
  @@ -1793,19 +1800,21 @@
      */
     public void characters(char ch[], int start, int length) throws SAXException
     {
  -    if(m_textPendingStart==-1)	// First one in this block
  -      {
  -	m_textPendingStart=m_chars.size();
  -	m_coalescedTextType=m_textType;
  -      }
  -    m_chars.append(ch,start,length);
  +
  +    if (m_textPendingStart == -1)  // First one in this block
  +    {
  +      m_textPendingStart = m_chars.size();
  +      m_coalescedTextType = m_textType;
  +    }
  +
  +    m_chars.append(ch, start, length);
   
       // Type logic: If all adjacent text is CDATASections, the
       // concatentated text is treated as a single CDATASection (see
       // initialization above).  If any were ordinary Text, the whole
       // thing is treated as Text. This may be worth %REVIEW%ing.
  -    if(m_textType==DTM.TEXT_NODE)
  -	m_coalescedTextType=DTM.TEXT_NODE;
  +    if (m_textType == DTM.TEXT_NODE)
  +      m_coalescedTextType = DTM.TEXT_NODE;
     }
   
     /**
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.10.2.1  +633 -426  xml-xalan/java/src/org/apache/xml/utils/FastStringBuffer.java
  
  Index: FastStringBuffer.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xml/utils/FastStringBuffer.java,v
  retrieving revision 1.10
  retrieving revision 1.10.2.1
  diff -u -r1.10 -r1.10.2.1
  --- FastStringBuffer.java	2001/03/23 18:23:22	1.10
  +++ FastStringBuffer.java	2001/05/18 07:16:53	1.10.2.1
  @@ -2,7 +2,7 @@
    * The Apache Software License, Version 1.1
    *
    *
  - * Copyright (c) 1999 The Apache Software Foundation.  All rights
  + * Copyright (c) 1999 The Apache Software Foundation.  All rights 
    * reserved.
    *
    * Redistribution and use in source and binary forms, with or without
  @@ -59,7 +59,7 @@
   /**
    * Bare-bones, unsafe, fast string buffer. No thread-safety, no
    * parameter range checking, exposed fields. Note that in typical
  - * applications, thread-safety of a StringBuffer is a somewhat 
  + * applications, thread-safety of a StringBuffer is a somewhat
    * dubious concept in any case.
    * <p>
    * Note that Stree is using a single FastStringBuffer as a string pool,
  @@ -79,49 +79,61 @@
    * theory, RTFs might want to be tuned differently from the main
    * document's text.
    * <p>
  - * */
  + */
   public class FastStringBuffer
   {
  -  /** Field m_chunkBits sets our chunking strategy, by saying how many
  +
  +  /**
  +   * Field m_chunkBits sets our chunking strategy, by saying how many
      * bits of index can be used within a single chunk before flowing over
      * to the next chunk. For example, if m_chunkbits is set to 15, each
  -   * chunk can contain up to 2^15 (32K) characters  */
  -  int m_chunkBits=15;
  -        
  -  /** Field m_maxChunkBits affects our chunk-growth strategy, by saying what
  -   * the largest permissible chunk size is in this particular FastStringBuffer 
  -   * hierarchy. */
  -  int m_maxChunkBits=15;
  -  
  -  /** Field m_rechunkBits affects our chunk-growth strategy, by saying how
  +   * chunk can contain up to 2^15 (32K) characters  
  +   */
  +  int m_chunkBits = 15;
  +
  +  /**
  +   * Field m_maxChunkBits affects our chunk-growth strategy, by saying what
  +   * the largest permissible chunk size is in this particular FastStringBuffer
  +   * hierarchy. 
  +   */
  +  int m_maxChunkBits = 15;
  +
  +  /**
  +   * Field m_rechunkBits affects our chunk-growth strategy, by saying how
      * many chunks should be allocated at one size before we encapsulate them
      * into the first chunk of the next size up. For example, if m_rechunkBits
      * is set to 3, then after 8 chunks at a given size we will rebundle
      * them as the first element of a FastStringBuffer using a chunk size
      * 8 times larger (chunkBits shifted left three bits).
      */
  -  int m_rebundleBits=2;
  +  int m_rebundleBits = 2;
   
  -  /** Field m_chunkSize establishes the maximum size of one chunk of the array
  +  /**
  +   * Field m_chunkSize establishes the maximum size of one chunk of the array
      * as 2**chunkbits characters.
  -   * (Which may also be the minimum size if we aren't tuning for storage) */
  -  int m_chunkSize; // =1<<(m_chunkBits-1);
  -  
  -  /** Field m_chunkMask is m_chunkSize-1 -- in other words, m_chunkBits
  +   * (Which may also be the minimum size if we aren't tuning for storage) 
  +   */
  +  int m_chunkSize;  // =1<<(m_chunkBits-1);
  +
  +  /**
  +   * Field m_chunkMask is m_chunkSize-1 -- in other words, m_chunkBits
      * worth of low-order '1' bits, useful for shift-and-mask addressing
  -   * within the chunks. */
  -  int m_chunkMask; // =m_chunkSize-1;
  +   * within the chunks. 
  +   */
  +  int m_chunkMask;  // =m_chunkSize-1;
   
  -  /** Field m_array holds the string buffer's text contents, using an
  -   * array-of-arrays. Note that this array, and the arrays it contains, may be 
  -   * reallocated when necessary in order to allow the buffer to grow; 
  +  /**
  +   * Field m_array holds the string buffer's text contents, using an
  +   * array-of-arrays. Note that this array, and the arrays it contains, may be
  +   * reallocated when necessary in order to allow the buffer to grow;
      * references to them should be considered to be invalidated after any
      * append. However, the only time these arrays are directly exposed
      * is in the sendSAXcharacters call.
      */
     char[][] m_array;
   
  -  /** Field m_lastChunk is an index into m_array[], pointing to the last
  +  /**
  +   * Field m_lastChunk is an index into m_array[], pointing to the last
      * chunk of the Chunked Array currently in use. Note that additional
      * chunks may actually be allocated, eg if the FastStringBuffer had
      * previously been truncated or if someone issued an ensureSpace request.
  @@ -131,20 +143,23 @@
      */
     int m_lastChunk = 0;
   
  -  /** Field m_firstFree is an index into m_array[m_lastChunk][], pointing to 
  +  /**
  +   * Field m_firstFree is an index into m_array[m_lastChunk][], pointing to
      * the first character in the Chunked Array which is not part of the
  -   * FastStringBuffer's current content. Since m_array[][] is zero-based, 
  -   * the length of that content can be calculated as 
  -   * (m_lastChunk<<m_chunkBits) + m_firstFree */
  +   * FastStringBuffer's current content. Since m_array[][] is zero-based,
  +   * the length of that content can be calculated as
  +   * (m_lastChunk<<m_chunkBits) + m_firstFree 
  +   */
     int m_firstFree = 0;
  -  
  -  /** Field m_innerFSB, when non-null, is a FastStringBuffer whose total
  +
  +  /**
  +   * Field m_innerFSB, when non-null, is a FastStringBuffer whose total
      * length equals m_chunkSize, and which replaces m_array[0]. This allows
      * building a hierarchy of FastStringBuffers, where early appends use
      * a smaller chunkSize (for less wasted memory overhead) but later
      * ones use a larger chunkSize (for less heap activity overhead).
      */
  -  FastStringBuffer m_innerFSB=null;
  +  FastStringBuffer m_innerFSB = null;
   
     /**
      * Construct a FastStringBuffer, with allocation policy as per parameters.
  @@ -156,41 +171,45 @@
      * <p>
      * An alternative would be to accept integer sizes and round to powers of two;
      * that really doesn't seem to buy us much, if anything.
  -   * 
  -   * @param initChunkBits Length in characters of the initial allocation 
  -   * of a chunk, expressed in log-base-2. (That is, 10 means allocate 1024 
  +   *
  +   * @param initChunkBits Length in characters of the initial allocation
  +   * of a chunk, expressed in log-base-2. (That is, 10 means allocate 1024
      * characters.) Later chunks will use larger allocation units, to trade off
  -   * allocation speed of large document against storage efficiency of small 
  +   * allocation speed of large document against storage efficiency of small
      * ones.
      * @param maxChunkBits Number of character-offset bits that should be used for
  -   * addressing within a chunk. Maximum length of a chunk is 2^chunkBits 
  +   * addressing within a chunk. Maximum length of a chunk is 2^chunkBits
      * characters.
      * @param rebundleBits Number of character-offset bits that addressing should
      * advance before we attempt to take a step from initChunkBits to maxChunkBits
      */
  -  public FastStringBuffer(int initChunkBits,int maxChunkBits, int rebundleBits)
  +  public FastStringBuffer(int initChunkBits, int maxChunkBits,
  +                          int rebundleBits)
     {
  +
       m_array = new char[16][];
   
       // Don't bite off more than we're prepared to swallow!
  -    if(initChunkBits>maxChunkBits)
  -      initChunkBits=maxChunkBits;
  -        
  -    m_chunkBits=initChunkBits;
  -    m_maxChunkBits=maxChunkBits;
  -    m_rebundleBits=rebundleBits;
  -        
  -    m_chunkSize=1<<(initChunkBits);
  -    m_chunkMask=m_chunkSize-1;
  +    if (initChunkBits > maxChunkBits)
  +      initChunkBits = maxChunkBits;
  +
  +    m_chunkBits = initChunkBits;
  +    m_maxChunkBits = maxChunkBits;
  +    m_rebundleBits = rebundleBits;
  +    m_chunkSize = 1 << (initChunkBits);
  +    m_chunkMask = m_chunkSize - 1;
       m_array[0] = new char[m_chunkSize];
     }
   
     /**
      * Construct a FastStringBuffer, using a default rebundleBits value.
  +   *
  +   * NEEDSDOC @param initChunkBits
  +   * NEEDSDOC @param maxChunkBits
      */
  -  public FastStringBuffer(int initChunkBits,int maxChunkBits)
  +  public FastStringBuffer(int initChunkBits, int maxChunkBits)
     {
  -          this(initChunkBits,maxChunkBits,2);
  +    this(initChunkBits, maxChunkBits, 2);
     }
   
     /**
  @@ -199,27 +218,30 @@
      * <p>
      * ISSUE: Should this call assert initial size, or fixed size?
      * Now configured as initial, with a default for fixed.
  +   *
  +   * @param
      *
  -   * @param 
  +   * NEEDSDOC @param initChunkBits
      */
     public FastStringBuffer(int initChunkBits)
     {
  -    this(initChunkBits,15,2);
  +    this(initChunkBits, 15, 2);
     }
  +
     /**
      * Construct a FastStringBuffer, using a default allocation policy.
      */
     public FastStringBuffer()
     {
  +
       // 10 bits is 1K. 15 bits is 32K. Remember that these are character
       // counts, so actual memory allocation unit is doubled for UTF-16 chars.
       //
       // For reference: In the original FastStringBuffer, we simply
       // overallocated by blocksize (default 1KB) on each buffer-growth.
  -    this(10,15,2);
  +    this(10, 15, 2);
     }
   
  -
     /**
      * Get the length of the list. Synonym for length().
      *
  @@ -227,7 +249,7 @@
      */
     public final int size()
     {
  -        return (m_lastChunk<<m_chunkBits) + m_firstFree;
  +    return (m_lastChunk << m_chunkBits) + m_firstFree;
     }
   
     /**
  @@ -237,7 +259,7 @@
      */
     public final int length()
     {
  -    return (m_lastChunk<<m_chunkBits) + m_firstFree;
  +    return (m_lastChunk << m_chunkBits) + m_firstFree;
     }
   
     /**
  @@ -247,22 +269,26 @@
      */
     public final void reset()
     {
  +
       m_lastChunk = 0;
       m_firstFree = 0;
  -	
  -	// Recover the original chunk size
  -	FastStringBuffer innermost=this;
  -	while(innermost.m_innerFSB!=null)
  -		innermost=innermost.m_innerFSB;
  -	m_chunkBits=innermost.m_chunkBits;
  -	m_chunkSize=innermost.m_chunkSize;
  -	m_chunkMask=innermost.m_chunkMask;
  -	 
  -	// Discard the hierarchy
  -	m_innerFSB  = null;
  +
  +    // Recover the original chunk size
  +    FastStringBuffer innermost = this;
   
  -	m_array=new char[16][0];
  -	m_array[0]=new char[m_chunkSize];
  +    while (innermost.m_innerFSB != null)
  +    {
  +      innermost = innermost.m_innerFSB;
  +    }
  +
  +    m_chunkBits = innermost.m_chunkBits;
  +    m_chunkSize = innermost.m_chunkSize;
  +    m_chunkMask = innermost.m_chunkMask;
  +
  +    // Discard the hierarchy
  +    m_innerFSB = null;
  +    m_array = new char[16][0];
  +    m_array[0] = new char[m_chunkSize];
     }
   
     /**
  @@ -280,72 +306,83 @@
      * the inner FSB, and extending the append operations to recurse
      * into the inner FSB when space exists within them. Could be done,
      * but nontrivial change and adds some overhead to the append
  -   * operation. Consider alternatives. *****
  +   * operation. Consider alternatives. 
      *
      * @param l New length. If l<0 or l>=getLength(), this operation will
      * not report an error but future operations will almost certainly fail.
      */
     public final void setLength(int l)
     {
  -	m_lastChunk = l >>> m_chunkBits;
  -	if(m_lastChunk==0 && m_innerFSB!=null)
  -	{
  -		m_innerFSB.setLength(l,this);
  -	}
  -	else
  -	{
  -		m_firstFree = l  &  m_chunkMask;
  -	}
  +
  +    m_lastChunk = l >>> m_chunkBits;
  +
  +    if (m_lastChunk == 0 && m_innerFSB != null)
  +    {
  +      m_innerFSB.setLength(l, this);
  +    }
  +    else
  +    {
  +      m_firstFree = l & m_chunkMask;
  +    }
     }
  -  
  -  /** Subroutine for the public setLength() method. Deals with the fact
  +
  +  /**
  +   * Subroutine for the public setLength() method. Deals with the fact
      * that truncation may require restoring one of the innerFSBs
  +   *
  +   * NEEDSDOC @param l
  +   * NEEDSDOC @param rootFSB
      */
     final void setLength(int l, FastStringBuffer rootFSB)
     {
  -	m_lastChunk = l >>> m_chunkBits;
  -	if(m_lastChunk==0 && m_innerFSB!=null)
  -	{
  -		m_innerFSB.setLength(l,rootFSB);
  -	}
  -	else
  -	{
  -		// Undo encapsulation -- pop the innerFSB data back up to root.
  -		rootFSB.m_chunkBits   =m_chunkBits;
  -        rootFSB.m_maxChunkBits=m_maxChunkBits;
  -        rootFSB.m_rebundleBits=m_rebundleBits;
  -        rootFSB.m_chunkSize   =m_chunkSize;
  -        rootFSB.m_chunkMask   =m_chunkMask;
  -        rootFSB.m_array       =m_array; 
  -		rootFSB.m_innerFSB    =m_innerFSB;
  -		rootFSB.m_lastChunk   =m_lastChunk; 
  -		
  -		// Finally, truncate this sucker.
  -		rootFSB.m_firstFree = l  &  m_chunkMask;
  -	}
  +
  +    m_lastChunk = l >>> m_chunkBits;
  +
  +    if (m_lastChunk == 0 && m_innerFSB != null)
  +    {
  +      m_innerFSB.setLength(l, rootFSB);
  +    }
  +    else
  +    {
  +
  +      // Undo encapsulation -- pop the innerFSB data back up to root.
  +      rootFSB.m_chunkBits = m_chunkBits;
  +      rootFSB.m_maxChunkBits = m_maxChunkBits;
  +      rootFSB.m_rebundleBits = m_rebundleBits;
  +      rootFSB.m_chunkSize = m_chunkSize;
  +      rootFSB.m_chunkMask = m_chunkMask;
  +      rootFSB.m_array = m_array;
  +      rootFSB.m_innerFSB = m_innerFSB;
  +      rootFSB.m_lastChunk = m_lastChunk;
  +
  +      // Finally, truncate this sucker.
  +      rootFSB.m_firstFree = l & m_chunkMask;
  +    }
     }
   
     /**
      * Note that this operation has been somewhat deoptimized by the shift to a
  -   * chunked array, as there is no factory method to produce a String object 
  +   * chunked array, as there is no factory method to produce a String object
      * directly from an array of arrays and hence a double copy is needed.
  -   * By using ensureCapacity we hope to minimize the heap overhead of building 
  +   * By using ensureCapacity we hope to minimize the heap overhead of building
      * the intermediate StringBuffer.
      * <p>
      * (It really is a pity that Java didn't design String as a final subclass
      * of MutableString, rather than having StringBuffer be a separate hierarchy.
      * We'd avoid a <strong>lot</strong> of double-buffering.)
  -   * 
  +   *
      * @return the contents of the FastStringBuffer as a standard Java string.
      */
     public final String toString()
     {
  -	int length=(m_lastChunk<<m_chunkBits)+m_firstFree;
  -    return getString(new StringBuffer(length),0,0,length).toString();
  +
  +    int length = (m_lastChunk << m_chunkBits) + m_firstFree;
  +
  +    return getString(new StringBuffer(length), 0, 0, length).toString();
     }
   
     /**
  -   * Append a single character onto the FastStringBuffer, growing the 
  +   * Append a single character onto the FastStringBuffer, growing the
      * storage if necessary.
      * <p>
      * NOTE THAT after calling append(), previously obtained
  @@ -356,51 +393,59 @@
      */
     public final void append(char value)
     {
  +
       char[] chunk;
  -          
  +
       // We may have preallocated chunks. If so, all but last should
       // be at full size.
  -    boolean lastchunk=(m_lastChunk+1==m_array.length);
  -          
  -    if(m_firstFree<m_chunkSize) // Simplified test single-character-fits
  -      chunk=m_array[m_lastChunk];
  -          
  +    boolean lastchunk = (m_lastChunk + 1 == m_array.length);
  +
  +    if (m_firstFree < m_chunkSize)  // Simplified test single-character-fits
  +      chunk = m_array[m_lastChunk];
       else
  +    {
  +
  +      // Extend array?
  +      int i = m_array.length;
  +
  +      if (m_lastChunk + 1 == i)
         {
  -        // Extend array?
  -        int i=m_array.length;
  -        if(m_lastChunk+1==i)
  -          {
  -            char[][] newarray=new char[i+16][];
  -            System.arraycopy(m_array,0,newarray,0,i);
  -            m_array=newarray;
  -          }
  -                  
  -        // Advance one chunk
  -        chunk=m_array[++m_lastChunk];
  -        if(chunk==null)
  -          {
  -                // Hierarchical encapsulation
  -                if(m_lastChunk==1<<m_rebundleBits && m_chunkBits<m_maxChunkBits)
  -                {
  -                  // Should do all the work of both encapsulating
  -                  // existing data and establishing new sizes/offsets
  -                  m_innerFSB=new FastStringBuffer(this);
  -                }
  -                                
  -            // Add a chunk.
  -            chunk=m_array[m_lastChunk]=new char[m_chunkSize];
  -          }
  -                  
  -        m_firstFree=0;
  +        char[][] newarray = new char[i + 16][];
  +
  +        System.arraycopy(m_array, 0, newarray, 0, i);
  +
  +        m_array = newarray;
  +      }
  +
  +      // Advance one chunk
  +      chunk = m_array[++m_lastChunk];
  +
  +      if (chunk == null)
  +      {
  +
  +        // Hierarchical encapsulation
  +        if (m_lastChunk == 1 << m_rebundleBits
  +                && m_chunkBits < m_maxChunkBits)
  +        {
  +
  +          // Should do all the work of both encapsulating
  +          // existing data and establishing new sizes/offsets
  +          m_innerFSB = new FastStringBuffer(this);
  +        }
  +
  +        // Add a chunk.
  +        chunk = m_array[m_lastChunk] = new char[m_chunkSize];
         }
   
  +      m_firstFree = 0;
  +    }
  +
       // Space exists in the chunk. Append the character.
  -    chunk[m_firstFree++]=value;
  +    chunk[m_firstFree++] = value;
     }
   
     /**
  -   * Append the contents of a String onto the FastStringBuffer, 
  +   * Append the contents of a String onto the FastStringBuffer,
      * growing the storage if necessary.
      * <p>
      * NOTE THAT after calling append(), previously obtained
  @@ -410,57 +455,73 @@
      */
     public final void append(String value)
     {
  -    int strlen=value.length();
  +
  +    int strlen = value.length();
  +
       if (0 == strlen)
         return;
  -    int copyfrom=0;
  -    char[] chunk=m_array[m_lastChunk];
  -    int available=m_chunkSize-m_firstFree;
  -          
  +
  +    int copyfrom = 0;
  +    char[] chunk = m_array[m_lastChunk];
  +    int available = m_chunkSize - m_firstFree;
  +
       // Repeat while data remains to be copied
  -    while(strlen>0)
  +    while (strlen > 0)
  +    {
  +
  +      // Copy what fits
  +      if (available > strlen)
  +        available = strlen;
  +
  +      value.getChars(copyfrom, copyfrom + available, m_array[m_lastChunk],
  +                     m_firstFree);
  +
  +      strlen -= available;
  +      copyfrom += available;
  +
  +      // If there's more left, allocate another chunk and continue
  +      if (strlen > 0)
         {
  -        // Copy what fits
  -        if(available>strlen) available=strlen;
  -        value.getChars(copyfrom, copyfrom+available, m_array[m_lastChunk], m_firstFree);
  -        strlen-=available;
  -        copyfrom+=available;
  -                  
  -        // If there's more left, allocate another chunk and continue
  -        if(strlen>0)
  +
  +        // Extend array?
  +        int i = m_array.length;
  +
  +        if (m_lastChunk + 1 == i)
  +        {
  +          char[][] newarray = new char[i + 16][];
  +
  +          System.arraycopy(m_array, 0, newarray, 0, i);
  +
  +          m_array = newarray;
  +        }
  +
  +        // Advance one chunk
  +        chunk = m_array[++m_lastChunk];
  +
  +        if (chunk == null)
  +        {
  +
  +          // Hierarchical encapsulation
  +          if (m_lastChunk == 1 << m_rebundleBits
  +                  && m_chunkBits < m_maxChunkBits)
             {
  -            // Extend array?
  -            int i=m_array.length;
  -            if(m_lastChunk+1==i)
  -              {
  -                char[][] newarray=new char[i+16][];
  -                System.arraycopy(m_array,0,newarray,0,i);
  -                m_array=newarray;
  -              }
  -                  
  -            // Advance one chunk
  -            chunk=m_array[++m_lastChunk];
  -            if(chunk==null)
  -              {
  -                // Hierarchical encapsulation
  -                if(m_lastChunk==1<<m_rebundleBits && m_chunkBits<m_maxChunkBits)
  -                {
  -                  // Should do all the work of both encapsulating
  -                  // existing data and establishing new sizes/offsets
  -                  m_innerFSB=new FastStringBuffer(this);
  -                }
  -
  -                // Add a chunk. 
  -                chunk=m_array[m_lastChunk]=new char[m_chunkSize];
  -              }
  -            available=m_chunkSize;
  -                          
  -            m_firstFree=0;
  +
  +            // Should do all the work of both encapsulating
  +            // existing data and establishing new sizes/offsets
  +            m_innerFSB = new FastStringBuffer(this);
             }
  +
  +          // Add a chunk. 
  +          chunk = m_array[m_lastChunk] = new char[m_chunkSize];
  +        }
  +
  +        available = m_chunkSize;
  +        m_firstFree = 0;
         }
  -          
  +    }
  +
       // Adjust the insert point in the last chunk, when we've reached it.
  -    m_firstFree+=available;
  +    m_firstFree += available;
     }
   
     /**
  @@ -474,60 +535,77 @@
      */
     public final void append(StringBuffer value)
     {
  -    int strlen=value.length();
  +
  +    int strlen = value.length();
  +
       if (0 == strlen)
         return;
  -    int copyfrom=0;
  -    char[] chunk=m_array[m_lastChunk];
  -    int available=m_chunkSize-m_firstFree;
  -          
  +
  +    int copyfrom = 0;
  +    char[] chunk = m_array[m_lastChunk];
  +    int available = m_chunkSize - m_firstFree;
  +
       // Repeat while data remains to be copied
  -    while(strlen>0)
  +    while (strlen > 0)
  +    {
  +
  +      // Copy what fits
  +      if (available > strlen)
  +        available = strlen;
  +
  +      value.getChars(copyfrom, copyfrom + available, m_array[m_lastChunk],
  +                     m_firstFree);
  +
  +      strlen -= available;
  +      copyfrom += available;
  +
  +      // If there's more left, allocate another chunk and continue
  +      if (strlen > 0)
         {
  -        // Copy what fits
  -        if(available>strlen) available=strlen;
  -        value.getChars(copyfrom, copyfrom+available, m_array[m_lastChunk], m_firstFree);
  -        strlen-=available;
  -        copyfrom+=available;
  -                  
  -        // If there's more left, allocate another chunk and continue
  -        if(strlen>0)
  +
  +        // Extend array?
  +        int i = m_array.length;
  +
  +        if (m_lastChunk + 1 == i)
  +        {
  +          char[][] newarray = new char[i + 16][];
  +
  +          System.arraycopy(m_array, 0, newarray, 0, i);
  +
  +          m_array = newarray;
  +        }
  +
  +        // Advance one chunk
  +        chunk = m_array[++m_lastChunk];
  +
  +        if (chunk == null)
  +        {
  +
  +          // Hierarchical encapsulation
  +          if (m_lastChunk == 1 << m_rebundleBits
  +                  && m_chunkBits < m_maxChunkBits)
             {
  -            // Extend array?
  -            int i=m_array.length;
  -            if(m_lastChunk+1==i)
  -              {
  -                char[][] newarray=new char[i+16][];
  -                System.arraycopy(m_array,0,newarray,0,i);
  -                m_array=newarray;
  -              }
  -                  
  -            // Advance one chunk
  -            chunk=m_array[++m_lastChunk];
  -            if(chunk==null)
  -              {
  -                // Hierarchical encapsulation
  -                if(m_lastChunk==1<<m_rebundleBits &&  m_chunkBits<m_maxChunkBits)
  -                {
  -                  // Should do all the work of both encapsulating
  -                  // existing data and establishing new sizes/offsets
  -                  m_innerFSB=new FastStringBuffer(this);
  -                }
  -                // Add a chunk.
  -                chunk=m_array[m_lastChunk]=new char[m_chunkSize];
  -              }
  -            available=m_chunkSize;
  -                          
  -            m_firstFree=0;
  +
  +            // Should do all the work of both encapsulating
  +            // existing data and establishing new sizes/offsets
  +            m_innerFSB = new FastStringBuffer(this);
             }
  +
  +          // Add a chunk.
  +          chunk = m_array[m_lastChunk] = new char[m_chunkSize];
  +        }
  +
  +        available = m_chunkSize;
  +        m_firstFree = 0;
         }
  -          
  +    }
  +
       // Adjust the insert point in the last chunk, when we've reached it.
  -    m_firstFree+=available;
  +    m_firstFree += available;
     }
   
     /**
  -   * Append part of the contents of a Character Array onto the 
  +   * Append part of the contents of a Character Array onto the
      * FastStringBuffer,  growing the storage if necessary.
      * <p>
      * NOTE THAT after calling append(), previously obtained
  @@ -540,60 +618,77 @@
      */
     public final void append(char[] chars, int start, int length)
     {
  -    int strlen=length;
  +
  +    int strlen = length;
  +
       if (0 == strlen)
         return;
  -    int copyfrom=start;
  -    char[] chunk=m_array[m_lastChunk];
  -    int available=m_chunkSize-m_firstFree;
  -          
  +
  +    int copyfrom = start;
  +    char[] chunk = m_array[m_lastChunk];
  +    int available = m_chunkSize - m_firstFree;
  +
       // Repeat while data remains to be copied
  -    while(strlen>0)
  +    while (strlen > 0)
  +    {
  +
  +      // Copy what fits
  +      if (available > strlen)
  +        available = strlen;
  +
  +      System.arraycopy(chars, copyfrom, m_array[m_lastChunk], m_firstFree,
  +                       available);
  +
  +      strlen -= available;
  +      copyfrom += available;
  +
  +      // If there's more left, allocate another chunk and continue
  +      if (strlen > 0)
         {
  -        // Copy what fits
  -        if(available>strlen) available=strlen;
  -        System.arraycopy(chars,copyfrom, m_array[m_lastChunk], m_firstFree, available);
  -        strlen-=available;
  -        copyfrom+=available;
  -                  
  -        // If there's more left, allocate another chunk and continue
  -        if(strlen>0)
  +
  +        // Extend array?
  +        int i = m_array.length;
  +
  +        if (m_lastChunk + 1 == i)
  +        {
  +          char[][] newarray = new char[i + 16][];
  +
  +          System.arraycopy(m_array, 0, newarray, 0, i);
  +
  +          m_array = newarray;
  +        }
  +
  +        // Advance one chunk
  +        chunk = m_array[++m_lastChunk];
  +
  +        if (chunk == null)
  +        {
  +
  +          // Hierarchical encapsulation
  +          if (m_lastChunk == 1 << m_rebundleBits
  +                  && m_chunkBits < m_maxChunkBits)
             {
  -            // Extend array?
  -            int i=m_array.length;
  -            if(m_lastChunk+1==i)
  -              {
  -                char[][] newarray=new char[i+16][];
  -                System.arraycopy(m_array,0,newarray,0,i);
  -                m_array=newarray;
  -              }
  -                  
  -            // Advance one chunk
  -            chunk=m_array[++m_lastChunk];
  -            if(chunk==null)
  -              {
  -                // Hierarchical encapsulation
  -                if(m_lastChunk==1<<m_rebundleBits &&  m_chunkBits<m_maxChunkBits)
  -                {
  -                  // Should do all the work of both encapsulating
  -                  // existing data and establishing new sizes/offsets
  -                  m_innerFSB=new FastStringBuffer(this);
  -                }
  -                // Add a chunk.
  -                chunk=m_array[m_lastChunk]=new char[m_chunkSize];
  -              }
  -            available=m_chunkSize;
   
  -            m_firstFree=0;
  +            // Should do all the work of both encapsulating
  +            // existing data and establishing new sizes/offsets
  +            m_innerFSB = new FastStringBuffer(this);
             }
  +
  +          // Add a chunk.
  +          chunk = m_array[m_lastChunk] = new char[m_chunkSize];
  +        }
  +
  +        available = m_chunkSize;
  +        m_firstFree = 0;
         }
  -          
  +    }
  +
       // Adjust the insert point in the last chunk, when we've reached it.
  -    m_firstFree+=available;
  +    m_firstFree += available;
     }
   
     /**
  -   * Append the contents of another FastStringBuffer onto 
  +   * Append the contents of another FastStringBuffer onto
      * this FastStringBuffer, growing the storage if necessary.
      * <p>
      * NOTE THAT after calling append(), previously obtained
  @@ -604,119 +699,145 @@
      */
     public final void append(FastStringBuffer value)
     {
  +
       // Complicating factor here is that the two buffers may use
       // different chunk sizes, and even if they're the same we're
       // probably on a different alignment due to previously appended
       // data. We have to work through the source in bite-sized chunks.
  -    int strlen=value.length();
  +    int strlen = value.length();
  +
       if (0 == strlen)
         return;
  -    int copyfrom=0;
  -    char[] chunk=m_array[m_lastChunk];
  -    int available=m_chunkSize-m_firstFree;
  -          
  +
  +    int copyfrom = 0;
  +    char[] chunk = m_array[m_lastChunk];
  +    int available = m_chunkSize - m_firstFree;
  +
       // Repeat while data remains to be copied
  -    while(strlen>0)
  +    while (strlen > 0)
  +    {
  +
  +      // Copy what fits
  +      if (available > strlen)
  +        available = strlen;
  +
  +      int sourcechunk = (copyfrom + value.m_chunkSize - 1)
  +                        >>> value.m_chunkBits;
  +      int sourcecolumn = copyfrom & value.m_chunkMask;
  +      int runlength = value.m_chunkSize - sourcecolumn;
  +
  +      if (runlength > available)
  +        runlength = available;
  +
  +      System.arraycopy(value.m_array[sourcechunk], sourcecolumn,
  +                       m_array[m_lastChunk], m_firstFree, runlength);
  +
  +      if (runlength != available)
  +        System.arraycopy(value.m_array[sourcechunk + 1], 0,
  +                         m_array[m_lastChunk], m_firstFree + runlength,
  +                         available - runlength);
  +
  +      strlen -= available;
  +      copyfrom += available;
  +
  +      // If there's more left, allocate another chunk and continue
  +      if (strlen > 0)
         {
  -        // Copy what fits
  -        if(available>strlen) available=strlen;
  -                  
  -        int sourcechunk=(copyfrom+value.m_chunkSize-1)>>>value.m_chunkBits;
  -        int sourcecolumn=copyfrom & value.m_chunkMask;
  -        int runlength=value.m_chunkSize-sourcecolumn;
  -        if(runlength>available) runlength=available;
  -        System.arraycopy(value.m_array[sourcechunk],sourcecolumn,
  -                         m_array[m_lastChunk], m_firstFree, runlength);
  -        if(runlength!=available)
  -          System.arraycopy(value.m_array[sourcechunk+1],0,
  -                           m_array[m_lastChunk], m_firstFree+runlength, available-runlength);
  -                  
  -        strlen-=available;
  -        copyfrom+=available;
  -                  
  -        // If there's more left, allocate another chunk and continue
  -        if(strlen>0)
  +
  +        // Extend array?
  +        int i = m_array.length;
  +
  +        if (m_lastChunk + 1 == i)
  +        {
  +          char[][] newarray = new char[i + 16][];
  +
  +          System.arraycopy(m_array, 0, newarray, 0, i);
  +
  +          m_array = newarray;
  +        }
  +
  +        // Advance one chunk
  +        chunk = m_array[++m_lastChunk];
  +
  +        if (chunk == null)
  +        {
  +
  +          // Hierarchical encapsulation
  +          if (m_lastChunk == 1 << m_rebundleBits
  +                  && m_chunkBits < m_maxChunkBits)
             {
  -            // Extend array?
  -            int i=m_array.length;
  -            if(m_lastChunk+1==i)
  -              {
  -                char[][] newarray=new char[i+16][];
  -                System.arraycopy(m_array,0,newarray,0,i);
  -                m_array=newarray;
  -              }
  -                  
  -            // Advance one chunk
  -            chunk=m_array[++m_lastChunk];
  -            if(chunk==null)
  -              {
  -                // Hierarchical encapsulation
  -                if(m_lastChunk==1<<m_rebundleBits &&  m_chunkBits<m_maxChunkBits)
  -                {
  -                  // Should do all the work of both encapsulating
  -                  // existing data and establishing new sizes/offsets
  -                  m_innerFSB=new FastStringBuffer(this);
  -                }
  -                // Add a chunk. 
  -                chunk=m_array[m_lastChunk]=new char[m_chunkSize];
  -              }
  -            available=m_chunkSize;
  -                          
  -            m_firstFree=0;
  +
  +            // Should do all the work of both encapsulating
  +            // existing data and establishing new sizes/offsets
  +            m_innerFSB = new FastStringBuffer(this);
             }
  +
  +          // Add a chunk. 
  +          chunk = m_array[m_lastChunk] = new char[m_chunkSize];
  +        }
  +
  +        available = m_chunkSize;
  +        m_firstFree = 0;
         }
  -          
  +    }
  +
       // Adjust the insert point in the last chunk, when we've reached it.
  -    m_firstFree+=available;
  +    m_firstFree += available;
     }
   
  -  /** @return true if the specified range of characters are all whitespace,
  +  /**
  +   * @return true if the specified range of characters are all whitespace,
      * as defined by XMLCharacterRecognizer.
      * <p>
      * CURRENTLY DOES NOT CHECK FOR OUT-OF-RANGE.
  -   * 
  +   *
      * @param start Offset of first character in the range.
      * @param length Number of characters to send.
      */
     public boolean isWhitespace(int start, int length)
     {
  -    int sourcechunk=start >>> m_chunkBits;
  -    int sourcecolumn=start & m_chunkMask;
  -    int available=m_chunkSize-sourcecolumn;
  -	boolean chunkOK;
  -          
  -    while(length>0)
  -      {
  -        int runlength=(length<=available) ? length : available;
  -		
  -		if(sourcechunk==0 && m_innerFSB!=null)
  -			chunkOK=m_innerFSB.isWhitespace(sourcecolumn,runlength);
  -		else
  -			chunkOK=org.apache.xml.utils.XMLCharacterRecognizer
  -			    .isWhiteSpace(m_array[sourcechunk],sourcecolumn,runlength);
  -		if(!chunkOK)
  -          return false;
  -        
  -        length-=runlength;
  -        ++sourcechunk;
  -        sourcecolumn=0;
  -        available=m_chunkSize;
  -      }
  -          
  +
  +    int sourcechunk = start >>> m_chunkBits;
  +    int sourcecolumn = start & m_chunkMask;
  +    int available = m_chunkSize - sourcecolumn;
  +    boolean chunkOK;
  +
  +    while (length > 0)
  +    {
  +      int runlength = (length <= available) ? length : available;
  +
  +      if (sourcechunk == 0 && m_innerFSB != null)
  +        chunkOK = m_innerFSB.isWhitespace(sourcecolumn, runlength);
  +      else
  +        chunkOK = org.apache.xml.utils.XMLCharacterRecognizer.isWhiteSpace(
  +          m_array[sourcechunk], sourcecolumn, runlength);
  +
  +      if (!chunkOK)
  +        return false;
  +
  +      length -= runlength;
  +
  +      ++sourcechunk;
  +
  +      sourcecolumn = 0;
  +      available = m_chunkSize;
  +    }
  +
       return true;
     }
  -  
  +
     /**
      * @param start Offset of first character in the range.
      * @param length Number of characters to send.
  -   * @return a new String object initialized from the specified range of 
  +   * @return a new String object initialized from the specified range of
      * characters.
      */
     public String getString(int start, int length)
     {
  -    return getString(new StringBuffer(length),start>>>m_chunkBits,start&m_chunkMask,length).toString();
  +    return getString(new StringBuffer(length), start >>> m_chunkBits,
  +                     start & m_chunkMask, length).toString();
     }
  -  
  +
     /**
      * @param sb StringBuffer to be appended to
      * @param start Offset of first character in the range.
  @@ -725,56 +846,83 @@
      */
     StringBuffer getString(StringBuffer sb, int start, int length)
     {
  -    return getString(sb,start>>>m_chunkBits,start&m_chunkMask,length);
  +    return getString(sb, start >>> m_chunkBits, start & m_chunkMask, length);
     }
  -  
  -  /** Internal support for toString() and getString().
  +
  +  /**
  +   * Internal support for toString() and getString().
      * PLEASE NOTE SIGNATURE CHANGE from earlier versions; it now appends into
  -   * and returns a StringBuffer supplied by the caller. This simplifies 
  +   * and returns a StringBuffer supplied by the caller. This simplifies
      * m_innerFSB support.
      * <p>
      * Note that this operation has been somewhat deoptimized by the shift to a
  -   * chunked array, as there is no factory method to produce a String object 
  +   * chunked array, as there is no factory method to produce a String object
      * directly from an array of arrays and hence a double copy is needed.
  -   * By presetting length we hope to minimize the heap overhead of building 
  +   * By presetting length we hope to minimize the heap overhead of building
      * the intermediate StringBuffer.
      * <p>
      * (It really is a pity that Java didn't design String as a final subclass
      * of MutableString, rather than having StringBuffer be a separate hierarchy.
      * We'd avoid a <strong>lot</strong> of double-buffering.)
  +   *
  +   *
  +   * @param sb
  +   * @param startChunk
  +   * @param startColumn
  +   * @param length
      * 
      * @return the contents of the FastStringBuffer as a standard Java string.
      */
  -  StringBuffer getString(StringBuffer sb,int startChunk,int startColumn,int length)
  +  StringBuffer getString(StringBuffer sb, int startChunk, int startColumn,
  +                         int length)
     {
  -    int stop=(startChunk<<m_chunkBits)+startColumn+length;
  -    int stopChunk=stop>>>m_chunkBits;
  -    int stopColumn=stop&m_chunkMask;
  -      
  -	// Factored out
  +
  +    int stop = (startChunk << m_chunkBits) + startColumn + length;
  +    int stopChunk = stop >>> m_chunkBits;
  +    int stopColumn = stop & m_chunkMask;
  +
  +    // Factored out
       //StringBuffer sb=new StringBuffer(length);
  -          
  -    for(int i=startChunk;i<stopChunk;++i)
  -      {
  -		if(i==0 && m_innerFSB!=null)
  -			m_innerFSB.getString(sb,startColumn,m_chunkSize-startColumn);
  -		else
  -			sb.append(m_array[i],startColumn,m_chunkSize-startColumn);
  -        startColumn=0; // after first chunk
  -      }
  +    for (int i = startChunk; i < stopChunk; ++i)
  +    {
  +      if (i == 0 && m_innerFSB != null)
  +        m_innerFSB.getString(sb, startColumn, m_chunkSize - startColumn);
  +      else
  +        sb.append(m_array[i], startColumn, m_chunkSize - startColumn);
  +
  +      startColumn = 0;  // after first chunk
  +    }
  +
  +    if (stopChunk == 0 && m_innerFSB != null)
  +      m_innerFSB.getString(sb, startColumn, stopColumn - startColumn);
  +    else if (stopColumn > startColumn)
  +      sb.append(m_array[stopChunk], startColumn, stopColumn - startColumn);
   
  -	if(stopChunk==0 && m_innerFSB!=null)
  -		m_innerFSB.getString(sb,startColumn,stopColumn-startColumn);
  -	else if(stopColumn>startColumn)
  -		sb.append(m_array[stopChunk],startColumn,stopColumn-startColumn);
  +    return sb;
  +  }
   
  -	return sb;
  +  /**
  +   * Get a single character from the string buffer.
  +   *
  +   *
  +   * @param pos character position requested.
  +   * @return A character from the requested position.
  +   */
  +  public char charAt(int pos)
  +  {
  +    int startChunk = pos >>> m_chunkBits;
  +
  +    if (startChunk == 0 && m_innerFSB != null)
  +      return m_innerFSB.charAt(pos & m_chunkMask);
  +    else
  +      return m_array[startChunk][pos & m_chunkMask];
     }
  -  
  -  /** Sends the specified range of characters as one or more SAX characters()
  +
  +  /**
  +   * Sends the specified range of characters as one or more SAX characters()
      * events.
  -   * Note that the buffer reference passed to the ContentHandler may be 
  -   * invalidated if the FastStringBuffer is edited; it's the user's 
  +   * Note that the buffer reference passed to the ContentHandler may be
  +   * invalidated if the FastStringBuffer is edited; it's the user's
      * responsibility to manage access to the FastStringBuffer to prevent this
      * problem from arising.
      * <p>
  @@ -782,68 +930,127 @@
      * single call. As is always true in SAX, one logical string may be split
      * across multiple blocks of memory and hence delivered as several
      * successive events.
  -   * 
  +   *
      * @param ch SAX ContentHandler object to receive the event.
      * @param start Offset of first character in the range.
      * @param length Number of characters to send.
      * @exception org.xml.sax.SAXException may be thrown by handler's
      * characters() method.
      */
  -  public void sendSAXcharacters(org.xml.sax.ContentHandler ch,int start, int length) 
  -       throws org.xml.sax.SAXException
  -  {
  -    int stop=start+length;
  -    int startChunk=start>>>m_chunkBits;
  -    int startColumn=start&m_chunkMask;
  -    int stopChunk=stop>>>m_chunkBits;
  -    int stopColumn=stop&m_chunkMask;
  -          
  -    for(int i=startChunk;i<stopChunk;++i)
  -      {
  -		if(i==0 && m_innerFSB!=null)
  -			m_innerFSB.sendSAXcharacters(ch,startColumn,m_chunkSize-startColumn);
  -		else
  -			ch.characters(m_array[i],startColumn,m_chunkSize-startColumn);
  -        startColumn=0; // after first chunk
  -      }
  +  public void sendSAXcharacters(
  +          org.xml.sax.ContentHandler ch, int start, int length)
  +            throws org.xml.sax.SAXException
  +  {
  +
  +    int stop = start + length;
  +    int startChunk = start >>> m_chunkBits;
  +    int startColumn = start & m_chunkMask;
  +    int stopChunk = stop >>> m_chunkBits;
  +    int stopColumn = stop & m_chunkMask;
  +
  +    for (int i = startChunk; i < stopChunk; ++i)
  +    {
  +      if (i == 0 && m_innerFSB != null)
  +        m_innerFSB.sendSAXcharacters(ch, startColumn,
  +                                     m_chunkSize - startColumn);
  +      else
  +        ch.characters(m_array[i], startColumn, m_chunkSize - startColumn);
   
  +      startColumn = 0;  // after first chunk
  +    }
  +
       // Last, or only, chunk
  -	if(stopChunk==0 && m_innerFSB!=null)
  -		m_innerFSB.sendSAXcharacters(ch,startColumn,stopColumn-startColumn);
  -	else if(stopColumn>startColumn)
  -	    ch.characters(m_array[stopChunk],startColumn,stopColumn-startColumn);
  +    if (stopChunk == 0 && m_innerFSB != null)
  +      m_innerFSB.sendSAXcharacters(ch, startColumn, stopColumn - startColumn);
  +    else if (stopColumn > startColumn)
  +      ch.characters(m_array[stopChunk], startColumn,
  +                    stopColumn - startColumn);
  +  }
  +  
  +  /**
  +   * Sends the specified range of characters as sax Comment.
  +   * <p>
  +   * Note that, unlike sendSAXcharacters, this has to be done as a single 
  +   * call to LexicalHandler#comment.
  +   *
  +   * @param ch SAX LexicalHandler object to receive the event.
  +   * @param start Offset of first character in the range.
  +   * @param length Number of characters to send.
  +   * @exception org.xml.sax.SAXException may be thrown by handler's
  +   * characters() method.
  +   */
  +  public void sendSAXComment(
  +          org.xml.sax.ext.LexicalHandler ch, int start, int length)
  +            throws org.xml.sax.SAXException
  +  {
  +
  +    // %OPT% Do it this way for now...
  +    String comment = getString(start, length);
  +    ch.comment(comment.toCharArray(), 0, length);
     }
   
  -  /** Encapsulation c'tor. After this is called, the source FastStringBuffer
  +  /**
  +   * Copies characters from this string into the destination character
  +   * array.
  +   *
  +   * @param      srcBegin   index of the first character in the string
  +   *                        to copy.
  +   * @param      srcEnd     index after the last character in the string
  +   *                        to copy.
  +   * @param      dst        the destination array.
  +   * @param      dstBegin   the start offset in the destination array.
  +   * @exception IndexOutOfBoundsException If any of the following
  +   *            is true:
  +   *            <ul><li><code>srcBegin</code> is negative.
  +   *            <li><code>srcBegin</code> is greater than <code>srcEnd</code>
  +   *            <li><code>srcEnd</code> is greater than the length of this
  +   *                string
  +   *            <li><code>dstBegin</code> is negative
  +   *            <li><code>dstBegin+(srcEnd-srcBegin)</code> is larger than
  +   *                <code>dst.length</code></ul>
  +   * @exception NullPointerException if <code>dst</code> is <code>null</code>
  +   */
  +  private void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin)
  +  {
  +    // %TBD% Joe needs to write this function.  Make public when implemented.
  +  }
  +
  +  /**
  +   * Encapsulation c'tor. After this is called, the source FastStringBuffer
      * will be reset to use the new object as its m_innerFSB, and will have
      * had its chunk size reset appropriately. IT SHOULD NEVER BE CALLED
      * EXCEPT WHEN source.length()==1<<(source.m_chunkBits+source.m_rebundleBits)
  +   *
  +   * NEEDSDOC @param source
      */
     private FastStringBuffer(FastStringBuffer source)
     {
  -        // Copy existing information into new encapsulation
  -        m_chunkBits   =source.m_chunkBits;
  -        m_maxChunkBits=source.m_maxChunkBits;
  -        m_rebundleBits=source.m_rebundleBits;
  -        m_chunkSize   =source.m_chunkSize;
  -        m_chunkMask   =source.m_chunkMask;
  -        m_array       =source.m_array; 
  -		m_innerFSB    =source.m_innerFSB;
  -		// These have to be adjusted because we're calling just at the time
  -		// when we would be about to allocate another chunk
  -        m_lastChunk   =source.m_lastChunk-1; 
  -        m_firstFree   =source.m_chunkSize;
  -        
  -        // Establish capsule as the Inner FSB, reset chunk sizes/addressing
  -		source.m_array = new char[16][];
  -        source.m_innerFSB=this; 
  -		// Since we encapsulated just as we were about to append another
  -		// chunk, return ready to create the chunk after the innerFSB
  -		// -- 1, not 0.
  -        source.m_lastChunk=1;
  -        source.m_firstFree=0;
  -        source.m_chunkBits+=m_rebundleBits;
  -        source.m_chunkSize=1<<(source.m_chunkBits); 
  -        source.m_chunkMask=source.m_chunkSize-1;
  +
  +    // Copy existing information into new encapsulation
  +    m_chunkBits = source.m_chunkBits;
  +    m_maxChunkBits = source.m_maxChunkBits;
  +    m_rebundleBits = source.m_rebundleBits;
  +    m_chunkSize = source.m_chunkSize;
  +    m_chunkMask = source.m_chunkMask;
  +    m_array = source.m_array;
  +    m_innerFSB = source.m_innerFSB;
  +
  +    // These have to be adjusted because we're calling just at the time
  +    // when we would be about to allocate another chunk
  +    m_lastChunk = source.m_lastChunk - 1;
  +    m_firstFree = source.m_chunkSize;
  +
  +    // Establish capsule as the Inner FSB, reset chunk sizes/addressing
  +    source.m_array = new char[16][];
  +    source.m_innerFSB = this;
  +
  +    // Since we encapsulated just as we were about to append another
  +    // chunk, return ready to create the chunk after the innerFSB
  +    // -- 1, not 0.
  +    source.m_lastChunk = 1;
  +    source.m_firstFree = 0;
  +    source.m_chunkBits += m_rebundleBits;
  +    source.m_chunkSize = 1 << (source.m_chunkBits);
  +    source.m_chunkMask = source.m_chunkSize - 1;
     }
   }
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.1.2.1   +657 -0    xml-xalan/java/src/org/apache/xml/utils/Attic/XMLString.java
  
  
  
  
  1.1.2.1   +107 -0    xml-xalan/java/src/org/apache/xml/utils/Attic/XMLStringFactory.java
  
  
  
  
  1.1.2.1   +743 -0    xml-xalan/java/src/org/apache/xml/utils/Attic/XMLStringWrapperForString.java
  
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.24.2.6  +8 -1      xml-xalan/java/src/org/apache/xpath/SourceTreeManager.java
  
  Index: SourceTreeManager.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/SourceTreeManager.java,v
  retrieving revision 1.24.2.5
  retrieving revision 1.24.2.6
  diff -u -r1.24.2.5 -r1.24.2.6
  --- SourceTreeManager.java	2001/05/16 05:33:43	1.24.2.5
  +++ SourceTreeManager.java	2001/05/18 07:17:00	1.24.2.6
  @@ -64,6 +64,8 @@
   import java.util.StringTokenizer;
   import java.util.Vector;
   
  +import org.apache.xpath.objects.XString;
  +
   //import org.w3c.dom.Node;
   //import org.w3c.dom.Document;
   
  @@ -339,9 +341,14 @@
         Object xowner = xctxt.getOwnerObject();
         DTM dtm;
         if(null != xowner && xowner instanceof org.apache.xml.dtm.DTMWSFilter)
  -        dtm = xctxt.getDTM(source, false, (org.apache.xml.dtm.DTMWSFilter)xowner, false);
  +      {
  +        dtm = xctxt.getDTM(source, false, 
  +                          (org.apache.xml.dtm.DTMWSFilter)xowner, false);
  +      }
         else
  +      {
           dtm = xctxt.getDTM(source, false, null, false);
  +      }
         return dtm.getDocument();
       }
       catch (Exception e)
  
  
  
  1.20.2.7  +14 -15    xml-xalan/java/src/org/apache/xpath/XPathContext.java
  
  Index: XPathContext.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/XPathContext.java,v
  retrieving revision 1.20.2.6
  retrieving revision 1.20.2.7
  diff -u -r1.20.2.6 -r1.20.2.7
  --- XPathContext.java	2001/05/17 05:38:47	1.20.2.6
  +++ XPathContext.java	2001/05/18 07:17:01	1.20.2.7
  @@ -76,6 +76,7 @@
   import org.apache.xpath.axes.SubContextList;
   import org.apache.xpath.objects.XObject;
   import org.apache.xpath.objects.XNodeSet;
  +import org.apache.xpath.objects.XString;
   
   // DOM Imports
   //import org.w3c.dom.traversal.NodeIterator;
  @@ -92,7 +93,6 @@
   // TRaX imports
   import javax.xml.transform.URIResolver;
   import javax.xml.transform.TransformerException;
  -import org.apache.xml.utils.SAXSourceLocator;
   import javax.xml.transform.sax.SAXSource;
   import javax.xml.transform.dom.DOMSource;
   
  @@ -109,6 +109,11 @@
   import org.apache.xml.dtm.DTM;
   import org.apache.xml.dtm.DTMWSFilter;
   
  +// Utility imports.
  +import org.apache.xml.utils.SAXSourceLocator;
  +import org.apache.xml.utils.XMLString;
  +import org.apache.xml.utils.XMLStringFactory;
  +
   import org.apache.xpath.axes.DescendantIterator;
   
   /**
  @@ -124,7 +129,8 @@
      * the DTMManager, it really is a proxy for this object, which 
      * is the real DTMManager.
      */
  -  private DTMManager m_dtmManager = DTMManager.newInstance();
  +  private DTMManager m_dtmManager = DTMManager.newInstance(
  +                   org.apache.xpath.objects.XMLStringFactoryImpl.getFactory());
     
     /**
      * Return the DTMManager object.  Though XPathContext context extends 
  @@ -161,7 +167,8 @@
                       DTMWSFilter wsfilter,
                       boolean incremental)
     {
  -    return m_dtmManager.getDTM(source, unique, wsfilter, incremental);
  +    return m_dtmManager.getDTM(source, unique, wsfilter, 
  +                               incremental);
     }
                                
     /**
  @@ -926,16 +933,8 @@
         // %REVIEW% You can't get much uglier than this...
         int nodeHandle = getDTMHandleFromNode(n);
         DTM dtm = getDTM(nodeHandle);
  -      String strVal = dtm.getStringValue(nodeHandle);
  -      XObject xobj = new org.apache.xpath.objects.XString(strVal);
  -      try
  -      {
  -        return xobj.num();
  -      }
  -      catch(TransformerException te)
  -      {
  -        throw new org.apache.xml.utils.WrappedRuntimeException(te);
  -      }
  +      XString xobj = (XString)dtm.getStringValue(nodeHandle);
  +      return xobj.num();
       }
     
       /**
  @@ -948,8 +947,8 @@
         // %REVIEW% You can't get much uglier than this...
         int nodeHandle = getDTMHandleFromNode(n);
         DTM dtm = getDTM(nodeHandle);
  -      String strVal = dtm.getStringValue(nodeHandle);
  -      return strVal;
  +      XMLString strVal = dtm.getStringValue(nodeHandle);
  +      return strVal.toString();
       }
   
       
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.18.2.4  +4 -8      xml-xalan/java/src/org/apache/xpath/axes/AxesWalker.java
  
  Index: AxesWalker.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/axes/AxesWalker.java,v
  retrieving revision 1.18.2.3
  retrieving revision 1.18.2.4
  diff -u -r1.18.2.3 -r1.18.2.4
  --- AxesWalker.java	2001/05/17 05:38:48	1.18.2.3
  +++ AxesWalker.java	2001/05/18 07:17:04	1.18.2.4
  @@ -73,16 +73,12 @@
   import org.apache.xpath.XPathContext;
   import org.apache.xpath.XPath;
   
  -// DOM2 imports
  -//import org.w3c.dom.Node;
  -//import org.w3c.dom.NamedNodeMap;
  -//import org.w3c.dom.traversal.TreeWalker;
  -//import org.w3c.dom.traversal.NodeFilter;
  -//import org.w3c.dom.DOMException;
   import org.apache.xml.dtm.DTM;
   import org.apache.xml.dtm.DTMIterator;
   import org.apache.xml.dtm.DTMFilter;
   
  +import org.apache.xml.utils.XMLString;
  +
   /**
    * Serves as common interface for axes Walkers, and stores common
    * state variables.
  @@ -631,7 +627,7 @@
   
       if (DTM.TEXT_NODE == getDTM(node).getNodeType(node))
       {
  -      String value = getDTM(node).getStringValue(node);
  +      XMLString value = getDTM(node).getStringValue(node);
   
         if (null != value)
         {
  @@ -653,7 +649,7 @@
         System.out.print("attr -->");
         System.out.print(nodeToString(attr));
   
  -      String value = dtm.getStringValue(attr);
  +      XMLString value = dtm.getStringValue(attr);
   
         if (null != value)
         {
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.6.2.3   +1 -1      xml-xalan/java/src/org/apache/xpath/functions/FuncId.java
  
  Index: FuncId.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/functions/FuncId.java,v
  retrieving revision 1.6.2.2
  retrieving revision 1.6.2.3
  diff -u -r1.6.2.2 -r1.6.2.3
  --- FuncId.java	2001/05/06 02:09:54	1.6.2.2
  +++ FuncId.java	2001/05/18 07:17:06	1.6.2.3
  @@ -171,7 +171,7 @@
         while (DTM.NULL != pos)
         {
           DTM ndtm = ni.getDTM(pos);
  -        String refval = ndtm.getStringValue(pos);
  +        String refval = ndtm.getStringValue(pos).toString();
   
           pos = ni.nextNode();
           usedrefs = getNodesByID(xctxt, docContext, refval, usedrefs, nodeSet,
  
  
  
  1.3.2.3   +2 -1      xml-xalan/java/src/org/apache/xpath/functions/FuncLang.java
  
  Index: FuncLang.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/functions/FuncLang.java,v
  retrieving revision 1.3.2.2
  retrieving revision 1.3.2.3
  diff -u -r1.3.2.2 -r1.3.2.3
  --- FuncLang.java	2001/04/17 15:50:26	1.3.2.2
  +++ FuncLang.java	2001/05/18 07:17:07	1.3.2.3
  @@ -99,7 +99,8 @@
   
           if (DTM.NULL != langAttr)
           {
  -          String langVal = dtm.getStringValue(langAttr);
  +          String langVal = dtm.getNodeValue(langAttr);
  +          // %OPT%
             if (langVal.toLowerCase().startsWith(lang.toLowerCase()))
             {
               int valLen = lang.length();
  
  
  
  1.6.2.2   +6 -112    xml-xalan/java/src/org/apache/xpath/functions/FuncNormalizeSpace.java
  
  Index: FuncNormalizeSpace.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/functions/FuncNormalizeSpace.java,v
  retrieving revision 1.6.2.1
  retrieving revision 1.6.2.2
  diff -u -r1.6.2.1 -r1.6.2.2
  --- FuncNormalizeSpace.java	2001/04/10 18:45:30	1.6.2.1
  +++ FuncNormalizeSpace.java	2001/05/18 07:17:07	1.6.2.2
  @@ -67,7 +67,11 @@
   import org.apache.xpath.objects.XObject;
   import org.apache.xpath.objects.XString;
   import org.apache.xpath.objects.XNodeSet;
  +import org.apache.xpath.objects.XMLStringFactoryImpl;
   import org.apache.xml.utils.XMLCharacterRecognizer;
  +import org.apache.xml.utils.XMLString;
  +import org.apache.xml.utils.XMLStringFactory;
  +import org.apache.xml.utils.FastStringBuffer;
   
   /**
    * <meta name="usage" content="advanced"/>
  @@ -87,119 +91,9 @@
     public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
     {
   
  -    String s1 = getArg0AsString(xctxt);
  +    XMLString s1 = getArg0AsString(xctxt);
   
  -    return new XString(fixWhiteSpace(s1, true, true, false));
  +    return (XString)s1.fixWhiteSpace(true, true, false);
     }
   
  -  /**
  -   * Returns whether the specified <var>ch</var> conforms to the XML 1.0 definition
  -   * of whitespace.  Refer to <A href="http://www.w3.org/TR/1998/REC-xml-19980210#NT-S">
  -   * the definition of <CODE>S</CODE></A> for details.
  -   * @param   ch      Character to check as XML whitespace.
  -   * @return          =true if <var>ch</var> is XML whitespace; otherwise =false.
  -   */
  -  private static boolean isSpace(char ch)
  -  {
  -    return XMLCharacterRecognizer.isWhiteSpace(ch);  // Take the easy way out for now.
  -  }
  -
  -  /**
  -   * (Code stolen and modified from XML4J)
  -   * Conditionally trim all leading and trailing whitespace in the specified String.
  -   * All strings of white space are
  -   * replaced by a single space character (#x20), except spaces after punctuation which
  -   * receive double spaces if doublePunctuationSpaces is true.
  -   * This function may be useful to a formatter, but to get first class
  -   * results, the formatter should probably do it's own white space handling
  -   * based on the semantics of the formatting object.
  -   * @param   string      String to be trimmed.
  -   * @param   trimHead    Trim leading whitespace?
  -   * @param   trimTail    Trim trailing whitespace?
  -   * @param   doublePunctuationSpaces    Use double spaces for punctuation?
  -   * @return              The trimmed string.
  -   */
  -  protected String fixWhiteSpace(String string, boolean trimHead,
  -                                 boolean trimTail,
  -                                 boolean doublePunctuationSpaces)
  -  {
  -
  -    char[] buf = string.toCharArray();
  -    int len = buf.length;
  -    boolean edit = false;
  -    int s;
  -
  -    for (s = 0; s < len; s++)
  -    {
  -      if (isSpace(buf[s]))
  -      {
  -        break;
  -      }
  -    }
  -
  -    /* replace S to ' '. and ' '+ -> single ' '. */
  -    int d = s;
  -    boolean pres = false;
  -
  -    for (; s < len; s++)
  -    {
  -      char c = buf[s];
  -
  -      if (isSpace(c))
  -      {
  -        if (!pres)
  -        {
  -          if (' ' != c)
  -          {
  -            edit = true;
  -          }
  -
  -          buf[d++] = ' ';
  -
  -          if (doublePunctuationSpaces && (s != 0))
  -          {
  -            char prevChar = buf[s - 1];
  -
  -            if (!((prevChar == '.') || (prevChar == '!')
  -                  || (prevChar == '?')))
  -            {
  -              pres = true;
  -            }
  -          }
  -          else
  -          {
  -            pres = true;
  -          }
  -        }
  -        else
  -        {
  -          edit = true;
  -          pres = true;
  -        }
  -      }
  -      else
  -      {
  -        buf[d++] = c;
  -        pres = false;
  -      }
  -    }
  -
  -    if (trimTail && 1 <= d && ' ' == buf[d - 1])
  -    {
  -      edit = true;
  -
  -      d--;
  -    }
  -
  -    int start = 0;
  -
  -    if (trimHead && 0 < d && ' ' == buf[0])
  -    {
  -      edit = true;
  -
  -      start++;
  -    }
  -
  -    return edit ? new String(buf, start, d - start) : string;
  -  }
   }
  
  
  
  1.3.2.2   +1 -1      xml-xalan/java/src/org/apache/xpath/functions/FuncString.java
  
  Index: FuncString.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/functions/FuncString.java,v
  retrieving revision 1.3.2.1
  retrieving revision 1.3.2.2
  diff -u -r1.3.2.1 -r1.3.2.2
  --- FuncString.java	2001/04/10 18:45:32	1.3.2.1
  +++ FuncString.java	2001/05/18 07:17:08	1.3.2.2
  @@ -85,6 +85,6 @@
      */
     public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
     {
  -    return new XString(getArg0AsString(xctxt));
  +    return (XString)getArg0AsString(xctxt);
     }
   }
  
  
  
  1.3.2.2   +5 -3      xml-xalan/java/src/org/apache/xpath/functions/FuncSubstringAfter.java
  
  Index: FuncSubstringAfter.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/functions/FuncSubstringAfter.java,v
  retrieving revision 1.3.2.1
  retrieving revision 1.3.2.2
  diff -u -r1.3.2.1 -r1.3.2.2
  --- FuncSubstringAfter.java	2001/04/10 18:45:33	1.3.2.1
  +++ FuncSubstringAfter.java	2001/05/18 07:17:08	1.3.2.2
  @@ -65,6 +65,8 @@
   import org.apache.xpath.objects.XObject;
   import org.apache.xpath.objects.XString;
   
  +import org.apache.xml.utils.XMLString;
  +
   /**
    * <meta name="usage" content="advanced"/>
    * Execute the SubstringAfter() function.
  @@ -83,12 +85,12 @@
     public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
     {
   
  -    String s1 = m_arg0.execute(xctxt).str();
  -    String s2 = m_arg1.execute(xctxt).str();
  +    XMLString s1 = m_arg0.execute(xctxt).xstr();
  +    XMLString s2 = m_arg1.execute(xctxt).xstr();
       int index = s1.indexOf(s2);
   
       return (-1 == index)
              ? XString.EMPTYSTRING
  -           : new XString(s1.substring(index + s2.length()));
  +           : (XString)s1.substring(index + s2.length());
     }
   }
  
  
  
  1.4.2.2   +3 -3      xml-xalan/java/src/org/apache/xpath/functions/FuncSum.java
  
  Index: FuncSum.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/functions/FuncSum.java,v
  retrieving revision 1.4.2.1
  retrieving revision 1.4.2.2
  diff -u -r1.4.2.1 -r1.4.2.2
  --- FuncSum.java	2001/04/10 18:45:33	1.4.2.1
  +++ FuncSum.java	2001/05/18 07:17:09	1.4.2.2
  @@ -56,8 +56,6 @@
    */
   package org.apache.xpath.functions;
   
  -//import org.w3c.dom.Node;
  -//import org.w3c.dom.traversal.NodeIterator;
   import org.apache.xml.dtm.DTM;
   import org.apache.xml.dtm.DTMIterator;
   
  @@ -70,6 +68,8 @@
   import org.apache.xpath.objects.XNumber;
   import org.apache.xpath.objects.XString;
   
  +import org.apache.xml.utils.XMLString;
  +
   /**
    * <meta name="usage" content="advanced"/>
    * Execute the Sum() function.
  @@ -95,7 +95,7 @@
       while (DTM.NULL != (pos = nodes.nextNode()))
       {
         DTM dtm = nodes.getDTM(pos);
  -      String s = dtm.getStringValue(pos);
  +      XMLString s = dtm.getStringValue(pos);
   
         if (null != s)
           sum += XString.castToNum(s);
  
  
  
  1.5.2.3   +6 -4      xml-xalan/java/src/org/apache/xpath/functions/FunctionDef1Arg.java
  
  Index: FunctionDef1Arg.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/functions/FunctionDef1Arg.java,v
  retrieving revision 1.5.2.2
  retrieving revision 1.5.2.3
  diff -u -r1.5.2.2 -r1.5.2.3
  --- FunctionDef1Arg.java	2001/05/06 02:09:54	1.5.2.2
  +++ FunctionDef1Arg.java	2001/05/18 07:17:09	1.5.2.3
  @@ -63,6 +63,8 @@
   import org.apache.xpath.objects.XNumber;
   import org.apache.xpath.objects.XString;
   
  +import org.apache.xml.utils.XMLString;
  +
   import org.apache.xml.dtm.DTM;
   
   /**
  @@ -107,14 +109,14 @@
      * @throws javax.xml.transform.TransformerException if an error occurs while
      *                                   executing the argument expression.
      */
  -  protected String getArg0AsString(XPathContext xctxt)
  +  protected XMLString getArg0AsString(XPathContext xctxt)
             throws javax.xml.transform.TransformerException
     {
       if(null == m_arg0)
       {
         int currentNode = xctxt.getCurrentNode();
         if(DTM.NULL == currentNode)
  -        return "";
  +        return XString.EMPTYSTRING;
         else
         {
           DTM dtm = xctxt.getDTM(currentNode);
  @@ -123,7 +125,7 @@
         
       }
       else
  -      return m_arg0.execute(xctxt).str();   
  +      return m_arg0.execute(xctxt).xstr();   
     }
   
     /**
  @@ -151,7 +153,7 @@
         else
         {
           DTM dtm = xctxt.getDTM(currentNode);
  -        String str = dtm.getStringValue(currentNode);
  +        XMLString str = dtm.getStringValue(currentNode);
           return XString.castToNum(str);
         }
         
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.7.2.1   +9 -2      xml-xalan/java/src/org/apache/xpath/objects/XBoolean.java
  
  Index: XBoolean.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/objects/XBoolean.java,v
  retrieving revision 1.7
  retrieving revision 1.7.2.1
  diff -u -r1.7 -r1.7.2.1
  --- XBoolean.java	2001/01/02 03:47:17	1.7
  +++ XBoolean.java	2001/05/18 07:17:16	1.7.2.1
  @@ -166,7 +166,7 @@
      *
      * @throws javax.xml.transform.TransformerException
      */
  -  public boolean equals(XObject obj2) throws javax.xml.transform.TransformerException
  +  public boolean equals(XObject obj2)
     {
   
       // In order to handle the 'all' semantics of 
  @@ -175,7 +175,14 @@
       if (obj2.getType() == XObject.CLASS_NODESET)
         return obj2.equals(this);
   
  -    return m_val == obj2.bool();
  +    try
  +    {
  +      return m_val == obj2.bool();
  +    }
  +    catch(javax.xml.transform.TransformerException te)
  +    {
  +      throw new org.apache.xml.utils.WrappedRuntimeException(te);
  +    }
     }
   
   }
  
  
  
  1.5.2.1   +9 -2      xml-xalan/java/src/org/apache/xpath/objects/XBooleanStatic.java
  
  Index: XBooleanStatic.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/objects/XBooleanStatic.java,v
  retrieving revision 1.5
  retrieving revision 1.5.2.1
  diff -u -r1.5 -r1.5.2.1
  --- XBooleanStatic.java	2001/01/02 03:47:17	1.5
  +++ XBooleanStatic.java	2001/05/18 07:17:16	1.5.2.1
  @@ -95,8 +95,15 @@
      *
      * @throws javax.xml.transform.TransformerException
      */
  -  public boolean equals(XObject obj2) throws javax.xml.transform.TransformerException
  +  public boolean equals(XObject obj2)
     {
  -    return m_val == obj2.bool();
  +    try
  +    {
  +      return m_val == obj2.bool();
  +    }
  +    catch(javax.xml.transform.TransformerException te)
  +    {
  +      throw new org.apache.xml.utils.WrappedRuntimeException(te);
  +    }
     }
   }
  
  
  
  1.10.2.4  +44 -21    xml-xalan/java/src/org/apache/xpath/objects/XNodeSet.java
  
  Index: XNodeSet.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/objects/XNodeSet.java,v
  retrieving revision 1.10.2.3
  retrieving revision 1.10.2.4
  diff -u -r1.10.2.3 -r1.10.2.4
  --- XNodeSet.java	2001/05/07 13:15:56	1.10.2.3
  +++ XNodeSet.java	2001/05/18 07:17:19	1.10.2.4
  @@ -70,6 +70,7 @@
   import org.apache.xpath.NodeSet;
   import org.apache.xpath.axes.ContextNodeList;
   import org.apache.xml.utils.StringVector;
  +import org.apache.xml.utils.XMLString;
   
   /**
    * <meta name="usage" content="general"/>
  @@ -188,7 +189,7 @@
      *
      * @return the string conversion from a single node.
      */
  -  public String getStringFromNode(int n)
  +  public XMLString getStringFromNode(int n)
     {
       // %OPT%
       // I guess we'll have to get a static instance of the DTM manager...
  @@ -198,10 +199,24 @@
       }
       else
       {
  -      return "";
  +      return org.apache.xpath.objects.XString.EMPTYSTRING;
       }
     }
  +  
  +  /**
  +   * Cast result object to an XMLString.
  +   *
  +   * @return The document fragment node data or the empty string. 
  +   */
  +  public XMLString xstr()
  +  {
  +    DTMIterator nl = nodeset();
  +    int node = nl.nextNode();
   
  +    return (node != DTM.NULL) ? getStringFromNode(node) : XString.EMPTYSTRING;
  +  }
  +
  +
     /**
      * Cast result object to a string.
      *
  @@ -214,7 +229,7 @@
       DTMIterator nl = nodeset();
       int node = nl.nextNode();
   
  -    return (node != DTM.NULL) ? getStringFromNode(node) : "";
  +    return (node != DTM.NULL) ? getStringFromNode(node).toString() : "";
     }
   
     // %REVIEW%
  @@ -330,6 +345,7 @@
   
       if (XObject.CLASS_NODESET == type)
       {
  +      // %OPT% This should be XMLString based instead of string based...
   
         // From http://www.w3.org/TR/xpath: 
         // If both objects to be compared are node-sets, then the comparison 
  @@ -345,11 +361,11 @@
         DTMIterator list1 = nodeset();
         DTMIterator list2 = ((XNodeSet) obj2).nodeset();
         int node1;
  -      StringVector node2Strings = null;
  +      java.util.Vector node2Strings = null;
   
         while (DTM.NULL != (node1 = list1.nextNode()))
         {
  -        String s1 = getStringFromNode(node1);
  +        XMLString s1 = getStringFromNode(node1);
   
           if (null == node2Strings)
           {
  @@ -357,7 +373,7 @@
   
             while (DTM.NULL != (node2 = list2.nextNode()))
             {
  -            String s2 = getStringFromNode(node2);
  +            XMLString s2 = getStringFromNode(node2);
   
               if (comparator.compareStrings(s1, s2))
               {
  @@ -367,7 +383,7 @@
               }
   
               if (null == node2Strings)
  -              node2Strings = new StringVector();
  +              node2Strings = new java.util.Vector();
   
               node2Strings.addElement(s2);
             }
  @@ -378,7 +394,7 @@
   
             for (int i = 0; i < n; i++)
             {
  -            if (comparator.compareStrings(s1, node2Strings.elementAt(i)))
  +            if (comparator.compareStrings(s1, (XMLString)node2Strings.elementAt(i)))
               {
                 result = true;
   
  @@ -455,13 +471,13 @@
         }
         else
         {
  -        String s2 = obj2.str();
  +        XMLString s2 = obj2.xstr();
           DTMIterator list1 = nodeset();
           int node;
   
           while (DTM.NULL != (node = list1.nextNode()))
           {
  -          String s1 = getStringFromNode(node);
  +          XMLString s1 = getStringFromNode(node);
   
             if (comparator.compareStrings(s1, s2))
             {
  @@ -481,13 +497,13 @@
         // is a node in the node-set such that the result of performing 
         // the comparison on the string-value of the node and the other 
         // string is true. 
  -      String s2 = obj2.str();
  +      XMLString s2 = obj2.xstr();
         DTMIterator list1 = nodeset();
         int node;
   
         while (DTM.NULL != (node = list1.nextNode()))
         {
  -        String s1 = getStringFromNode(node);
  +        XMLString s1 = getStringFromNode(node);
   
           if (comparator.compareStrings(s1, s2))
           {
  @@ -571,9 +587,16 @@
      *
      * @throws javax.xml.transform.TransformerException
      */
  -  public boolean equals(XObject obj2) throws javax.xml.transform.TransformerException
  +  public boolean equals(XObject obj2)
     {
  -    return compare(obj2, S_EQ);
  +    try
  +    {
  +      return compare(obj2, S_EQ);
  +    }
  +    catch(javax.xml.transform.TransformerException te)
  +    {
  +      throw new org.apache.xml.utils.WrappedRuntimeException(te);
  +    }
     }
   
     /**
  @@ -606,7 +629,7 @@
      *
      * @return Whether the strings are equal or not
      */
  -  abstract boolean compareStrings(String s1, String s2);
  +  abstract boolean compareStrings(XMLString s1, XMLString s2);
   
     /**
      * Compare two numbers
  @@ -635,7 +658,7 @@
      *
      * @return True if s1 is less than s2
      */
  -  boolean compareStrings(String s1, String s2)
  +  boolean compareStrings(XMLString s1, XMLString s2)
     {
       return s1.compareTo(s2) < 0;
     }
  @@ -670,7 +693,7 @@
      *
      * @return true if s1 is less than or equal to s2
      */
  -  boolean compareStrings(String s1, String s2)
  +  boolean compareStrings(XMLString s1, XMLString s2)
     {
       return s1.compareTo(s2) <= 0;
     }
  @@ -705,7 +728,7 @@
      *
      * @return true if s1 is greater than s2
      */
  -  boolean compareStrings(String s1, String s2)
  +  boolean compareStrings(XMLString s1, XMLString s2)
     {
       return s1.compareTo(s2) > 0;
     }
  @@ -740,7 +763,7 @@
      *
      * @return true if s1 is greater than or equal to s2
      */
  -  boolean compareStrings(String s1, String s2)
  +  boolean compareStrings(XMLString s1, XMLString s2)
     {
       return s1.compareTo(s2) >= 0;
     }
  @@ -775,7 +798,7 @@
      *
      * @return true if s1 is equal to s2
      */
  -  boolean compareStrings(String s1, String s2)
  +  boolean compareStrings(XMLString s1, XMLString s2)
     {
       return s1.equals(s2);
     }
  @@ -810,7 +833,7 @@
      *
      * @return true if s1 is not equal to s2
      */
  -  boolean compareStrings(String s1, String s2)
  +  boolean compareStrings(XMLString s1, XMLString s2)
     {
       return !s1.equals(s2);
     }
  
  
  
  1.8.2.3   +9 -2      xml-xalan/java/src/org/apache/xpath/objects/XNumber.java
  
  Index: XNumber.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/objects/XNumber.java,v
  retrieving revision 1.8.2.2
  retrieving revision 1.8.2.3
  diff -u -r1.8.2.2 -r1.8.2.3
  --- XNumber.java	2001/05/10 20:49:16	1.8.2.2
  +++ XNumber.java	2001/05/18 07:17:20	1.8.2.3
  @@ -386,7 +386,7 @@
      *
      * @throws javax.xml.transform.TransformerException
      */
  -  public boolean equals(XObject obj2) throws javax.xml.transform.TransformerException
  +  public boolean equals(XObject obj2)
     {
   
       // In order to handle the 'all' semantics of 
  @@ -395,6 +395,13 @@
       if (obj2.getType() == XObject.CLASS_NODESET)
         return obj2.equals(this);
   
  -    return m_val == obj2.num();
  +    try
  +    {
  +      return m_val == obj2.num();
  +    }
  +    catch(javax.xml.transform.TransformerException te)
  +    {
  +      throw new org.apache.xml.utils.WrappedRuntimeException(te);
  +    }
     }
   }
  
  
  
  1.8.2.4   +12 -1     xml-xalan/java/src/org/apache/xpath/objects/XObject.java
  
  Index: XObject.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/objects/XObject.java,v
  retrieving revision 1.8.2.3
  retrieving revision 1.8.2.4
  diff -u -r1.8.2.3 -r1.8.2.4
  --- XObject.java	2001/05/17 05:38:50	1.8.2.3
  +++ XObject.java	2001/05/18 07:17:20	1.8.2.4
  @@ -72,6 +72,7 @@
   import org.apache.xpath.XPathException;
   import org.apache.xalan.res.XSLMessages;
   import org.apache.xpath.Expression;
  +import org.apache.xml.utils.XMLString;
   
   /**
    * <meta name="usage" content="general"/>
  @@ -249,6 +250,16 @@
   
       return false;
     }
  +  
  +  /**
  +   * Cast result object to a string.
  +   *
  +   * @return The string this wraps or the empty string if null
  +   */
  +  public XMLString xstr()
  +  {
  +    return XMLStringFactoryImpl.getFactory().newstr(str());
  +  }
   
     /**
      * Cast result object to a string.
  @@ -498,7 +509,7 @@
      *
      * @throws javax.xml.transform.TransformerException
      */
  -  public boolean equals(XObject obj2) throws javax.xml.transform.TransformerException
  +  public boolean equals(XObject obj2)
     {
   
       // In order to handle the 'all' semantics of 
  
  
  
  1.13.2.3  +52 -33    xml-xalan/java/src/org/apache/xpath/objects/XRTreeFrag.java
  
  Index: XRTreeFrag.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/objects/XRTreeFrag.java,v
  retrieving revision 1.13.2.2
  retrieving revision 1.13.2.3
  diff -u -r1.13.2.2 -r1.13.2.3
  --- XRTreeFrag.java	2001/05/07 13:16:01	1.13.2.2
  +++ XRTreeFrag.java	2001/05/18 07:17:21	1.13.2.3
  @@ -63,6 +63,8 @@
   import org.apache.xml.dtm.DTMIterator;
   import org.apache.xml.dtm.DTMFilter;
   
  +import org.apache.xml.utils.XMLString;
  +
   import org.apache.xpath.DOMHelper;
   import org.apache.xpath.XPathContext;
   
  @@ -138,7 +140,7 @@
   //      java.text.NumberFormat.getNumberInstance();
       double result;
       
  -    String s = m_dtm.getStringValue(m_dtmRoot);
  +    XMLString s = m_dtm.getStringValue(m_dtmRoot);
   
       if (null != s)
       {
  @@ -176,6 +178,16 @@
     {
       return true;
     }
  +  
  +  /**
  +   * Cast result object to an XMLString.
  +   *
  +   * @return The document fragment node data or the empty string. 
  +   */
  +  public XMLString xstr()
  +  {
  +    return m_dtm.getStringValue(m_dtmRoot);
  +  }
   
     /**
      * Cast result object to a string.
  @@ -184,7 +196,7 @@
      */
     public String str()
     {
  -    String str = m_dtm.getStringValue(m_dtmRoot);
  +    String str = m_dtm.getStringValue(m_dtmRoot).toString();
   
       return (null == str) ? "" : str;
     }
  @@ -233,42 +245,49 @@
      *
      * @throws javax.xml.transform.TransformerException
      */
  -  public boolean equals(XObject obj2) throws javax.xml.transform.TransformerException
  +  public boolean equals(XObject obj2)
     {
  -
  -    if (XObject.CLASS_NODESET == obj2.getType())
  -    {
   
  -      // In order to handle the 'all' semantics of 
  -      // nodeset comparisons, we always call the 
  -      // nodeset function.
  -      return obj2.equals(this);
  -    }
  -    else if (XObject.CLASS_BOOLEAN == obj2.getType())
  +    try
       {
  -      return bool() == obj2.bool();
  -    }
  -    else if (XObject.CLASS_NUMBER == obj2.getType())
  -    {
  -      return num() == obj2.num();
  -    }
  -    else if (XObject.CLASS_NODESET == obj2.getType())
  -    {
  -      return str().equals(obj2.str());
  -    }
  -    else if (XObject.CLASS_STRING == obj2.getType())
  -    {
  -      return str().equals(obj2.str());
  -    }
  -    else if (XObject.CLASS_RTREEFRAG == obj2.getType())
  -    {
  -
  -      // Probably not so good.  Think about this.
  -      return str().equals(obj2.str());
  +      if (XObject.CLASS_NODESET == obj2.getType())
  +      {
  +  
  +        // In order to handle the 'all' semantics of 
  +        // nodeset comparisons, we always call the 
  +        // nodeset function.
  +        return obj2.equals(this);
  +      }
  +      else if (XObject.CLASS_BOOLEAN == obj2.getType())
  +      {
  +        return bool() == obj2.bool();
  +      }
  +      else if (XObject.CLASS_NUMBER == obj2.getType())
  +      {
  +        return num() == obj2.num();
  +      }
  +      else if (XObject.CLASS_NODESET == obj2.getType())
  +      {
  +        return str().equals(obj2.str());
  +      }
  +      else if (XObject.CLASS_STRING == obj2.getType())
  +      {
  +        return str().equals(obj2.str());
  +      }
  +      else if (XObject.CLASS_RTREEFRAG == obj2.getType())
  +      {
  +  
  +        // Probably not so good.  Think about this.
  +        return str().equals(obj2.str());
  +      }
  +      else
  +      {
  +        return super.equals(obj2);
  +      }
       }
  -    else
  +    catch(javax.xml.transform.TransformerException te)
       {
  -      return super.equals(obj2);
  +      throw new org.apache.xml.utils.WrappedRuntimeException(te);
       }
     }
   
  
  
  
  1.6.2.3   +805 -7    xml-xalan/java/src/org/apache/xpath/objects/XString.java
  
  Index: XString.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/objects/XString.java,v
  retrieving revision 1.6.2.2
  retrieving revision 1.6.2.3
  diff -u -r1.6.2.2 -r1.6.2.3
  --- XString.java	2001/05/07 13:16:02	1.6.2.2
  +++ XString.java	2001/05/18 07:17:22	1.6.2.3
  @@ -60,19 +60,34 @@
   import org.apache.xml.dtm.DTM;
   import org.apache.xml.dtm.DTMIterator;
   import org.apache.xml.dtm.DTMFilter;
  -
   import org.apache.xpath.XPathContext;
  +import org.apache.xml.utils.XMLString;
  +import org.apache.xml.utils.XMLStringFactory;
  +import org.apache.xml.utils.XMLCharacterRecognizer;
  +import org.apache.xml.utils.FastStringBuffer;
  +
  +import java.util.Locale;
   
   /**
    * <meta name="usage" content="general"/>
    * This class represents an XPath string object, and is capable of
    * converting the string to other types, such as a number.
    */
  -public class XString extends XObject
  +public class XString extends XObject implements XMLString
   {
   
  -  /** Empty string XString object          */
  +  /** Empty string XString object */
     public static XString EMPTYSTRING = new XString("");
  +  
  +  /**
  +   * Construct a XString object.  This constructor exists for derived classes.
  +   *
  +   * @param val String object this will wrap.
  +   */
  +  protected XString(Object val)
  +  {
  +    super(val);
  +  }
   
     /**
      * Construct a XNodeSet object.
  @@ -113,6 +128,20 @@
      * @return 0.0 if the string is null, numeric value of the string
      * or NaN
      */
  +  public static double castToNum(XMLString s)
  +  {
  +    // %OPT% For now...
  +    return castToNum(s.toString());
  +  }
  +  
  +  /**
  +   * Cast a string to a number.
  +   *
  +   * @param s The string to convert
  +   *
  +   * @return 0.0 if the string is null, numeric value of the string
  +   * or NaN
  +   */
     public static double castToNum(String s)
     {
   
  @@ -172,7 +201,7 @@
      */
     public double num()
     {
  -    return castToNum((String) m_obj);
  +    return castToNum(str());
     }
   
     /**
  @@ -185,6 +214,16 @@
     {
       return str().length() > 0;
     }
  +  
  +  /**
  +   * Cast result object to a string.
  +   *
  +   * @return The string this wraps or the empty string if null
  +   */
  +  public XMLString xstr()
  +  {
  +    return this;
  +  }
   
     /**
      * Cast result object to a string.
  @@ -199,19 +238,110 @@
     /**
      * Cast result object to a result tree fragment.
      *
  -   * @param support Xpath context to use for the conversion 
  +   * @param support Xpath context to use for the conversion
      *
      * @return A document fragment with this string as a child node
      */
     public int rtree(XPathContext support)
     {
  +
       DTM frag = support.createDocumentFragment();
  +
       frag.appendTextChild(str());
  -    
  +
       return frag.getDocument();
     }
  +  
  +  /**
  +   * Directly call the
  +   * characters method on the passed ContentHandler for the
  +   * string-value. Multiple calls to the
  +   * ContentHandler's characters methods may well occur for a single call to
  +   * this method.
  +   *
  +   * @param ch A non-null reference to a ContentHandler.
  +   *
  +   * @throws org.xml.sax.SAXException
  +   */
  +  public void dispatchCharactersEvents(org.xml.sax.ContentHandler ch)
  +      throws org.xml.sax.SAXException
  +  {
  +    String str = str();
  +    ch.characters(str.toCharArray(), 0, str.length());
  +  }
  +      
  +  /**
  +   * Directly call the
  +   * comment method on the passed LexicalHandler for the
  +   * string-value.
  +   *
  +   * @param lh A non-null reference to a LexicalHandler.
  +   *
  +   * @throws org.xml.sax.SAXException
  +   */
  +  public void dispatchAsComment(org.xml.sax.ext.LexicalHandler lh)
  +      throws org.xml.sax.SAXException
  +  {
  +    String str = str();
  +    lh.comment(str.toCharArray(), 0, str.length());
  +  }
  +  
  +  /**
  +   * Returns the length of this string.
  +   *
  +   * @return  the length of the sequence of characters represented by this
  +   *          object.
  +   */
  +  public int length()
  +  {
  +    return str().length();
  +  }
   
     /**
  +   * Returns the character at the specified index. An index ranges
  +   * from <code>0</code> to <code>length() - 1</code>. The first character
  +   * of the sequence is at index <code>0</code>, the next at index
  +   * <code>1</code>, and so on, as for array indexing.
  +   *
  +   * @param      index   the index of the character.
  +   * @return     the character at the specified index of this string.
  +   *             The first character is at index <code>0</code>.
  +   * @exception  IndexOutOfBoundsException  if the <code>index</code>
  +   *             argument is negative or not less than the length of this
  +   *             string.
  +   */
  +  public char charAt(int index)
  +  {
  +    return str().charAt(index);
  +  }
  +
  +  /**
  +   * Copies characters from this string into the destination character
  +   * array.
  +   *
  +   * @param      srcBegin   index of the first character in the string
  +   *                        to copy.
  +   * @param      srcEnd     index after the last character in the string
  +   *                        to copy.
  +   * @param      dst        the destination array.
  +   * @param      dstBegin   the start offset in the destination array.
  +   * @exception IndexOutOfBoundsException If any of the following
  +   *            is true:
  +   *            <ul><li><code>srcBegin</code> is negative.
  +   *            <li><code>srcBegin</code> is greater than <code>srcEnd</code>
  +   *            <li><code>srcEnd</code> is greater than the length of this
  +   *                string
  +   *            <li><code>dstBegin</code> is negative
  +   *            <li><code>dstBegin+(srcEnd-srcBegin)</code> is larger than
  +   *                <code>dst.length</code></ul>
  +   * @exception NullPointerException if <code>dst</code> is <code>null</code>
  +   */
  +  public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin)
  +  {
  +    str().getChars(srcBegin, srcEnd, dst, dstBegin);
  +  }
  +  
  +  /**
      * Tell if two objects are functionally equal.
      *
      * @param obj2 Object to compare this to
  @@ -220,7 +350,7 @@
      *
      * @throws javax.xml.transform.TransformerException
      */
  -  public boolean equals(XObject obj2) throws javax.xml.transform.TransformerException
  +  public boolean equals(XObject obj2)
     {
   
       // In order to handle the 'all' semantics of 
  @@ -231,4 +361,672 @@
   
       return str().equals(obj2.str());
     }
  +  
  +  /**
  +   * Compares this string to the specified object.
  +   * The result is <code>true</code> if and only if the argument is not
  +   * <code>null</code> and is a <code>String</code> object that represents
  +   * the same sequence of characters as this object.
  +   *
  +   * @param   anObject   the object to compare this <code>String</code>
  +   *                     against.
  +   * @return  <code>true</code> if the <code>String </code>are equal;
  +   *          <code>false</code> otherwise.
  +   * @see     java.lang.String#compareTo(java.lang.String)
  +   * @see     java.lang.String#equalsIgnoreCase(java.lang.String)
  +   */
  +  public boolean equals(XMLString obj2)
  +  {
  +    return str().equals(obj2.toString());
  +  }
  +
  +  /**
  +   * Compares this string to the specified object.
  +   * The result is <code>true</code> if and only if the argument is not
  +   * <code>null</code> and is a <code>String</code> object that represents
  +   * the same sequence of characters as this object.
  +   *
  +   * @param   anObject   the object to compare this <code>String</code>
  +   *                     against.
  +   * @return  <code>true</code> if the <code>String </code>are equal;
  +   *          <code>false</code> otherwise.
  +   * @see     java.lang.String#compareTo(java.lang.String)
  +   * @see     java.lang.String#equalsIgnoreCase(java.lang.String)
  +   */
  +  public boolean equals(Object obj2)
  +  {
  +    if(null == obj2)
  +      return false;
  +      
  +    // In order to handle the 'all' semantics of 
  +    // nodeset comparisons, we always call the 
  +    // nodeset function.
  +    else if (obj2 instanceof XNodeSet)
  +      return obj2.equals(this);
  +    else
  +      return str().equals(obj2.toString());
  +  }
  +
  +
  +  /**
  +   * Compares this <code>String</code> to another <code>String</code>,
  +   * ignoring case considerations.  Two strings are considered equal
  +   * ignoring case if they are of the same length, and corresponding
  +   * characters in the two strings are equal ignoring case.
  +   *
  +   * @param   anotherString   the <code>String</code> to compare this
  +   *                          <code>String</code> against.
  +   * @return  <code>true</code> if the argument is not <code>null</code>
  +   *          and the <code>String</code>s are equal,
  +   *          ignoring case; <code>false</code> otherwise.
  +   * @see     #equals(Object)
  +   * @see     java.lang.Character#toLowerCase(char)
  +   * @see java.lang.Character#toUpperCase(char)
  +   */
  +  public boolean equalsIgnoreCase(String anotherString)
  +  {
  +    return str().equalsIgnoreCase(anotherString);
  +  }
  +
  +  /**
  +   * Compares two strings lexicographically.
  +   *
  +   * @param   anotherString   the <code>String</code> to be compared.
  +   * @return  the value <code>0</code> if the argument string is equal to
  +   *          this string; a value less than <code>0</code> if this string
  +   *          is lexicographically less than the string argument; and a
  +   *          value greater than <code>0</code> if this string is
  +   *          lexicographically greater than the string argument.
  +   * @exception java.lang.NullPointerException if <code>anotherString</code>
  +   *          is <code>null</code>.
  +   */
  +  public int compareTo(XMLString anotherString)
  +  {
  +    return str().compareTo(anotherString.toString());
  +  }
  +
  +  /**
  +   * Compares two strings lexicographically, ignoring case considerations.
  +   * This method returns an integer whose sign is that of
  +   * <code>this.toUpperCase().toLowerCase().compareTo(
  +   * str.toUpperCase().toLowerCase())</code>.
  +   * <p>
  +   * Note that this method does <em>not</em> take locale into account,
  +   * and will result in an unsatisfactory ordering for certain locales.
  +   * The java.text package provides <em>collators</em> to allow
  +   * locale-sensitive ordering.
  +   *
  +   * @param   str   the <code>String</code> to be compared.
  +   * @return  a negative integer, zero, or a positive integer as the
  +   *          the specified String is greater than, equal to, or less
  +   *          than this String, ignoring case considerations.
  +   * @see     java.text.Collator#compare(String, String)
  +   * @since   1.2
  +   */
  +  public int compareToIgnoreCase(XMLString str)
  +  {
  +    return str().compareToIgnoreCase(str.toString());
  +  }
  +
  +  /**
  +   * Tests if this string starts with the specified prefix beginning
  +   * a specified index.
  +   *
  +   * @param   prefix    the prefix.
  +   * @param   toffset   where to begin looking in the string.
  +   * @return  <code>true</code> if the character sequence represented by the
  +   *          argument is a prefix of the substring of this object starting
  +   *          at index <code>toffset</code>; <code>false</code> otherwise.
  +   *          The result is <code>false</code> if <code>toffset</code> is
  +   *          negative or greater than the length of this
  +   *          <code>String</code> object; otherwise the result is the same
  +   *          as the result of the expression
  +   *          <pre>
  +   *          this.subString(toffset).startsWith(prefix)
  +   *          </pre>
  +   * @exception java.lang.NullPointerException if <code>prefix</code> is
  +   *          <code>null</code>.
  +   */
  +  public boolean startsWith(String prefix, int toffset)
  +  {
  +    return str().startsWith(prefix, toffset);
  +  }
  +
  +  /**
  +   * Tests if this string starts with the specified prefix.
  +   *
  +   * @param   prefix   the prefix.
  +   * @return  <code>true</code> if the character sequence represented by the
  +   *          argument is a prefix of the character sequence represented by
  +   *          this string; <code>false</code> otherwise.
  +   *          Note also that <code>true</code> will be returned if the
  +   *          argument is an empty string or is equal to this
  +   *          <code>String</code> object as determined by the
  +   *          {@link #equals(Object)} method.
  +   * @exception java.lang.NullPointerException if <code>prefix</code> is
  +   *          <code>null</code>.
  +   */
  +  public boolean startsWith(String prefix)
  +  {
  +    return str().startsWith(prefix);
  +  }
  +
  +  /**
  +   * Tests if this string ends with the specified suffix.
  +   *
  +   * @param   suffix   the suffix.
  +   * @return  <code>true</code> if the character sequence represented by the
  +   *          argument is a suffix of the character sequence represented by
  +   *          this object; <code>false</code> otherwise. Note that the
  +   *          result will be <code>true</code> if the argument is the
  +   *          empty string or is equal to this <code>String</code> object
  +   *          as determined by the {@link #equals(Object)} method.
  +   * @exception java.lang.NullPointerException if <code>suffix</code> is
  +   *          <code>null</code>.
  +   */
  +  public boolean endsWith(String suffix)
  +  {
  +    return str().endsWith(suffix);
  +  }
  +
  +  /**
  +   * Returns a hashcode for this string. The hashcode for a
  +   * <code>String</code> object is computed as
  +   * <blockquote><pre>
  +   * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
  +   * </pre></blockquote>
  +   * using <code>int</code> arithmetic, where <code>s[i]</code> is the
  +   * <i>i</i>th character of the string, <code>n</code> is the length of
  +   * the string, and <code>^</code> indicates exponentiation.
  +   * (The hash value of the empty string is zero.)
  +   *
  +   * @return  a hash code value for this object.
  +   */
  +  public int hashCode()
  +  {
  +    return str().hashCode();
  +  }
  +
  +  /**
  +   * Returns the index within this string of the first occurrence of the
  +   * specified character. If a character with value <code>ch</code> occurs
  +   * in the character sequence represented by this <code>String</code>
  +   * object, then the index of the first such occurrence is returned --
  +   * that is, the smallest value <i>k</i> such that:
  +   * <blockquote><pre>
  +   * this.charAt(<i>k</i>) == ch
  +   * </pre></blockquote>
  +   * is <code>true</code>. If no such character occurs in this string,
  +   * then <code>-1</code> is returned.
  +   *
  +   * @param   ch   a character.
  +   * @return  the index of the first occurrence of the character in the
  +   *          character sequence represented by this object, or
  +   *          <code>-1</code> if the character does not occur.
  +   */
  +  public int indexOf(int ch)
  +  {
  +    return str().indexOf(ch);
  +  }
  +
  +  /**
  +   * Returns the index within this string of the first occurrence of the
  +   * specified character, starting the search at the specified index.
  +   * <p>
  +   * If a character with value <code>ch</code> occurs in the character
  +   * sequence represented by this <code>String</code> object at an index
  +   * no smaller than <code>fromIndex</code>, then the index of the first
  +   * such occurrence is returned--that is, the smallest value <i>k</i>
  +   * such that:
  +   * <blockquote><pre>
  +   * (this.charAt(<i>k</i>) == ch) && (<i>k</i> >= fromIndex)
  +   * </pre></blockquote>
  +   * is true. If no such character occurs in this string at or after
  +   * position <code>fromIndex</code>, then <code>-1</code> is returned.
  +   * <p>
  +   * There is no restriction on the value of <code>fromIndex</code>. If it
  +   * is negative, it has the same effect as if it were zero: this entire
  +   * string may be searched. If it is greater than the length of this
  +   * string, it has the same effect as if it were equal to the length of
  +   * this string: <code>-1</code> is returned.
  +   *
  +   * @param   ch          a character.
  +   * @param   fromIndex   the index to start the search from.
  +   * @return  the index of the first occurrence of the character in the
  +   *          character sequence represented by this object that is greater
  +   *          than or equal to <code>fromIndex</code>, or <code>-1</code>
  +   *          if the character does not occur.
  +   */
  +  public int indexOf(int ch, int fromIndex)
  +  {
  +    return str().indexOf(ch, fromIndex);
  +  }
  +
  +  /**
  +   * Returns the index within this string of the last occurrence of the
  +   * specified character. That is, the index returned is the largest
  +   * value <i>k</i> such that:
  +   * <blockquote><pre>
  +   * this.charAt(<i>k</i>) == ch
  +   * </pre></blockquote>
  +   * is true.
  +   * The String is searched backwards starting at the last character.
  +   *
  +   * @param   ch   a character.
  +   * @return  the index of the last occurrence of the character in the
  +   *          character sequence represented by this object, or
  +   *          <code>-1</code> if the character does not occur.
  +   */
  +  public int lastIndexOf(int ch)
  +  {
  +    return str().lastIndexOf(ch);
  +  }
  +
  +  /**
  +   * Returns the index within this string of the last occurrence of the
  +   * specified character, searching backward starting at the specified
  +   * index. That is, the index returned is the largest value <i>k</i>
  +   * such that:
  +   * <blockquote><pre>
  +   * this.charAt(k) == ch) && (k <= fromIndex)
  +   * </pre></blockquote>
  +   * is true.
  +   *
  +   * @param   ch          a character.
  +   * @param   fromIndex   the index to start the search from. There is no
  +   *          restriction on the value of <code>fromIndex</code>. If it is
  +   *          greater than or equal to the length of this string, it has
  +   *          the same effect as if it were equal to one less than the
  +   *          length of this string: this entire string may be searched.
  +   *          If it is negative, it has the same effect as if it were -1:
  +   *          -1 is returned.
  +   * @return  the index of the last occurrence of the character in the
  +   *          character sequence represented by this object that is less
  +   *          than or equal to <code>fromIndex</code>, or <code>-1</code>
  +   *          if the character does not occur before that point.
  +   */
  +  public int lastIndexOf(int ch, int fromIndex)
  +  {
  +    return str().lastIndexOf(ch, fromIndex);
  +  }
  +
  +  /**
  +   * Returns the index within this string of the first occurrence of the
  +   * specified substring. The integer returned is the smallest value
  +   * <i>k</i> such that:
  +   * <blockquote><pre>
  +   * this.startsWith(str, <i>k</i>)
  +   * </pre></blockquote>
  +   * is <code>true</code>.
  +   *
  +   * @param   str   any string.
  +   * @return  if the string argument occurs as a substring within this
  +   *          object, then the index of the first character of the first
  +   *          such substring is returned; if it does not occur as a
  +   *          substring, <code>-1</code> is returned.
  +   * @exception java.lang.NullPointerException if <code>str</code> is
  +   *          <code>null</code>.
  +   */
  +  public int indexOf(String str)
  +  {
  +    return str().indexOf(str);
  +  }
  +  
  +  /**
  +   * Returns the index within this string of the first occurrence of the
  +   * specified substring. The integer returned is the smallest value
  +   * <i>k</i> such that:
  +   * <blockquote><pre>
  +   * this.startsWith(str, <i>k</i>)
  +   * </pre></blockquote>
  +   * is <code>true</code>.
  +   *
  +   * @param   str   any string.
  +   * @return  if the string argument occurs as a substring within this
  +   *          object, then the index of the first character of the first
  +   *          such substring is returned; if it does not occur as a
  +   *          substring, <code>-1</code> is returned.
  +   * @exception java.lang.NullPointerException if <code>str</code> is
  +   *          <code>null</code>.
  +   */
  +  public int indexOf(XMLString str)
  +  {
  +    return str().indexOf(str.toString());
  +  }
  +
  +  /**
  +   * Returns the index within this string of the first occurrence of the
  +   * specified substring, starting at the specified index. The integer
  +   * returned is the smallest value <i>k</i> such that:
  +   * <blockquote><pre>
  +   * this.startsWith(str, <i>k</i>) && (<i>k</i> >= fromIndex)
  +   * </pre></blockquote>
  +   * is <code>true</code>.
  +   * <p>
  +   * There is no restriction on the value of <code>fromIndex</code>. If
  +   * it is negative, it has the same effect as if it were zero: this entire
  +   * string may be searched. If it is greater than the length of this
  +   * string, it has the same effect as if it were equal to the length of
  +   * this string: <code>-1</code> is returned.
  +   *
  +   * @param   str         the substring to search for.
  +   * @param   fromIndex   the index to start the search from.
  +   * @return  If the string argument occurs as a substring within this
  +   *          object at a starting index no smaller than
  +   *          <code>fromIndex</code>, then the index of the first character
  +   *          of the first such substring is returned. If it does not occur
  +   *          as a substring starting at <code>fromIndex</code> or beyond,
  +   *          <code>-1</code> is returned.
  +   * @exception java.lang.NullPointerException if <code>str</code> is
  +   *          <code>null</code>
  +   */
  +  public int indexOf(String str, int fromIndex)
  +  {
  +    return str().indexOf(str, fromIndex);
  +  }
  +
  +  /**
  +   * Returns the index within this string of the rightmost occurrence
  +   * of the specified substring.  The rightmost empty string "" is
  +   * considered to occur at the index value <code>this.length()</code>.
  +   * The returned index is the largest value <i>k</i> such that
  +   * <blockquote><pre>
  +   * this.startsWith(str, k)
  +   * </pre></blockquote>
  +   * is true.
  +   *
  +   * @param   str   the substring to search for.
  +   * @return  if the string argument occurs one or more times as a substring
  +   *          within this object, then the index of the first character of
  +   *          the last such substring is returned. If it does not occur as
  +   *          a substring, <code>-1</code> is returned.
  +   * @exception java.lang.NullPointerException  if <code>str</code> is
  +   *          <code>null</code>.
  +   */
  +  public int lastIndexOf(String str)
  +  {
  +    return str().lastIndexOf(str);
  +  }
  +
  +  /**
  +   * Returns the index within this string of the last occurrence of
  +   * the specified substring.
  +   *
  +   * @param   str         the substring to search for.
  +   * @param   fromIndex   the index to start the search from. There is no
  +   *          restriction on the value of fromIndex. If it is greater than
  +   *          the length of this string, it has the same effect as if it
  +   *          were equal to the length of this string: this entire string
  +   *          may be searched. If it is negative, it has the same effect
  +   *          as if it were -1: -1 is returned.
  +   * @return  If the string argument occurs one or more times as a substring
  +   *          within this object at a starting index no greater than
  +   *          <code>fromIndex</code>, then the index of the first character of
  +   *          the last such substring is returned. If it does not occur as a
  +   *          substring starting at <code>fromIndex</code> or earlier,
  +   *          <code>-1</code> is returned.
  +   * @exception java.lang.NullPointerException if <code>str</code> is
  +   *          <code>null</code>.
  +   */
  +  public int lastIndexOf(String str, int fromIndex)
  +  {
  +    return str().lastIndexOf(str, fromIndex);
  +  }
  +
  +  /**
  +   * Returns a new string that is a substring of this string. The
  +   * substring begins with the character at the specified index and
  +   * extends to the end of this string. <p>
  +   * Examples:
  +   * <blockquote><pre>
  +   * "unhappy".substring(2) returns "happy"
  +   * "Harbison".substring(3) returns "bison"
  +   * "emptiness".substring(9) returns "" (an empty string)
  +   * </pre></blockquote>
  +   *
  +   * @param      beginIndex   the beginning index, inclusive.
  +   * @return     the specified substring.
  +   * @exception  IndexOutOfBoundsException  if
  +   *             <code>beginIndex</code> is negative or larger than the
  +   *             length of this <code>String</code> object.
  +   */
  +  public XMLString substring(int beginIndex)
  +  {
  +    return new XString(str().substring(beginIndex));
  +  }
  +
  +  /**
  +   * Returns a new string that is a substring of this string. The
  +   * substring begins at the specified <code>beginIndex</code> and
  +   * extends to the character at index <code>endIndex - 1</code>.
  +   * Thus the length of the substring is <code>endIndex-beginIndex</code>.
  +   *
  +   * @param      beginIndex   the beginning index, inclusive.
  +   * @param      endIndex     the ending index, exclusive.
  +   * @return     the specified substring.
  +   * @exception  IndexOutOfBoundsException  if the
  +   *             <code>beginIndex</code> is negative, or
  +   *             <code>endIndex</code> is larger than the length of
  +   *             this <code>String</code> object, or
  +   *             <code>beginIndex</code> is larger than
  +   *             <code>endIndex</code>.
  +   */
  +  public XMLString substring(int beginIndex, int endIndex)
  +  {
  +    return new XString(str().substring(beginIndex, endIndex));
  +  }
  +
  +  /**
  +   * Concatenates the specified string to the end of this string.
  +   *
  +   * @param   str   the <code>String</code> that is concatenated to the end
  +   *                of this <code>String</code>.
  +   * @return  a string that represents the concatenation of this object's
  +   *          characters followed by the string argument's characters.
  +   * @exception java.lang.NullPointerException if <code>str</code> is
  +   *          <code>null</code>.
  +   */
  +  public XMLString concat(String str)
  +  {
  +
  +    // %REVIEW% Make an FSB here?
  +    return new XString(str().concat(str));
  +  }
  +
  +  /**
  +   * Converts all of the characters in this <code>String</code> to lower
  +   * case using the rules of the given <code>Locale</code>.
  +   *
  +   * @param locale use the case transformation rules for this locale
  +   * @return the String, converted to lowercase.
  +   * @see     java.lang.Character#toLowerCase(char)
  +   * @see     java.lang.String#toUpperCase(Locale)
  +   */
  +  public XMLString toLowerCase(Locale locale)
  +  {
  +    return new XString(str().toLowerCase(locale));
  +  }
  +
  +  /**
  +   * Converts all of the characters in this <code>String</code> to lower
  +   * case using the rules of the default locale, which is returned
  +   * by <code>Locale.getDefault</code>.
  +   * <p>
  +   *
  +   * @return  the string, converted to lowercase.
  +   * @see     java.lang.Character#toLowerCase(char)
  +   * @see     java.lang.String#toLowerCase(Locale)
  +   */
  +  public XMLString toLowerCase()
  +  {
  +    return new XString(str().toLowerCase());
  +  }
  +
  +  /**
  +   * Converts all of the characters in this <code>String</code> to upper
  +   * case using the rules of the given locale.
  +   * @param locale use the case transformation rules for this locale
  +   * @return the String, converted to uppercase.
  +   * @see     java.lang.Character#toUpperCase(char)
  +   * @see     java.lang.String#toLowerCase(Locale)
  +   */
  +  public XMLString toUpperCase(Locale locale)
  +  {
  +    return new XString(str().toUpperCase(locale));
  +  }
  +
  +  /**
  +   * Converts all of the characters in this <code>String</code> to upper
  +   * case using the rules of the default locale, which is returned
  +   * by <code>Locale.getDefault</code>.
  +   *
  +   * <p>
  +   * If no character in this string has a different uppercase version,
  +   * based on calling the <code>toUpperCase</code> method defined by
  +   * <code>Character</code>, then the original string is returned.
  +   * <p>
  +   * Otherwise, this method creates a new <code>String</code> object
  +   * representing a character sequence identical in length to the
  +   * character sequence represented by this <code>String</code> object and
  +   * with every character equal to the result of applying the method
  +   * <code>Character.toUpperCase</code> to the corresponding character of
  +   * this <code>String</code> object. <p>
  +   * Examples:
  +   * <blockquote><pre>
  +   * "Fahrvergn�gen".toUpperCase() returns "FAHRVERGN�GEN"
  +   * "Visit Ljubinje!".toUpperCase() returns "VISIT LJUBINJE!"
  +   * </pre></blockquote>
  +   *
  +   * @return  the string, converted to uppercase.
  +   * @see     java.lang.Character#toUpperCase(char)
  +   * @see     java.lang.String#toUpperCase(Locale)
  +   */
  +  public XMLString toUpperCase()
  +  {
  +    return new XString(str().toUpperCase());
  +  }
  +
  +  /**
  +   * Removes white space from both ends of this string.
  +   *
  +   * @return  this string, with white space removed from the front and end.
  +   */
  +  public XMLString trim()
  +  {
  +    return new XString(str().trim());
  +  }
  +  
  +  /**
  +   * Returns whether the specified <var>ch</var> conforms to the XML 1.0 definition
  +   * of whitespace.  Refer to <A href="http://www.w3.org/TR/1998/REC-xml-19980210#NT-S">
  +   * the definition of <CODE>S</CODE></A> for details.
  +   * @param   ch      Character to check as XML whitespace.
  +   * @return          =true if <var>ch</var> is XML whitespace; otherwise =false.
  +   */
  +  private static boolean isSpace(char ch)
  +  {
  +    return XMLCharacterRecognizer.isWhiteSpace(ch);  // Take the easy way out for now.
  +  }
  +  
  +  /**
  +   * Conditionally trim all leading and trailing whitespace in the specified String.
  +   * All strings of white space are
  +   * replaced by a single space character (#x20), except spaces after punctuation which
  +   * receive double spaces if doublePunctuationSpaces is true.
  +   * This function may be useful to a formatter, but to get first class
  +   * results, the formatter should probably do it's own white space handling
  +   * based on the semantics of the formatting object.
  +   * 
  +   * @param   trimHead    Trim leading whitespace?
  +   * @param   trimTail    Trim trailing whitespace?
  +   * @param   doublePunctuationSpaces    Use double spaces for punctuation?
  +   * @return              The trimmed string.
  +   */
  +  public XMLString fixWhiteSpace(boolean trimHead,
  +                                 boolean trimTail,
  +                                 boolean doublePunctuationSpaces)
  +  {
  +    // %OPT% !!!!!!!
  +
  +    int len = this.length();
  +    char[] buf = new char[len];
  +    this.getChars(0, len, buf, 0);
  +    boolean edit = false;
  +    int s;
  +
  +    for (s = 0; s < len; s++)
  +    {
  +      if (isSpace(buf[s]))
  +      {
  +        break;
  +      }
  +    }
  +
  +    /* replace S to ' '. and ' '+ -> single ' '. */
  +    int d = s;
  +    boolean pres = false;
  +
  +    for (; s < len; s++)
  +    {
  +      char c = buf[s];
  +
  +      if (isSpace(c))
  +      {
  +        if (!pres)
  +        {
  +          if (' ' != c)
  +          {
  +            edit = true;
  +          }
  +
  +          buf[d++] = ' ';
  +
  +          if (doublePunctuationSpaces && (s != 0))
  +          {
  +            char prevChar = buf[s - 1];
  +
  +            if (!((prevChar == '.') || (prevChar == '!')
  +                  || (prevChar == '?')))
  +            {
  +              pres = true;
  +            }
  +          }
  +          else
  +          {
  +            pres = true;
  +          }
  +        }
  +        else
  +        {
  +          edit = true;
  +          pres = true;
  +        }
  +      }
  +      else
  +      {
  +        buf[d++] = c;
  +        pres = false;
  +      }
  +    }
  +
  +    if (trimTail && 1 <= d && ' ' == buf[d - 1])
  +    {
  +      edit = true;
  +
  +      d--;
  +    }
  +
  +    int start = 0;
  +
  +    if (trimHead && 0 < d && ' ' == buf[0])
  +    {
  +      edit = true;
  +
  +      start++;
  +    }
  +
  +    XMLStringFactory xsf = XMLStringFactoryImpl.getFactory();
  +    return edit ? xsf.newstr( new String(buf, start, d - start) ) : this;
  +  }
  +
   }
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.1.2.1   +137 -0    xml-xalan/java/src/org/apache/xpath/objects/Attic/XMLStringFactoryImpl.java
  
  
  
  
  1.1.2.1   +164 -0    xml-xalan/java/src/org/apache/xpath/objects/Attic/XStringForChars.java
  
  
  
  
  1.1.2.1   +815 -0    xml-xalan/java/src/org/apache/xpath/objects/Attic/XStringForFSB.java
  
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: xalan-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: xalan-cvs-help@xml.apache.org