Coverage Report - org.codehaus.plexus.util.xml.pull.MXSerializer
 
Classes in this File Line Coverage Branch Coverage Complexity
MXSerializer
0%
0/558
0%
0/493
7.605
 
 1  
 /* -*-             c-basic-offset: 4; indent-tabs-mode: nil; -*-  //------100-columns-wide------>|*/
 2  
 // for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/)
 3  
 
 4  
 package org.codehaus.plexus.util.xml.pull;
 5  
 
 6  
 import java.io.IOException;
 7  
 import java.io.OutputStream;
 8  
 import java.io.OutputStreamWriter;
 9  
 import java.io.Writer;
 10  
 
 11  
 /**
 12  
  * Implementation of XmlSerializer interface from XmlPull V1 API. This implementation is optimized for performance and
 13  
  * low memory footprint.
 14  
  * <p>
 15  
  * Implemented features:
 16  
  * <ul>
 17  
  * <li>FEATURE_NAMES_INTERNED - when enabled all returned names (namespaces, prefixes) will be interned and it is
 18  
  * required that all names passed as arguments MUST be interned
 19  
  * <li>FEATURE_SERIALIZER_ATTVALUE_USE_APOSTROPHE
 20  
  * </ul>
 21  
  * <p>
 22  
  * Implemented properties:
 23  
  * <ul>
 24  
  * <li>PROPERTY_SERIALIZER_INDENTATION
 25  
  * <li>PROPERTY_SERIALIZER_LINE_SEPARATOR
 26  
  * </ul>
 27  
  */
 28  0
 public class MXSerializer
 29  
     implements XmlSerializer
 30  
 {
 31  
     protected final static String XML_URI = "http://www.w3.org/XML/1998/namespace";
 32  
 
 33  
     protected final static String XMLNS_URI = "http://www.w3.org/2000/xmlns/";
 34  
 
 35  
     private static final boolean TRACE_SIZING = false;
 36  
 
 37  0
     protected final String FEATURE_SERIALIZER_ATTVALUE_USE_APOSTROPHE =
 38  
         "http://xmlpull.org/v1/doc/features.html#serializer-attvalue-use-apostrophe";
 39  
 
 40  0
     protected final String FEATURE_NAMES_INTERNED = "http://xmlpull.org/v1/doc/features.html#names-interned";
 41  
 
 42  0
     protected final String PROPERTY_SERIALIZER_INDENTATION =
 43  
         "http://xmlpull.org/v1/doc/properties.html#serializer-indentation";
 44  
 
 45  0
     protected final String PROPERTY_SERIALIZER_LINE_SEPARATOR =
 46  
         "http://xmlpull.org/v1/doc/properties.html#serializer-line-separator";
 47  
 
 48  
     protected final static String PROPERTY_LOCATION = "http://xmlpull.org/v1/doc/properties.html#location";
 49  
 
 50  
     // properties/features
 51  
     protected boolean namesInterned;
 52  
 
 53  
     protected boolean attributeUseApostrophe;
 54  
 
 55  0
     protected String indentationString = null; // " ";
 56  
 
 57  0
     protected String lineSeparator = "\n";
 58  
 
 59  
     protected String location;
 60  
 
 61  
     protected Writer out;
 62  
 
 63  
     protected int autoDeclaredPrefixes;
 64  
 
 65  0
     protected int depth = 0;
 66  
 
 67  
     // element stack
 68  0
     protected String elNamespace[] = new String[2];
 69  
 
 70  0
     protected String elName[] = new String[elNamespace.length];
 71  
 
 72  0
     protected int elNamespaceCount[] = new int[elNamespace.length];
 73  
 
 74  
     // namespace stack
 75  0
     protected int namespaceEnd = 0;
 76  
 
 77  0
     protected String namespacePrefix[] = new String[8];
 78  
 
 79  0
     protected String namespaceUri[] = new String[namespacePrefix.length];
 80  
 
 81  
     protected boolean finished;
 82  
 
 83  
     protected boolean pastRoot;
 84  
 
 85  
     protected boolean setPrefixCalled;
 86  
 
 87  
     protected boolean startTagIncomplete;
 88  
 
 89  
     protected boolean doIndent;
 90  
 
 91  
     protected boolean seenTag;
 92  
 
 93  
     protected boolean seenBracket;
 94  
 
 95  
     protected boolean seenBracketBracket;
 96  
 
 97  
     // buffer output if needed to write escaped String see text(String)
 98  0
     private static final int BUF_LEN = Runtime.getRuntime().freeMemory() > 1000000L ? 8 * 1024 : 256;
 99  
 
 100  0
     protected char buf[] = new char[BUF_LEN];
 101  
 
 102  
     protected static final String precomputedPrefixes[];
 103  
 
 104  
     static
 105  
     {
 106  0
         precomputedPrefixes = new String[32]; // arbitrary number ...
 107  0
         for ( int i = 0; i < precomputedPrefixes.length; i++ )
 108  
         {
 109  0
             precomputedPrefixes[i] = ( "n" + i ).intern();
 110  
         }
 111  0
     }
 112  
 
 113  0
     private boolean checkNamesInterned = false;
 114  
 
 115  
     private void checkInterning( String name )
 116  
     {
 117  0
         if ( namesInterned && name != name.intern() )
 118  
         {
 119  0
             throw new IllegalArgumentException( "all names passed as arguments must be interned"
 120  
                 + "when NAMES INTERNED feature is enabled" );
 121  
         }
 122  0
     }
 123  
 
 124  
     protected void reset()
 125  
     {
 126  0
         location = null;
 127  0
         out = null;
 128  0
         autoDeclaredPrefixes = 0;
 129  0
         depth = 0;
 130  
 
 131  
         // nullify references on all levels to allow it to be GCed
 132  0
         for ( int i = 0; i < elNamespaceCount.length; i++ )
 133  
         {
 134  0
             elName[i] = null;
 135  0
             elNamespace[i] = null;
 136  0
             elNamespaceCount[i] = 2;
 137  
         }
 138  
 
 139  0
         namespaceEnd = 0;
 140  
 
 141  
         // NOTE: no need to intern() as all literal strings and string-valued constant expressions
 142  
         // are interned. String literals are defined in 3.10.5 of the Java Language Specification
 143  
         // just checking ...
 144  
         // assert "xmlns" == "xmlns".intern();
 145  
         // assert XMLNS_URI == XMLNS_URI.intern();
 146  
 
 147  
         // TODO: how to prevent from reporting this namespace?
 148  
         // this is special namespace declared for consistency with XML infoset
 149  0
         namespacePrefix[namespaceEnd] = "xmlns";
 150  0
         namespaceUri[namespaceEnd] = XMLNS_URI;
 151  0
         ++namespaceEnd;
 152  
 
 153  0
         namespacePrefix[namespaceEnd] = "xml";
 154  0
         namespaceUri[namespaceEnd] = XML_URI;
 155  0
         ++namespaceEnd;
 156  
 
 157  0
         finished = false;
 158  0
         pastRoot = false;
 159  0
         setPrefixCalled = false;
 160  0
         startTagIncomplete = false;
 161  
         // doIntent is not changed
 162  0
         seenTag = false;
 163  
 
 164  0
         seenBracket = false;
 165  0
         seenBracketBracket = false;
 166  0
     }
 167  
 
 168  
     protected void ensureElementsCapacity()
 169  
     {
 170  0
         final int elStackSize = elName.length;
 171  
         // assert (depth + 1) >= elName.length;
 172  
         // we add at least one extra slot ...
 173  0
         final int newSize = ( depth >= 7 ? 2 * depth : 8 ) + 2; // = lucky 7 + 1 //25
 174  
         if ( TRACE_SIZING )
 175  
         {
 176  
             System.err.println( getClass().getName() + " elStackSize " + elStackSize + " ==> " + newSize );
 177  
         }
 178  0
         final boolean needsCopying = elStackSize > 0;
 179  0
         String[] arr = null;
 180  
         // reuse arr local variable slot
 181  0
         arr = new String[newSize];
 182  0
         if ( needsCopying )
 183  0
             System.arraycopy( elName, 0, arr, 0, elStackSize );
 184  0
         elName = arr;
 185  0
         arr = new String[newSize];
 186  0
         if ( needsCopying )
 187  0
             System.arraycopy( elNamespace, 0, arr, 0, elStackSize );
 188  0
         elNamespace = arr;
 189  
 
 190  0
         final int[] iarr = new int[newSize];
 191  0
         if ( needsCopying )
 192  
         {
 193  0
             System.arraycopy( elNamespaceCount, 0, iarr, 0, elStackSize );
 194  
         }
 195  
         else
 196  
         {
 197  
             // special initialization
 198  0
             iarr[0] = 0;
 199  
         }
 200  0
         elNamespaceCount = iarr;
 201  0
     }
 202  
 
 203  
     protected void ensureNamespacesCapacity()
 204  
     { // int size) {
 205  
         // int namespaceSize = namespacePrefix != null ? namespacePrefix.length : 0;
 206  
         // assert (namespaceEnd >= namespacePrefix.length);
 207  
 
 208  
         // if(size >= namespaceSize) {
 209  
         // int newSize = size > 7 ? 2 * size : 8; // = lucky 7 + 1 //25
 210  0
         final int newSize = namespaceEnd > 7 ? 2 * namespaceEnd : 8;
 211  
         if ( TRACE_SIZING )
 212  
         {
 213  
             System.err.println( getClass().getName() + " namespaceSize " + namespacePrefix.length + " ==> " + newSize );
 214  
         }
 215  0
         final String[] newNamespacePrefix = new String[newSize];
 216  0
         final String[] newNamespaceUri = new String[newSize];
 217  0
         if ( namespacePrefix != null )
 218  
         {
 219  0
             System.arraycopy( namespacePrefix, 0, newNamespacePrefix, 0, namespaceEnd );
 220  0
             System.arraycopy( namespaceUri, 0, newNamespaceUri, 0, namespaceEnd );
 221  
         }
 222  0
         namespacePrefix = newNamespacePrefix;
 223  0
         namespaceUri = newNamespaceUri;
 224  
 
 225  
         // TODO use hashes for quick namespace->prefix lookups
 226  
         // if( ! allStringsInterned ) {
 227  
         // int[] newNamespacePrefixHash = new int[newSize];
 228  
         // if(namespacePrefixHash != null) {
 229  
         // System.arraycopy(
 230  
         // namespacePrefixHash, 0, newNamespacePrefixHash, 0, namespaceEnd);
 231  
         // }
 232  
         // namespacePrefixHash = newNamespacePrefixHash;
 233  
         // }
 234  
         // prefixesSize = newSize;
 235  
         // ////assert nsPrefixes.length > size && nsPrefixes.length == newSize
 236  
         // }
 237  0
     }
 238  
 
 239  
     public void setFeature( String name, boolean state )
 240  
         throws IllegalArgumentException, IllegalStateException
 241  
     {
 242  0
         if ( name == null )
 243  
         {
 244  0
             throw new IllegalArgumentException( "feature name can not be null" );
 245  
         }
 246  0
         if ( FEATURE_NAMES_INTERNED.equals( name ) )
 247  
         {
 248  0
             namesInterned = state;
 249  
         }
 250  0
         else if ( FEATURE_SERIALIZER_ATTVALUE_USE_APOSTROPHE.equals( name ) )
 251  
         {
 252  0
             attributeUseApostrophe = state;
 253  
         }
 254  
         else
 255  
         {
 256  0
             throw new IllegalStateException( "unsupported feature " + name );
 257  
         }
 258  0
     }
 259  
 
 260  
     public boolean getFeature( String name )
 261  
         throws IllegalArgumentException
 262  
     {
 263  0
         if ( name == null )
 264  
         {
 265  0
             throw new IllegalArgumentException( "feature name can not be null" );
 266  
         }
 267  0
         if ( FEATURE_NAMES_INTERNED.equals( name ) )
 268  
         {
 269  0
             return namesInterned;
 270  
         }
 271  0
         else if ( FEATURE_SERIALIZER_ATTVALUE_USE_APOSTROPHE.equals( name ) )
 272  
         {
 273  0
             return attributeUseApostrophe;
 274  
         }
 275  
         else
 276  
         {
 277  0
             return false;
 278  
         }
 279  
     }
 280  
 
 281  
     // precomputed variables to simplify writing indentation
 282  
     protected int offsetNewLine;
 283  
 
 284  
     protected int indentationJump;
 285  
 
 286  
     protected char[] indentationBuf;
 287  
 
 288  
     protected int maxIndentLevel;
 289  
 
 290  
     protected boolean writeLineSeparator; // should end-of-line be written
 291  
 
 292  
     protected boolean writeIndentation; // is indentation used?
 293  
 
 294  
     /**
 295  
      * For maximum efficiency when writing indents the required output is pre-computed This is internal function that
 296  
      * recomputes buffer after user requested changes.
 297  
      */
 298  
     protected void rebuildIndentationBuf()
 299  
     {
 300  0
         if ( doIndent == false )
 301  0
             return;
 302  0
         final int maxIndent = 65; // hardcoded maximum indentation size in characters
 303  0
         int bufSize = 0;
 304  0
         offsetNewLine = 0;
 305  0
         if ( writeLineSeparator )
 306  
         {
 307  0
             offsetNewLine = lineSeparator.length();
 308  0
             bufSize += offsetNewLine;
 309  
         }
 310  0
         maxIndentLevel = 0;
 311  0
         if ( writeIndentation )
 312  
         {
 313  0
             indentationJump = indentationString.length();
 314  0
             maxIndentLevel = maxIndent / indentationJump;
 315  0
             bufSize += maxIndentLevel * indentationJump;
 316  
         }
 317  0
         if ( indentationBuf == null || indentationBuf.length < bufSize )
 318  
         {
 319  0
             indentationBuf = new char[bufSize + 8];
 320  
         }
 321  0
         int bufPos = 0;
 322  0
         if ( writeLineSeparator )
 323  
         {
 324  0
             for ( int i = 0; i < lineSeparator.length(); i++ )
 325  
             {
 326  0
                 indentationBuf[bufPos++] = lineSeparator.charAt( i );
 327  
             }
 328  
         }
 329  0
         if ( writeIndentation )
 330  
         {
 331  0
             for ( int i = 0; i < maxIndentLevel; i++ )
 332  
             {
 333  0
                 for ( int j = 0; j < indentationString.length(); j++ )
 334  
                 {
 335  0
                     indentationBuf[bufPos++] = indentationString.charAt( j );
 336  
                 }
 337  
             }
 338  
         }
 339  0
     }
 340  
 
 341  
     // if(doIndent) writeIndent();
 342  
     protected void writeIndent()
 343  
         throws IOException
 344  
     {
 345  0
         final int start = writeLineSeparator ? 0 : offsetNewLine;
 346  0
         final int level = ( depth > maxIndentLevel ) ? maxIndentLevel : depth;
 347  0
         out.write( indentationBuf, start, ( level * indentationJump ) + offsetNewLine );
 348  0
     }
 349  
 
 350  
     public void setProperty( String name, Object value )
 351  
         throws IllegalArgumentException, IllegalStateException
 352  
     {
 353  0
         if ( name == null )
 354  
         {
 355  0
             throw new IllegalArgumentException( "property name can not be null" );
 356  
         }
 357  0
         if ( PROPERTY_SERIALIZER_INDENTATION.equals( name ) )
 358  
         {
 359  0
             indentationString = (String) value;
 360  
         }
 361  0
         else if ( PROPERTY_SERIALIZER_LINE_SEPARATOR.equals( name ) )
 362  
         {
 363  0
             lineSeparator = (String) value;
 364  
         }
 365  0
         else if ( PROPERTY_LOCATION.equals( name ) )
 366  
         {
 367  0
             location = (String) value;
 368  
         }
 369  
         else
 370  
         {
 371  0
             throw new IllegalStateException( "unsupported property " + name );
 372  
         }
 373  0
         writeLineSeparator = lineSeparator != null && lineSeparator.length() > 0;
 374  0
         writeIndentation = indentationString != null && indentationString.length() > 0;
 375  
         // optimize - do not write when nothing to write ...
 376  0
         doIndent = indentationString != null && ( writeLineSeparator || writeIndentation );
 377  
         // NOTE: when indentationString == null there is no indentation
 378  
         // (even though writeLineSeparator may be true ...)
 379  0
         rebuildIndentationBuf();
 380  0
         seenTag = false; // for consistency
 381  0
     }
 382  
 
 383  
     public Object getProperty( String name )
 384  
         throws IllegalArgumentException
 385  
     {
 386  0
         if ( name == null )
 387  
         {
 388  0
             throw new IllegalArgumentException( "property name can not be null" );
 389  
         }
 390  0
         if ( PROPERTY_SERIALIZER_INDENTATION.equals( name ) )
 391  
         {
 392  0
             return indentationString;
 393  
         }
 394  0
         else if ( PROPERTY_SERIALIZER_LINE_SEPARATOR.equals( name ) )
 395  
         {
 396  0
             return lineSeparator;
 397  
         }
 398  0
         else if ( PROPERTY_LOCATION.equals( name ) )
 399  
         {
 400  0
             return location;
 401  
         }
 402  
         else
 403  
         {
 404  0
             return null;
 405  
         }
 406  
     }
 407  
 
 408  
     private String getLocation()
 409  
     {
 410  0
         return location != null ? " @" + location : "";
 411  
     }
 412  
 
 413  
     // this is special method that can be accessed directly to retrieve Writer serializer is using
 414  
     public Writer getWriter()
 415  
     {
 416  0
         return out;
 417  
     }
 418  
 
 419  
     public void setOutput( Writer writer )
 420  
     {
 421  0
         reset();
 422  0
         out = writer;
 423  0
     }
 424  
 
 425  
     public void setOutput( OutputStream os, String encoding )
 426  
         throws IOException
 427  
     {
 428  0
         if ( os == null )
 429  0
             throw new IllegalArgumentException( "output stream can not be null" );
 430  0
         reset();
 431  0
         if ( encoding != null )
 432  
         {
 433  0
             out = new OutputStreamWriter( os, encoding );
 434  
         }
 435  
         else
 436  
         {
 437  0
             out = new OutputStreamWriter( os );
 438  
         }
 439  0
     }
 440  
 
 441  
     public void startDocument( String encoding, Boolean standalone )
 442  
         throws IOException
 443  
     {
 444  0
         char apos = attributeUseApostrophe ? '\'' : '"';
 445  0
         if ( attributeUseApostrophe )
 446  
         {
 447  0
             out.write( "<?xml version='1.0'" );
 448  
         }
 449  
         else
 450  
         {
 451  0
             out.write( "<?xml version=\"1.0\"" );
 452  
         }
 453  0
         if ( encoding != null )
 454  
         {
 455  0
             out.write( " encoding=" );
 456  0
             out.write( attributeUseApostrophe ? '\'' : '"' );
 457  0
             out.write( encoding );
 458  0
             out.write( attributeUseApostrophe ? '\'' : '"' );
 459  
             // out.write('\'');
 460  
         }
 461  0
         if ( standalone != null )
 462  
         {
 463  0
             out.write( " standalone=" );
 464  0
             out.write( attributeUseApostrophe ? '\'' : '"' );
 465  0
             if ( standalone )
 466  
             {
 467  0
                 out.write( "yes" );
 468  
             }
 469  
             else
 470  
             {
 471  0
                 out.write( "no" );
 472  
             }
 473  0
             out.write( attributeUseApostrophe ? '\'' : '"' );
 474  
             // if(standalone.booleanValue()) {
 475  
             // out.write(" standalone='yes'");
 476  
             // } else {
 477  
             // out.write(" standalone='no'");
 478  
             // }
 479  
         }
 480  0
         out.write( "?>" );
 481  0
         if ( writeLineSeparator )
 482  
         {
 483  0
             out.write( lineSeparator );
 484  
         }
 485  0
     }
 486  
 
 487  
     public void endDocument()
 488  
         throws IOException
 489  
     {
 490  
         // close all unclosed tag;
 491  0
         while ( depth > 0 )
 492  
         {
 493  0
             endTag( elNamespace[depth], elName[depth] );
 494  
         }
 495  0
         if ( writeLineSeparator )
 496  
         {
 497  0
             out.write( lineSeparator );
 498  
         }
 499  
         // assert depth == 0;
 500  
         // assert startTagIncomplete == false;
 501  0
         finished = pastRoot = startTagIncomplete = true;
 502  0
         out.flush();
 503  0
     }
 504  
 
 505  
     public void setPrefix( String prefix, String namespace )
 506  
         throws IOException
 507  
     {
 508  0
         if ( startTagIncomplete )
 509  0
             closeStartTag();
 510  
         // assert prefix != null;
 511  
         // assert namespace != null;
 512  0
         if ( prefix == null )
 513  
         {
 514  0
             prefix = "";
 515  
         }
 516  0
         if ( !namesInterned )
 517  
         {
 518  0
             prefix = prefix.intern(); // will throw NPE if prefix==null
 519  
         }
 520  0
         else if ( checkNamesInterned )
 521  
         {
 522  0
             checkInterning( prefix );
 523  
         }
 524  0
         else if ( prefix == null )
 525  
         {
 526  0
             throw new IllegalArgumentException( "prefix must be not null" + getLocation() );
 527  
         }
 528  
 
 529  
         // check that prefix is not duplicated ...
 530  0
         for ( int i = elNamespaceCount[depth]; i < namespaceEnd; i++ )
 531  
         {
 532  0
             if ( prefix == namespacePrefix[i] )
 533  
             {
 534  0
                 throw new IllegalStateException( "duplicated prefix " + printable( prefix ) + getLocation() );
 535  
             }
 536  
         }
 537  
 
 538  0
         if ( !namesInterned )
 539  
         {
 540  0
             namespace = namespace.intern();
 541  
         }
 542  0
         else if ( checkNamesInterned )
 543  
         {
 544  0
             checkInterning( namespace );
 545  
         }
 546  0
         else if ( namespace == null )
 547  
         {
 548  0
             throw new IllegalArgumentException( "namespace must be not null" + getLocation() );
 549  
         }
 550  
 
 551  0
         if ( namespaceEnd >= namespacePrefix.length )
 552  
         {
 553  0
             ensureNamespacesCapacity();
 554  
         }
 555  0
         namespacePrefix[namespaceEnd] = prefix;
 556  0
         namespaceUri[namespaceEnd] = namespace;
 557  0
         ++namespaceEnd;
 558  0
         setPrefixCalled = true;
 559  0
     }
 560  
 
 561  
     protected String lookupOrDeclarePrefix( String namespace )
 562  
     {
 563  0
         return getPrefix( namespace, true );
 564  
     }
 565  
 
 566  
     public String getPrefix( String namespace, boolean generatePrefix )
 567  
     {
 568  
         // assert namespace != null;
 569  0
         if ( !namesInterned )
 570  
         {
 571  
             // when String is interned we can do much faster namespace stack lookups ...
 572  0
             namespace = namespace.intern();
 573  
         }
 574  0
         else if ( checkNamesInterned )
 575  
         {
 576  0
             checkInterning( namespace );
 577  
             // assert namespace != namespace.intern();
 578  
         }
 579  0
         if ( namespace == null )
 580  
         {
 581  0
             throw new IllegalArgumentException( "namespace must be not null" + getLocation() );
 582  
         }
 583  0
         else if ( namespace.length() == 0 )
 584  
         {
 585  0
             throw new IllegalArgumentException( "default namespace cannot have prefix" + getLocation() );
 586  
         }
 587  
 
 588  
         // first check if namespace is already in scope
 589  0
         for ( int i = namespaceEnd - 1; i >= 0; --i )
 590  
         {
 591  0
             if ( namespace == namespaceUri[i] )
 592  
             {
 593  0
                 final String prefix = namespacePrefix[i];
 594  
                 // now check that prefix is still in scope
 595  0
                 for ( int p = namespaceEnd - 1; p > i; --p )
 596  
                 {
 597  0
                     if ( prefix == namespacePrefix[p] )
 598  
                         continue; // too bad - prefix is redeclared with different namespace
 599  
                 }
 600  0
                 return prefix;
 601  
             }
 602  
         }
 603  
 
 604  
         // so not found it ...
 605  0
         if ( !generatePrefix )
 606  
         {
 607  0
             return null;
 608  
         }
 609  0
         return generatePrefix( namespace );
 610  
     }
 611  
 
 612  
     private String generatePrefix( String namespace )
 613  
     {
 614  
         // assert namespace == namespace.intern();
 615  
         while ( true )
 616  
         {
 617  0
             ++autoDeclaredPrefixes;
 618  
             // fast lookup uses table that was pre-initialized in static{} ....
 619  0
             final String prefix =
 620  
                 autoDeclaredPrefixes < precomputedPrefixes.length ? precomputedPrefixes[autoDeclaredPrefixes]
 621  
                                 : ( "n" + autoDeclaredPrefixes ).intern();
 622  
             // make sure this prefix is not declared in any scope (avoid hiding in-scope prefixes)!
 623  0
             for ( int i = namespaceEnd - 1; i >= 0; --i )
 624  
             {
 625  0
                 if ( prefix == namespacePrefix[i] )
 626  
                 {
 627  
                     continue; // prefix is already declared - generate new and try again
 628  
                 }
 629  
             }
 630  
             // declare prefix
 631  
 
 632  0
             if ( namespaceEnd >= namespacePrefix.length )
 633  
             {
 634  0
                 ensureNamespacesCapacity();
 635  
             }
 636  0
             namespacePrefix[namespaceEnd] = prefix;
 637  0
             namespaceUri[namespaceEnd] = namespace;
 638  0
             ++namespaceEnd;
 639  
 
 640  0
             return prefix;
 641  
         }
 642  
     }
 643  
 
 644  
     public int getDepth()
 645  
     {
 646  0
         return depth;
 647  
     }
 648  
 
 649  
     public String getNamespace()
 650  
     {
 651  0
         return elNamespace[depth];
 652  
     }
 653  
 
 654  
     public String getName()
 655  
     {
 656  0
         return elName[depth];
 657  
     }
 658  
 
 659  
     public XmlSerializer startTag( String namespace, String name )
 660  
         throws IOException
 661  
     {
 662  
 
 663  0
         if ( startTagIncomplete )
 664  
         {
 665  0
             closeStartTag();
 666  
         }
 667  0
         seenBracket = seenBracketBracket = false;
 668  0
         if ( doIndent && depth > 0 && seenTag )
 669  
         {
 670  0
             writeIndent();
 671  
         }
 672  0
         seenTag = true;
 673  0
         setPrefixCalled = false;
 674  0
         startTagIncomplete = true;
 675  0
         ++depth;
 676  0
         if ( ( depth + 1 ) >= elName.length )
 677  
         {
 678  0
             ensureElementsCapacity();
 679  
         }
 680  
         //// assert namespace != null;
 681  
 
 682  0
         if ( checkNamesInterned && namesInterned )
 683  0
             checkInterning( namespace );
 684  0
         elNamespace[depth] = ( namesInterned || namespace == null ) ? namespace : namespace.intern();
 685  
         // assert name != null;
 686  
         // elName[ depth ] = name;
 687  0
         if ( checkNamesInterned && namesInterned )
 688  0
             checkInterning( name );
 689  0
         elName[depth] = ( namesInterned || name == null ) ? name : name.intern();
 690  0
         if ( out == null )
 691  
         {
 692  0
             throw new IllegalStateException( "setOutput() must called set before serialization can start" );
 693  
         }
 694  0
         out.write( '<' );
 695  0
         if ( namespace != null )
 696  
         {
 697  
 
 698  0
             if ( namespace.length() > 0 )
 699  
             {
 700  
                 // ALEK: in future make it as feature on serializer
 701  0
                 String prefix = null;
 702  0
                 if ( depth > 0 && ( namespaceEnd - elNamespaceCount[depth - 1] ) == 1 )
 703  
                 {
 704  
                     // if only one prefix was declared un-declare it if prefix is already declared on parent el with the
 705  
                     // same URI
 706  0
                     String uri = namespaceUri[namespaceEnd - 1];
 707  0
                     if ( uri == namespace || uri.equals( namespace ) )
 708  
                     {
 709  0
                         String elPfx = namespacePrefix[namespaceEnd - 1];
 710  
                         // 2 == to skip predefined namespaces (xml and xmlns ...)
 711  0
                         for ( int pos = elNamespaceCount[depth - 1] - 1; pos >= 2; --pos )
 712  
                         {
 713  0
                             String pf = namespacePrefix[pos];
 714  0
                             if ( pf == elPfx || pf.equals( elPfx ) )
 715  
                             {
 716  0
                                 String n = namespaceUri[pos];
 717  0
                                 if ( n == uri || n.equals( uri ) )
 718  
                                 {
 719  0
                                     --namespaceEnd; // un-declare namespace
 720  0
                                     prefix = elPfx;
 721  
                                 }
 722  
                                 break;
 723  
                             }
 724  
                         }
 725  
                     }
 726  
                 }
 727  0
                 if ( prefix == null )
 728  
                 {
 729  0
                     prefix = lookupOrDeclarePrefix( namespace );
 730  
                 }
 731  
                 // assert prefix != null;
 732  
                 // make sure that default ("") namespace to not print ":"
 733  0
                 if ( prefix.length() > 0 )
 734  
                 {
 735  0
                     out.write( prefix );
 736  0
                     out.write( ':' );
 737  
                 }
 738  0
             }
 739  
             else
 740  
             {
 741  
                 // make sure that default namespace can be declared
 742  0
                 for ( int i = namespaceEnd - 1; i >= 0; --i )
 743  
                 {
 744  0
                     if ( namespacePrefix[i] == "" )
 745  
                     {
 746  0
                         final String uri = namespaceUri[i];
 747  0
                         if ( uri == null )
 748  
                         {
 749  
                             // declare default namespace
 750  0
                             setPrefix( "", "" );
 751  
                         }
 752  0
                         else if ( uri.length() > 0 )
 753  
                         {
 754  0
                             throw new IllegalStateException( "start tag can not be written in empty default namespace "
 755  
                                 + "as default namespace is currently bound to '" + uri + "'" + getLocation() );
 756  
                         }
 757  
                         break;
 758  
                     }
 759  
                 }
 760  
             }
 761  
 
 762  
         }
 763  0
         out.write( name );
 764  0
         return this;
 765  
     }
 766  
 
 767  
     public XmlSerializer attribute( String namespace, String name, String value )
 768  
         throws IOException
 769  
     {
 770  0
         if ( !startTagIncomplete )
 771  
         {
 772  0
             throw new IllegalArgumentException( "startTag() must be called before attribute()" + getLocation() );
 773  
         }
 774  
         // assert setPrefixCalled == false;
 775  0
         out.write( ' ' );
 776  
         //// assert namespace != null;
 777  0
         if ( namespace != null && namespace.length() > 0 )
 778  
         {
 779  
             // namespace = namespace.intern();
 780  0
             if ( !namesInterned )
 781  
             {
 782  0
                 namespace = namespace.intern();
 783  
             }
 784  0
             else if ( checkNamesInterned )
 785  
             {
 786  0
                 checkInterning( namespace );
 787  
             }
 788  0
             String prefix = lookupOrDeclarePrefix( namespace );
 789  
             // assert( prefix != null);
 790  0
             if ( prefix.length() == 0 )
 791  
             {
 792  
                 // needs to declare prefix to hold default namespace
 793  
                 // NOTE: attributes such as a='b' are in NO namespace
 794  0
                 prefix = generatePrefix( namespace );
 795  
             }
 796  0
             out.write( prefix );
 797  0
             out.write( ':' );
 798  
             // if(prefix.length() > 0) {
 799  
             // out.write(prefix);
 800  
             // out.write(':');
 801  
             // }
 802  
         }
 803  
         // assert name != null;
 804  0
         out.write( name );
 805  0
         out.write( '=' );
 806  
         // assert value != null;
 807  0
         out.write( attributeUseApostrophe ? '\'' : '"' );
 808  0
         writeAttributeValue( value, out );
 809  0
         out.write( attributeUseApostrophe ? '\'' : '"' );
 810  0
         return this;
 811  
     }
 812  
 
 813  
     protected void closeStartTag()
 814  
         throws IOException
 815  
     {
 816  0
         if ( finished )
 817  
         {
 818  0
             throw new IllegalArgumentException( "trying to write past already finished output" + getLocation() );
 819  
         }
 820  0
         if ( seenBracket )
 821  
         {
 822  0
             seenBracket = seenBracketBracket = false;
 823  
         }
 824  0
         if ( startTagIncomplete || setPrefixCalled )
 825  
         {
 826  0
             if ( setPrefixCalled )
 827  
             {
 828  0
                 throw new IllegalArgumentException( "startTag() must be called immediately after setPrefix()"
 829  
                     + getLocation() );
 830  
             }
 831  0
             if ( !startTagIncomplete )
 832  
             {
 833  0
                 throw new IllegalArgumentException( "trying to close start tag that is not opened" + getLocation() );
 834  
             }
 835  
 
 836  
             // write all namespace declarations!
 837  0
             writeNamespaceDeclarations();
 838  0
             out.write( '>' );
 839  0
             elNamespaceCount[depth] = namespaceEnd;
 840  0
             startTagIncomplete = false;
 841  
         }
 842  0
     }
 843  
 
 844  
     private void writeNamespaceDeclarations()
 845  
         throws IOException
 846  
     {
 847  
         // int start = elNamespaceCount[ depth - 1 ];
 848  0
         for ( int i = elNamespaceCount[depth - 1]; i < namespaceEnd; i++ )
 849  
         {
 850  0
             if ( doIndent && namespaceUri[i].length() > 40 )
 851  
             {
 852  0
                 writeIndent();
 853  0
                 out.write( " " );
 854  
             }
 855  0
             if ( namespacePrefix[i] != "" )
 856  
             {
 857  0
                 out.write( " xmlns:" );
 858  0
                 out.write( namespacePrefix[i] );
 859  0
                 out.write( '=' );
 860  
             }
 861  
             else
 862  
             {
 863  0
                 out.write( " xmlns=" );
 864  
             }
 865  0
             out.write( attributeUseApostrophe ? '\'' : '"' );
 866  
 
 867  
             // NOTE: escaping of namespace value the same way as attributes!!!!
 868  0
             writeAttributeValue( namespaceUri[i], out );
 869  
 
 870  0
             out.write( attributeUseApostrophe ? '\'' : '"' );
 871  
         }
 872  0
     }
 873  
 
 874  
     public XmlSerializer endTag( String namespace, String name )
 875  
         throws IOException
 876  
     {
 877  
         // check that level is valid
 878  
         //// assert namespace != null;
 879  
         // if(namespace != null) {
 880  
         // namespace = namespace.intern();
 881  
         // }
 882  0
         seenBracket = seenBracketBracket = false;
 883  0
         if ( namespace != null )
 884  
         {
 885  0
             if ( !namesInterned )
 886  
             {
 887  0
                 namespace = namespace.intern();
 888  
             }
 889  0
             else if ( checkNamesInterned )
 890  
             {
 891  0
                 checkInterning( namespace );
 892  
             }
 893  
         }
 894  
 
 895  0
         if ( namespace != elNamespace[depth] )
 896  
         {
 897  0
             throw new IllegalArgumentException( "expected namespace " + printable( elNamespace[depth] ) + " and not "
 898  
                 + printable( namespace ) + getLocation() );
 899  
         }
 900  0
         if ( name == null )
 901  
         {
 902  0
             throw new IllegalArgumentException( "end tag name can not be null" + getLocation() );
 903  
         }
 904  0
         if ( checkNamesInterned && namesInterned )
 905  
         {
 906  0
             checkInterning( name );
 907  
         }
 908  
 
 909  0
         if ( ( !namesInterned && !name.equals( elName[depth] ) ) || ( namesInterned && name != elName[depth] ) )
 910  
         {
 911  0
             throw new IllegalArgumentException( "expected element name " + printable( elName[depth] ) + " and not "
 912  
                 + printable( name ) + getLocation() );
 913  
         }
 914  0
         if ( startTagIncomplete )
 915  
         {
 916  0
             writeNamespaceDeclarations();
 917  0
             out.write( " />" ); // space is added to make it easier to work in XHTML!!!
 918  0
             --depth;
 919  
         }
 920  
         else
 921  
         {
 922  0
             --depth;
 923  
             // assert startTagIncomplete == false;
 924  0
             if ( doIndent && seenTag )
 925  
             {
 926  0
                 writeIndent();
 927  
             }
 928  0
             out.write( "</" );
 929  0
             if ( namespace != null && namespace.length() > 0 )
 930  
             {
 931  
                 // TODO prefix should be already known from matching start tag ...
 932  0
                 final String prefix = lookupOrDeclarePrefix( namespace );
 933  
                 // assert( prefix != null);
 934  0
                 if ( prefix.length() > 0 )
 935  
                 {
 936  0
                     out.write( prefix );
 937  0
                     out.write( ':' );
 938  
                 }
 939  
             }
 940  0
             out.write( name );
 941  0
             out.write( '>' );
 942  
 
 943  
         }
 944  0
         namespaceEnd = elNamespaceCount[depth];
 945  0
         startTagIncomplete = false;
 946  0
         seenTag = true;
 947  0
         return this;
 948  
     }
 949  
 
 950  
     public XmlSerializer text( String text )
 951  
         throws IOException
 952  
     {
 953  
         // assert text != null;
 954  0
         if ( startTagIncomplete || setPrefixCalled )
 955  0
             closeStartTag();
 956  0
         if ( doIndent && seenTag )
 957  0
             seenTag = false;
 958  0
         writeElementContent( text, out );
 959  0
         return this;
 960  
     }
 961  
 
 962  
     public XmlSerializer text( char[] buf, int start, int len )
 963  
         throws IOException
 964  
     {
 965  0
         if ( startTagIncomplete || setPrefixCalled )
 966  0
             closeStartTag();
 967  0
         if ( doIndent && seenTag )
 968  0
             seenTag = false;
 969  0
         writeElementContent( buf, start, len, out );
 970  0
         return this;
 971  
     }
 972  
 
 973  
     public void cdsect( String text )
 974  
         throws IOException
 975  
     {
 976  0
         if ( startTagIncomplete || setPrefixCalled || seenBracket )
 977  0
             closeStartTag();
 978  0
         if ( doIndent && seenTag )
 979  0
             seenTag = false;
 980  0
         out.write( "<![CDATA[" );
 981  0
         out.write( text ); // escape?
 982  0
         out.write( "]]>" );
 983  0
     }
 984  
 
 985  
     public void entityRef( String text )
 986  
         throws IOException
 987  
     {
 988  0
         if ( startTagIncomplete || setPrefixCalled || seenBracket )
 989  0
             closeStartTag();
 990  0
         if ( doIndent && seenTag )
 991  0
             seenTag = false;
 992  0
         out.write( '&' );
 993  0
         out.write( text ); // escape?
 994  0
         out.write( ';' );
 995  0
     }
 996  
 
 997  
     public void processingInstruction( String text )
 998  
         throws IOException
 999  
     {
 1000  0
         if ( startTagIncomplete || setPrefixCalled || seenBracket )
 1001  0
             closeStartTag();
 1002  0
         if ( doIndent && seenTag )
 1003  0
             seenTag = false;
 1004  0
         out.write( "<?" );
 1005  0
         out.write( text ); // escape?
 1006  0
         out.write( "?>" );
 1007  0
     }
 1008  
 
 1009  
     public void comment( String text )
 1010  
         throws IOException
 1011  
     {
 1012  0
         if ( startTagIncomplete || setPrefixCalled || seenBracket )
 1013  0
             closeStartTag();
 1014  0
         if ( doIndent && seenTag )
 1015  0
             seenTag = false;
 1016  0
         out.write( "<!--" );
 1017  0
         out.write( text ); // escape?
 1018  0
         out.write( "-->" );
 1019  0
     }
 1020  
 
 1021  
     public void docdecl( String text )
 1022  
         throws IOException
 1023  
     {
 1024  0
         if ( startTagIncomplete || setPrefixCalled || seenBracket )
 1025  0
             closeStartTag();
 1026  0
         if ( doIndent && seenTag )
 1027  0
             seenTag = false;
 1028  0
         out.write( "<!DOCTYPE " );
 1029  0
         out.write( text ); // escape?
 1030  0
         out.write( ">" );
 1031  0
     }
 1032  
 
 1033  
     public void ignorableWhitespace( String text )
 1034  
         throws IOException
 1035  
     {
 1036  0
         if ( startTagIncomplete || setPrefixCalled || seenBracket )
 1037  0
             closeStartTag();
 1038  0
         if ( doIndent && seenTag )
 1039  0
             seenTag = false;
 1040  0
         if ( text.length() == 0 )
 1041  
         {
 1042  0
             throw new IllegalArgumentException( "empty string is not allowed for ignorable whitespace"
 1043  
                 + getLocation() );
 1044  
         }
 1045  0
         out.write( text ); // no escape?
 1046  0
     }
 1047  
 
 1048  
     public void flush()
 1049  
         throws IOException
 1050  
     {
 1051  0
         if ( !finished && startTagIncomplete )
 1052  0
             closeStartTag();
 1053  0
         out.flush();
 1054  0
     }
 1055  
 
 1056  
     // --- utility methods
 1057  
 
 1058  
     protected void writeAttributeValue( String value, Writer out )
 1059  
         throws IOException
 1060  
     {
 1061  
         // .[apostrophe and <, & escaped],
 1062  0
         final char quot = attributeUseApostrophe ? '\'' : '"';
 1063  0
         final String quotEntity = attributeUseApostrophe ? "&apos;" : "&quot;";
 1064  
 
 1065  0
         int pos = 0;
 1066  0
         for ( int i = 0; i < value.length(); i++ )
 1067  
         {
 1068  0
             char ch = value.charAt( i );
 1069  0
             if ( ch == '&' )
 1070  
             {
 1071  0
                 if ( i > pos )
 1072  0
                     out.write( value.substring( pos, i ) );
 1073  0
                 out.write( "&amp;" );
 1074  0
                 pos = i + 1;
 1075  
             }
 1076  0
             if ( ch == '<' )
 1077  
             {
 1078  0
                 if ( i > pos )
 1079  0
                     out.write( value.substring( pos, i ) );
 1080  0
                 out.write( "&lt;" );
 1081  0
                 pos = i + 1;
 1082  
             }
 1083  0
             else if ( ch == quot )
 1084  
             {
 1085  0
                 if ( i > pos )
 1086  0
                     out.write( value.substring( pos, i ) );
 1087  0
                 out.write( quotEntity );
 1088  0
                 pos = i + 1;
 1089  
             }
 1090  0
             else if ( ch < 32 )
 1091  
             {
 1092  
                 // in XML 1.0 only legal character are #x9 | #xA | #xD
 1093  
                 // and they must be escaped otherwise in attribute value they are normalized to spaces
 1094  0
                 if ( ch == 13 || ch == 10 || ch == 9 )
 1095  
                 {
 1096  0
                     if ( i > pos )
 1097  0
                         out.write( value.substring( pos, i ) );
 1098  0
                     out.write( "&#" );
 1099  0
                     out.write( Integer.toString( ch ) );
 1100  0
                     out.write( ';' );
 1101  0
                     pos = i + 1;
 1102  
                 }
 1103  
                 else
 1104  
                 {
 1105  0
                     throw new IllegalStateException( "character " + Integer.toString( ch ) + " is not allowed in output"
 1106  
                         + getLocation() );
 1107  
                     // in XML 1.1 legal are [#x1-#xD7FF]
 1108  
                     // if(ch > 0) {
 1109  
                     // if(i > pos) out.write(text.substring(pos, i));
 1110  
                     // out.write("&#");
 1111  
                     // out.write(Integer.toString(ch));
 1112  
                     // out.write(';');
 1113  
                     // pos = i + 1;
 1114  
                     // } else {
 1115  
                     // throw new IllegalStateException(
 1116  
                     // "character zero is not allowed in XML 1.1 output"+getLocation());
 1117  
                     // }
 1118  
                 }
 1119  
             }
 1120  
         }
 1121  0
         if ( pos > 0 )
 1122  
         {
 1123  0
             out.write( value.substring( pos ) );
 1124  
         }
 1125  
         else
 1126  
         {
 1127  0
             out.write( value ); // this is shortcut to the most common case
 1128  
         }
 1129  
 
 1130  0
     }
 1131  
 
 1132  
     protected void writeElementContent( String text, Writer out )
 1133  
         throws IOException
 1134  
     {
 1135  
         // escape '<', '&', ']]>', <32 if necessary
 1136  0
         int pos = 0;
 1137  0
         for ( int i = 0; i < text.length(); i++ )
 1138  
         {
 1139  
             // TODO: check if doing char[] text.getChars() would be faster than getCharAt(i) ...
 1140  0
             char ch = text.charAt( i );
 1141  0
             if ( ch == ']' )
 1142  
             {
 1143  0
                 if ( seenBracket )
 1144  
                 {
 1145  0
                     seenBracketBracket = true;
 1146  
                 }
 1147  
                 else
 1148  
                 {
 1149  0
                     seenBracket = true;
 1150  
                 }
 1151  
             }
 1152  
             else
 1153  
             {
 1154  0
                 if ( ch == '&' )
 1155  
                 {
 1156  0
                     if ( i > pos )
 1157  0
                         out.write( text.substring( pos, i ) );
 1158  0
                     out.write( "&amp;" );
 1159  0
                     pos = i + 1;
 1160  
                 }
 1161  0
                 else if ( ch == '<' )
 1162  
                 {
 1163  0
                     if ( i > pos )
 1164  0
                         out.write( text.substring( pos, i ) );
 1165  0
                     out.write( "&lt;" );
 1166  0
                     pos = i + 1;
 1167  
                 }
 1168  0
                 else if ( seenBracketBracket && ch == '>' )
 1169  
                 {
 1170  0
                     if ( i > pos )
 1171  0
                         out.write( text.substring( pos, i ) );
 1172  0
                     out.write( "&gt;" );
 1173  0
                     pos = i + 1;
 1174  
                 }
 1175  0
                 else if ( ch < 32 )
 1176  
                 {
 1177  
                     // in XML 1.0 only legal character are #x9 | #xA | #xD
 1178  0
                     if ( ch == 9 || ch == 10 || ch == 13 )
 1179  
                     {
 1180  
                         // pass through
 1181  
 
 1182  
                         // } else if(ch == 13) { //escape
 1183  
                         // if(i > pos) out.write(text.substring(pos, i));
 1184  
                         // out.write("&#");
 1185  
                         // out.write(Integer.toString(ch));
 1186  
                         // out.write(';');
 1187  
                         // pos = i + 1;
 1188  
                     }
 1189  
                     else
 1190  
                     {
 1191  0
                         throw new IllegalStateException( "character " + Integer.toString( ch )
 1192  
                             + " is not allowed in output" + getLocation() );
 1193  
                         // in XML 1.1 legal are [#x1-#xD7FF]
 1194  
                         // if(ch > 0) {
 1195  
                         // if(i > pos) out.write(text.substring(pos, i));
 1196  
                         // out.write("&#");
 1197  
                         // out.write(Integer.toString(ch));
 1198  
                         // out.write(';');
 1199  
                         // pos = i + 1;
 1200  
                         // } else {
 1201  
                         // throw new IllegalStateException(
 1202  
                         // "character zero is not allowed in XML 1.1 output"+getLocation());
 1203  
                         // }
 1204  
                     }
 1205  
                 }
 1206  0
                 if ( seenBracket )
 1207  
                 {
 1208  0
                     seenBracketBracket = seenBracket = false;
 1209  
                 }
 1210  
 
 1211  
             }
 1212  
         }
 1213  0
         if ( pos > 0 )
 1214  
         {
 1215  0
             out.write( text.substring( pos ) );
 1216  
         }
 1217  
         else
 1218  
         {
 1219  0
             out.write( text ); // this is shortcut to the most common case
 1220  
         }
 1221  
 
 1222  0
     }
 1223  
 
 1224  
     protected void writeElementContent( char[] buf, int off, int len, Writer out )
 1225  
         throws IOException
 1226  
     {
 1227  
         // escape '<', '&', ']]>'
 1228  0
         final int end = off + len;
 1229  0
         int pos = off;
 1230  0
         for ( int i = off; i < end; i++ )
 1231  
         {
 1232  0
             final char ch = buf[i];
 1233  0
             if ( ch == ']' )
 1234  
             {
 1235  0
                 if ( seenBracket )
 1236  
                 {
 1237  0
                     seenBracketBracket = true;
 1238  
                 }
 1239  
                 else
 1240  
                 {
 1241  0
                     seenBracket = true;
 1242  
                 }
 1243  
             }
 1244  
             else
 1245  
             {
 1246  0
                 if ( ch == '&' )
 1247  
                 {
 1248  0
                     if ( i > pos )
 1249  
                     {
 1250  0
                         out.write( buf, pos, i - pos );
 1251  
                     }
 1252  0
                     out.write( "&amp;" );
 1253  0
                     pos = i + 1;
 1254  
                 }
 1255  0
                 else if ( ch == '<' )
 1256  
                 {
 1257  0
                     if ( i > pos )
 1258  
                     {
 1259  0
                         out.write( buf, pos, i - pos );
 1260  
                     }
 1261  0
                     out.write( "&lt;" );
 1262  0
                     pos = i + 1;
 1263  
 
 1264  
                 }
 1265  0
                 else if ( seenBracketBracket && ch == '>' )
 1266  
                 {
 1267  0
                     if ( i > pos )
 1268  
                     {
 1269  0
                         out.write( buf, pos, i - pos );
 1270  
                     }
 1271  0
                     out.write( "&gt;" );
 1272  0
                     pos = i + 1;
 1273  
                 }
 1274  0
                 else if ( ch < 32 )
 1275  
                 {
 1276  
                     // in XML 1.0 only legal character are #x9 | #xA | #xD
 1277  0
                     if ( ch == 9 || ch == 10 || ch == 13 )
 1278  
                     {
 1279  
                         // pass through
 1280  
 
 1281  
                         // } else if(ch == 13 ) { //if(ch == '\r') {
 1282  
                         // if(i > pos) {
 1283  
                         // out.write(buf, pos, i - pos);
 1284  
                         // }
 1285  
                         // out.write("&#");
 1286  
                         // out.write(Integer.toString(ch));
 1287  
                         // out.write(';');
 1288  
                         // pos = i + 1;
 1289  
                     }
 1290  
                     else
 1291  
                     {
 1292  0
                         throw new IllegalStateException( "character " + Integer.toString( ch )
 1293  
                             + " is not allowed in output" + getLocation() );
 1294  
                         // in XML 1.1 legal are [#x1-#xD7FF]
 1295  
                         // if(ch > 0) {
 1296  
                         // if(i > pos) out.write(text.substring(pos, i));
 1297  
                         // out.write("&#");
 1298  
                         // out.write(Integer.toString(ch));
 1299  
                         // out.write(';');
 1300  
                         // pos = i + 1;
 1301  
                         // } else {
 1302  
                         // throw new IllegalStateException(
 1303  
                         // "character zero is not allowed in XML 1.1 output"+getLocation());
 1304  
                         // }
 1305  
                     }
 1306  
                 }
 1307  0
                 if ( seenBracket )
 1308  
                 {
 1309  0
                     seenBracketBracket = seenBracket = false;
 1310  
                 }
 1311  
                 // assert seenBracketBracket == seenBracket == false;
 1312  
             }
 1313  
         }
 1314  0
         if ( end > pos )
 1315  
         {
 1316  0
             out.write( buf, pos, end - pos );
 1317  
         }
 1318  0
     }
 1319  
 
 1320  
     /** simple utility method -- good for debugging */
 1321  
     protected static final String printable( String s )
 1322  
     {
 1323  0
         if ( s == null )
 1324  0
             return "null";
 1325  0
         StringBuilder retval = new StringBuilder( s.length() + 16 );
 1326  0
         retval.append( "'" );
 1327  
         char ch;
 1328  0
         for ( int i = 0; i < s.length(); i++ )
 1329  
         {
 1330  0
             addPrintable( retval, s.charAt( i ) );
 1331  
         }
 1332  0
         retval.append( "'" );
 1333  0
         return retval.toString();
 1334  
     }
 1335  
 
 1336  
     protected static final String printable( char ch )
 1337  
     {
 1338  0
         StringBuilder retval = new StringBuilder();
 1339  0
         addPrintable( retval, ch );
 1340  0
         return retval.toString();
 1341  
     }
 1342  
 
 1343  
     private static void addPrintable( StringBuilder retval, char ch )
 1344  
     {
 1345  0
         switch ( ch )
 1346  
         {
 1347  
             case '\b':
 1348  0
                 retval.append( "\\b" );
 1349  0
                 break;
 1350  
             case '\t':
 1351  0
                 retval.append( "\\t" );
 1352  0
                 break;
 1353  
             case '\n':
 1354  0
                 retval.append( "\\n" );
 1355  0
                 break;
 1356  
             case '\f':
 1357  0
                 retval.append( "\\f" );
 1358  0
                 break;
 1359  
             case '\r':
 1360  0
                 retval.append( "\\r" );
 1361  0
                 break;
 1362  
             case '\"':
 1363  0
                 retval.append( "\\\"" );
 1364  0
                 break;
 1365  
             case '\'':
 1366  0
                 retval.append( "\\\'" );
 1367  0
                 break;
 1368  
             case '\\':
 1369  0
                 retval.append( "\\\\" );
 1370  0
                 break;
 1371  
             default:
 1372  0
                 if ( ch < 0x20 || ch > 0x7e )
 1373  
                 {
 1374  0
                     final String ss = "0000" + Integer.toString( ch, 16 );
 1375  0
                     retval.append( "\\u" ).append( ss, ss.length() - 4, ss.length() );
 1376  0
                 }
 1377  
                 else
 1378  
                 {
 1379  0
                     retval.append( ch );
 1380  
                 }
 1381  
         }
 1382  0
     }
 1383  
 
 1384  
 }