Clover coverage report - Clover results for XOM 1.2d1
Coverage timestamp: Wed Feb 8 2006 08:31:33 EST
file stats: LOC: 930   Methods: 37
NCLOC: 603   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
TextWriter.java 100% 90.8% 100% 92.7%
coverage coverage
 1    /* Copyright 2002-2006 Elliotte Rusty Harold
 2   
 3    This library is free software; you can redistribute it and/or modify
 4    it under the terms of version 2.1 of the GNU Lesser General Public
 5    License as published by the Free Software Foundation.
 6   
 7    This library is distributed in the hope that it will be useful,
 8    but WITHOUT ANY WARRANTY; without even the implied warranty of
 9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 10    GNU Lesser General Public License for more details.
 11   
 12    You should have received a copy of the GNU Lesser General Public
 13    License along with this library; if not, write to the
 14    Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 15    Boston, MA 02111-1307 USA
 16   
 17    You can contact Elliotte Rusty Harold by sending e-mail to
 18    elharo@metalab.unc.edu. Please include the word "XOM" in the
 19    subject line. The XOM home page is located at http://www.xom.nu/
 20    */
 21   
 22    package nu.xom;
 23   
 24    import java.io.IOException;
 25    import java.io.Writer;
 26   
 27    /**
 28    * <p>
 29    * This class is responsible for writing strings with the
 30    * necessary escaping for their context.
 31    * </p>
 32    *
 33    * @author Elliotte Rusty Harold
 34    * @version 1.2d1
 35    *
 36    */
 37    abstract class TextWriter {
 38   
 39    protected final Writer out;
 40    protected final String encoding;
 41   
 42    private String lineSeparator = "\r\n";
 43    // true if the user has requested a specific
 44    // line separator
 45    boolean lineSeparatorSet = false;
 46    private boolean inDocType = false;
 47    private int maxLength = 0;
 48    private int indent = 0;
 49    private String indentString = "";
 50    protected int column = 0;
 51    // Is an xml:space="preserve" attribute in scope?
 52    private boolean preserveSpace = false;
 53    protected boolean normalize = false;
 54   
 55  19228 protected TextWriter(Writer out, String encoding) {
 56  19228 this.out = out;
 57  19228 this.encoding = encoding;
 58    }
 59   
 60   
 61  17949 void reset() {
 62  17949 column = 0;
 63  17949 fakeIndents = 0;
 64  17949 lastCharacterWasSpace = false;
 65  17949 skipFollowingLinefeed = false;
 66    }
 67   
 68   
 69    protected boolean lastCharacterWasSpace = false;
 70   
 71    /**
 72    * Indicates whether a linefeed is just half of a \r\n pair
 73    * used for a line break.
 74    */
 75    protected boolean skipFollowingLinefeed = false;
 76   
 77    // Needed for memory between calls.
 78    private char highSurrogate;
 79   
 80   
 81  1363919 private boolean isHighSurrogate(int c) {
 82  1363919 return c >= 0xD800 && c <= 0xDBFF;
 83    }
 84   
 85   
 86  1357770 private boolean isLowSurrogate(int c) {
 87  1357770 return c >= 0xDC00 && c <= 0xDFFF;
 88    }
 89   
 90   
 91  2315474 final void writePCDATA(char c) throws IOException {
 92   
 93  2315474 switch(c) {
 94  30 case '\r':
 95  30 if (!adjustingWhiteSpace() && !lineSeparatorSet) {
 96  13 out.write("&#x0D;");
 97  13 column += 6;
 98  13 justBroke=false;
 99    }
 100    else {
 101  17 breakLine();
 102  17 lastCharacterWasSpace = true;
 103    }
 104  30 skipFollowingLinefeed = true;
 105  30 break;
 106  0 case 14: // unreachable
 107  0 case 15: // unreachable
 108  0 case 16: // unreachable
 109  0 case 17: // unreachable
 110  0 case 18: // unreachable
 111  0 case 19: // unreachable
 112  0 case 20: // unreachable
 113  0 case 21: // unreachable
 114  0 case 22: // unreachable
 115  0 case 23: // unreachable
 116  0 case 24: // unreachable
 117  0 case 25: // unreachable
 118  0 case 26: // unreachable
 119  0 case 27: // unreachable
 120  0 case 28: // unreachable
 121  0 case 29: // unreachable
 122  0 case 30: // unreachable
 123  0 case 31: // unreachable
 124  0 throw new XMLException("Bad character snuck into document");
 125  81240 case ' ':
 126  81240 write(c);
 127  81240 break;
 128  301 case '!':
 129  301 write(c);
 130  301 break;
 131  904 case '"':
 132  904 write(c);
 133  904 break;
 134  3761 case '#':
 135  3761 write(c);
 136  3761 break;
 137  24 case '$':
 138  24 write(c);
 139  24 break;
 140  154 case '%':
 141  154 write(c);
 142  154 break;
 143  304 case '&':
 144  304 out.write("&amp;");
 145  304 column += 5;
 146  304 lastCharacterWasSpace = false;
 147  304 skipFollowingLinefeed = false;
 148  304 justBroke = false;
 149  304 break;
 150  2325 case '\'':
 151  2325 write(c);
 152  2325 break;
 153  1337 case '(':
 154  1337 write(c);
 155  1337 break;
 156  1721 case ')':
 157  1721 write(c);
 158  1721 break;
 159  318 case '*':
 160  318 write(c);
 161  318 break;
 162  96 case '+':
 163  96 write(c);
 164  96 break;
 165  4985 case ',':
 166  4985 write(c);
 167  4985 break;
 168  4644 case '-':
 169  4644 write(c);
 170  4644 break;
 171  1788 case '.':
 172  1788 write(c);
 173  1788 break;
 174  608 case '/':
 175  608 write(c);
 176  608 break;
 177  4771 case '0':
 178  4771 write(c);
 179  4771 break;
 180  2752 case '1':
 181  2752 write(c);
 182  2752 break;
 183  1592 case '2':
 184  1592 write(c);
 185  1592 break;
 186  1352 case '3':
 187  1352 write(c);
 188  1352 break;
 189  968 case '4':
 190  968 write(c);
 191  968 break;
 192  793 case '5':
 193  793 write(c);
 194  793 break;
 195  1347 case '6':
 196  1347 write(c);
 197  1347 break;
 198  824 case '7':
 199  824 write(c);
 200  824 break;
 201  1270 case '8':
 202  1270 write(c);
 203  1270 break;
 204  2561 case '9':
 205  2561 write(c);
 206  2561 break;
 207  1021 case ':':
 208  1021 write(c);
 209  1021 break;
 210  293 case ';':
 211  293 write(c);
 212  293 break;
 213  554 case '<':
 214  554 out.write("&lt;");
 215  554 column += 4;
 216  554 lastCharacterWasSpace = false;
 217  554 skipFollowingLinefeed = false;
 218  554 justBroke = false;
 219  554 break;
 220  96 case '=':
 221  96 write(c);
 222  96 break;
 223  507 case '>':
 224  507 out.write("&gt;");
 225  507 column += 4;
 226  507 lastCharacterWasSpace = false;
 227  507 skipFollowingLinefeed = false;
 228  507 justBroke = false;
 229  507 break;
 230  2190233 default:
 231  1363916 if (needsEscaping(c)) writeEscapedChar(c);
 232  826317 else write(c);
 233    }
 234   
 235    }
 236   
 237   
 238  1363919 private void writeEscapedChar(char c) throws IOException {
 239   
 240  1363919 if (isHighSurrogate(c)) {
 241    //store and wait for low half
 242  6149 highSurrogate = c;
 243    }
 244  1357770 else if (isLowSurrogate(c)) {
 245    // decode and write entity reference
 246    // I am assuming here that nothing allows the
 247    // text to be created with a malformed surrogate
 248    // pair such as a low surrogate that is not immediately
 249    // preceded by a high surrogate
 250  6149 int uchar = UnicodeUtil.combineSurrogatePair(highSurrogate, c);
 251  6149 String s = "&#x" + Integer.toHexString(uchar).toUpperCase() + ';';
 252  6149 out.write(s);
 253  6149 column += s.length();
 254  6149 lastCharacterWasSpace = false;
 255  6149 skipFollowingLinefeed = false;
 256  6149 justBroke = false;
 257    }
 258    else {
 259  1351621 String s = "&#x" + Integer.toHexString(c).toUpperCase() + ';';
 260  1351621 out.write(s);
 261  1351621 column += s.length();
 262  1351621 lastCharacterWasSpace = false;
 263  1351621 skipFollowingLinefeed = false;
 264  1351621 justBroke=false;
 265    }
 266   
 267    }
 268   
 269   
 270  76 private boolean adjustingWhiteSpace() {
 271  76 return maxLength > 0 || indent > 0;
 272    }
 273   
 274   
 275    // This is the same as writePCDATA except that it
 276    // also needs to escape " as &quot; and tab as "&#x09;".
 277    // I'm not escaping the single quote because Serializer
 278    // always uses double quotes to contain
 279    // values.
 280  7394634 final void writeAttributeValue(char c)
 281    throws IOException {
 282   
 283  7394634 switch(c) {
 284    // Handle white space that the parser might normalize
 285    // on roundtrip. We only escape them if the serializer
 286    // is not adjusting white space; that is indent is 0
 287    // and maxLength is 0.
 288  7 case '\t':
 289  7 if (!adjustingWhiteSpace()) {
 290  5 out.write("&#x09;");
 291  5 column += 6;
 292  5 lastCharacterWasSpace = true;
 293  5 skipFollowingLinefeed = false;
 294  5 justBroke=false;
 295    }
 296    else {
 297  2 write(' ');
 298    }
 299  7 break;
 300  21 case '\n':
 301  21 if (skipFollowingLinefeed) {
 302  7 skipFollowingLinefeed = false;
 303  7 return;
 304    }
 305  14 else if (adjustingWhiteSpace()) {
 306  1 out.write(" ");
 307  1 lastCharacterWasSpace = true;
 308  1 justBroke=false;
 309    }
 310    else {
 311  13 if (lineSeparatorSet) {
 312  4 escapeBreakLine();
 313    }
 314    else {
 315  9 out.write("&#x0A;");
 316  9 column += 6;
 317  9 justBroke=false;
 318    }
 319  13 lastCharacterWasSpace = true;
 320    }
 321  14 break;
 322  0 case 11:
 323    // unreachable
 324  0 case 12:
 325    // unreachable
 326  0 throw new XMLException("Bad character snuck into document");
 327  25 case '\r':
 328  25 if (adjustingWhiteSpace()) {
 329  2 out.write(" ");
 330  2 lastCharacterWasSpace = true;
 331  2 skipFollowingLinefeed = true;
 332  2 justBroke=false;
 333    }
 334    else {
 335  23 if (lineSeparatorSet) {
 336  14 escapeBreakLine();
 337  14 skipFollowingLinefeed = true;
 338    }
 339    else {
 340  9 out.write("&#x0D;");
 341  9 column += 6;
 342  9 justBroke=false;
 343    }
 344    }
 345  25 break;
 346  0 case 14:
 347    // unreachable
 348  0 case 15:
 349    // unreachable
 350  0 case 16:
 351    // unreachable
 352  0 case 17:
 353    // unreachable
 354  0 case 18:
 355    // unreachable
 356  0 case 19:
 357    // unreachable
 358  0 case 20:
 359    // unreachable
 360  0 case 21:
 361    // unreachable
 362  0 case 22:
 363    // unreachable
 364  0 case 23:
 365    // unreachable
 366  0 case 24:
 367    // unreachable
 368  0 case 25:
 369    // unreachable
 370  0 case 26:
 371    // unreachable
 372  0 case 27:
 373    // unreachable
 374  0 case 28:
 375    // unreachable
 376  0 case 29:
 377    // unreachable
 378  0 case 30:
 379    // unreachable
 380  0 case 31:
 381    // unreachable
 382  0 throw new XMLException("Bad character snuck into document");
 383  847 case ' ':
 384  847 write(c);
 385  847 break;
 386  8 case '!':
 387  8 write(c);
 388  8 break;
 389  16 case '"':
 390  16 out.write("&quot;");
 391  16 column += 6;
 392  16 lastCharacterWasSpace = false;
 393  16 skipFollowingLinefeed = false;
 394  16 justBroke=false;
 395  16 break;
 396  3 case '#':
 397  3 write(c);
 398  3 break;
 399  1 case '$':
 400  1 write(c);
 401  1 break;
 402  1 case '%':
 403  1 write(c);
 404  1 break;
 405  11 case '&':
 406  11 out.write("&amp;");
 407  11 column += 5;
 408  11 lastCharacterWasSpace = false;
 409  11 skipFollowingLinefeed = false;
 410  11 justBroke = false;
 411  11 break;
 412  4 case '\'':
 413  4 write(c);
 414  4 break;
 415  1 case '(':
 416  1 write(c);
 417  1 break;
 418  1 case ')':
 419  1 write(c);
 420  1 break;
 421  1 case '*':
 422  1 write(c);
 423  1 break;
 424  1 case '+':
 425  1 write(c);
 426  1 break;
 427  1 case ',':
 428  1 write(c);
 429  1 break;
 430  51 case '-':
 431  51 write(c);
 432  51 break;
 433  17 case '.':
 434  17 write(c);
 435  17 break;
 436  27 case '/':
 437  27 write(c);
 438  27 break;
 439  602205 case '0':
 440  602205 write(c);
 441  602205 break;
 442  881903 case '1':
 443  881903 write(c);
 444  881903 break;
 445  869418 case '2':
 446  869418 write(c);
 447  869418 break;
 448  866189 case '3':
 449  866189 write(c);
 450  866189 break;
 451  867597 case '4':
 452  867597 write(c);
 453  867597 break;
 454  788838 case '5':
 455  788838 write(c);
 456  788838 break;
 457  710065 case '6':
 458  710065 write(c);
 459  710065 break;
 460  592969 case '7':
 461  592969 write(c);
 462  592969 break;
 463  601234 case '8':
 464  601234 write(c);
 465  601234 break;
 466  607176 case '9':
 467  607176 write(c);
 468  607176 break;
 469  5 case ':':
 470  5 write(c);
 471  5 break;
 472  6 case ';':
 473  6 write(c);
 474  6 break;
 475  11 case '<':
 476  11 out.write("&lt;");
 477  11 column += 4;
 478  11 lastCharacterWasSpace = false;
 479  11 skipFollowingLinefeed = false;
 480  11 justBroke = false;
 481  11 break;
 482  1 case '=':
 483  1 write(c);
 484  1 break;
 485  15 case '>':
 486  15 out.write("&gt;");
 487  15 column += 4;
 488  15 lastCharacterWasSpace = false;
 489  15 skipFollowingLinefeed = false;
 490  15 justBroke = false;
 491  15 break;
 492  5958 default:
 493  3 if (needsEscaping(c)) writeEscapedChar(c);
 494  5955 else write(c);
 495    }
 496   
 497    }
 498   
 499   
 500    // XXX We might be able to optimize this by using switch statements
 501    // in the methods that call this to separate out the special cases.
 502    // --\n, \t, space, etc.--and passing them to a different method
 503    // thus avoiding the if tests here. See if this method shows up as
 504    // a HotSpot in profiling.
 505  30627440 void write(char c) throws IOException {
 506   
 507    // Carriage returns are completely handled by
 508    // writePCDATA and writeAttributeValue. They never
 509    // enter this method.
 510  30627440 if ((c == ' ' || c == '\n' || c == '\t')) {
 511  2191534 if (needsBreak()) {
 512  30 breakLine();
 513  30 skipFollowingLinefeed = false;
 514    }
 515  2191504 else if (preserveSpace || (indent <= 0 && maxLength <= 0)) {
 516    // We're neither indenting nor wrapping
 517    // so we need to preserve white space
 518  2191315 if (c == ' ' || c == '\t') {
 519  2103710 out.write(c);
 520  2103710 skipFollowingLinefeed = false;
 521  2103710 column++;
 522  2103710 justBroke=false;
 523    }
 524    else { // (c == '\n')
 525  87605 if (!lineSeparatorSet ||
 526    !skipFollowingLinefeed) {
 527  87601 writeLineSeparator(c);
 528    }
 529  87605 skipFollowingLinefeed = false;
 530  87605 column = 0;
 531    }
 532    }
 533  189 else if (!lastCharacterWasSpace) {
 534  185 out.write(' ');
 535  185 column++;
 536  185 skipFollowingLinefeed = false;
 537  185 justBroke=false;
 538    }
 539  2191534 lastCharacterWasSpace = true;
 540    }
 541    else {
 542  28435906 out.write(c);
 543    // don't increment column for high surrogate, only low surrogate
 544  28435891 if (c < 0xd800 || c > 0xDBFF) column++;
 545  28435906 lastCharacterWasSpace = false;
 546  28435906 skipFollowingLinefeed = false;
 547  28435906 justBroke=false;
 548    }
 549   
 550    }
 551   
 552   
 553  87601 private void writeLineSeparator(char c)
 554    throws IOException {
 555   
 556  28444 if (!inDocType && (!lineSeparatorSet || preserveSpace)) out.write(c);
 557  59157 else if (lineSeparator.equals("\r\n")) {
 558  2260 out.write("\r\n");
 559    }
 560  56897 else if (lineSeparator.equals("\n")) {
 561  56894 out.write('\n');
 562    }
 563    else { // lineSeparator.equals("\r"))
 564  3 out.write('\r');
 565    }
 566    // Remember, there are only three possible line separators
 567   
 568    }
 569   
 570   
 571  2191534 private boolean needsBreak() {
 572   
 573  2191378 if (maxLength <= 0 || preserveSpace) return false;
 574    // Better algorithm needed: Should look ahead in the
 575    // stream, see if there's a white space character
 576    // between here and the maxLength, Then again, simple is good.
 577    // Here we just assume there's probably space somewhere
 578    // within the next ten characters
 579   
 580  156 return column >= maxLength - 10;
 581   
 582    }
 583   
 584   
 585    protected boolean justBroke = false;
 586   
 587  24 boolean justBroke() {
 588  24 return justBroke;
 589    }
 590   
 591   
 592  37893 final void breakLine() throws IOException {
 593   
 594  37893 out.write(lineSeparator);
 595  37893 out.write(indentString);
 596  37893 column = indentString.length();
 597  37893 lastCharacterWasSpace = true;
 598  37893 justBroke = true;
 599   
 600    }
 601   
 602   
 603  18 private final void escapeBreakLine() throws IOException {
 604   
 605  18 if ("\n".equals(lineSeparator)) {
 606  6 out.write("&#x0A;");
 607  6 column += 6;
 608    }
 609  12 else if ("\r\n".equals(lineSeparator)) {
 610  6 out.write("&#x0D;&#x0A;");
 611  6 column += 12;
 612    }
 613    else {
 614  6 out.write("&#x0D;");
 615  6 column += 6;
 616    }
 617  18 lastCharacterWasSpace = true;
 618   
 619    }
 620   
 621   
 622    // Note that when this method is called directly, then
 623    // normalization is not performed on c. Currently this is
 624    // only called for ASCII characters like <, >, and the space,
 625    // which should be OK
 626  5890804 final void writeMarkup(char c) throws IOException {
 627   
 628  5890804 if (needsEscaping(c)) {
 629  2 throw new UnavailableCharacterException(c, encoding);
 630    }
 631  5890802 write(c);
 632   
 633    }
 634   
 635   
 636    // XXX should we have a special package protected
 637    // method to be used only for ASCII characters we know don't need escaping or
 638    // normalization such as <, /, A-Z, etc.?
 639   
 640   
 641  1529063 void writePCDATA(String s) throws IOException {
 642   
 643  1529063 s = normalize(s);
 644  1529063 int length = s.length();
 645  1529063 for (int i=0; i < length; i++) {
 646  1535232 writePCDATA(s.charAt(i));
 647    }
 648   
 649    }
 650   
 651   
 652  1529058 void writeAttributeValue(String s)
 653    throws IOException {
 654   
 655  1529058 s = normalize(s);
 656  1529058 int length = s.length();
 657  1529058 for (int i=0; i < length; i++) {
 658  7387412 writeAttributeValue(s.charAt(i));
 659    }
 660   
 661    }
 662   
 663   
 664  4587324 void writeMarkup(String s) throws IOException {
 665   
 666  4587324 s = normalize(s);
 667  4587324 int length = s.length();
 668  4587324 for (int i=0; i < length; i++) {
 669  4588286 writeMarkup(s.charAt(i));
 670    }
 671   
 672    }
 673   
 674   
 675    // This is for ASCII characters like < and = we know are
 676    // available in all encodings and do not need to be normalized
 677  37453 void writeUncheckedMarkup(String s) throws IOException {
 678   
 679  37453 int length = s.length();
 680  37453 for (int i=0; i < length; i++) {
 681  601226 write(s.charAt(i));
 682    }
 683   
 684    }
 685   
 686   
 687  8056485 protected String normalize(String s) {
 688   
 689  8056485 if (normalize) {
 690  411084 return UnicodeUtil.normalize(s);
 691    }
 692  7645401 return s;
 693   
 694    }
 695   
 696   
 697   
 698  1691822 boolean isIndenting() {
 699  1691822 return indentString.length() > 0;
 700    }
 701   
 702   
 703    private int fakeIndents = 0;
 704   
 705    private final static String _128_SPACES=" ";
 706    private final static int _128 = 128;
 707   
 708  1687772 void incrementIndent() {
 709   
 710  1687729 if (indent == 0) return;
 711   
 712  43 String newIndent;
 713  43 int length = indentString.length() + indent;
 714  43 if (indentString.length() + indent < _128) {
 715  39 newIndent = _128_SPACES.substring(0, length);
 716    }
 717    else {
 718  4 StringBuffer sb = new StringBuffer(length);
 719  4 sb.append(_128_SPACES);
 720  4 for (int i = _128; i < length; i++) {
 721  888 sb.append(' ');
 722    }
 723  4 newIndent = sb.toString();
 724    }
 725   
 726    // limit maximum indent to half of maximum line length
 727  43 if (maxLength > 0 && newIndent.length() > maxLength / 2) {
 728  2 fakeIndents++;
 729    }
 730  41 else this.indentString = newIndent;
 731   
 732    }
 733   
 734   
 735  1687772 void decrementIndent() {
 736   
 737  1687729 if (indent == 0) return;
 738  2 else if (fakeIndents > 0) fakeIndents--;
 739    else {
 740  41 indentString = indentString.substring(
 741    0, indentString.length()-indent
 742    );
 743    }
 744   
 745    }
 746   
 747   
 748  17985 String getEncoding() {
 749  17985 return this.encoding;
 750    }
 751   
 752   
 753    /**
 754    * <p>
 755    * Returns the String used as a line separator.
 756    * This is always "\n", "\r", or "\r\n".
 757    * </p>
 758    *
 759    * @return the line separator
 760    */
 761  38 String getLineSeparator() {
 762  38 return lineSeparator;
 763    }
 764   
 765   
 766    /**
 767    * <p>
 768    * Sets the lineSeparator. This
 769    * can only be one of the three
 770    * strings "\n", "\r", or "\r\n".
 771    * All other values are forbidden.
 772    * </p>
 773    *
 774    * @param lineSeparator the lineSeparator to set
 775    *
 776    * @throws IllegalArgumentException if you attempt to use
 777    * any line separator other than "\n", "\r", or "\r\n".
 778    *
 779    */
 780  2548 void setLineSeparator(String lineSeparator) {
 781   
 782  2548 if (lineSeparator.equals("\n")
 783    || lineSeparator.equals("\r")
 784    || lineSeparator.equals("\r\n")) {
 785  2542 this.lineSeparator = lineSeparator;
 786  2542 this.lineSeparatorSet = true;
 787    }
 788    else {
 789  6 throw new IllegalArgumentException(
 790    "Illegal Line Separator");
 791    }
 792   
 793    }
 794   
 795   
 796  885 void setInDocType(boolean inDocType) {
 797  885 this.inDocType = inDocType;
 798    }
 799   
 800   
 801    /**
 802    * <p>
 803    * Returns the number of spaces this serializer indents.
 804    * </p>
 805    *
 806    * @return the number of spaces this serializer indents
 807    */
 808  3386172 int getIndent() {
 809  3386172 return indent;
 810    }
 811   
 812   
 813    /**
 814    * <p>
 815    * Returns the maximum line length.
 816    * </p>
 817    *
 818    * @return the maximum line length.
 819    */
 820  40 int getMaxLength() {
 821  40 return maxLength;
 822    }
 823   
 824    /**
 825    * <p>
 826    * Sets the suggested maximum line length for this serializer.
 827    * In some circumstances this may not be respected.
 828    * </p>
 829    *
 830    * @param maxLength the maxLength to set
 831    */
 832  52 void setMaxLength(int maxLength) {
 833  1 if (maxLength < 0) maxLength = 0;
 834  52 this.maxLength = maxLength;
 835    }
 836   
 837   
 838    /**
 839    * <p>
 840    * Sets the number of spaces to indent each successive level in the
 841    * hierarchy. Use 0 for no extra indenting.
 842    * </p>
 843    *
 844    * @param indent the indent to set
 845    */
 846  67 void setIndent(int indent) {
 847  67 this.indent = indent;
 848    }
 849   
 850   
 851  37703 void flush() throws IOException {
 852  37703 out.flush();
 853    }
 854   
 855   
 856    abstract boolean needsEscaping(char c);
 857   
 858   
 859    /**
 860    * <p>
 861    * Used to track the current status of xml:space.
 862    * This is false by default, unless an xml:space="preserve"
 863    * attribute is in-scope. When such an attribute is in-scope,
 864    * white space is not adjusted even if indenting and/or
 865    * a maximum line length has been requested.
 866    * </p>
 867    *
 868    *
 869    * @return true if an <code>xml:space="true"</code> attribute
 870    * is in-scope
 871    */
 872  1687838 boolean isPreserveSpace() {
 873  1687838 return preserveSpace;
 874    }
 875   
 876   
 877    /**
 878    * @param preserveSpace whether to preserve all white space
 879    */
 880  1687969 void setPreserveSpace(boolean preserveSpace) {
 881  1687969 this.preserveSpace = preserveSpace;
 882    }
 883   
 884   
 885    /**
 886    * @return the current column number
 887    */
 888  4 int getColumnNumber() {
 889  4 return this.column;
 890    }
 891   
 892   
 893    /**
 894    * <p>
 895    * If true, this property indicates serialization will
 896    * perform Unicode normalization on all data using normalization
 897    * form C (NFC). Performing Unicode normalization
 898    * does change the document's infoset.
 899    * The default is false; do not normalize.
 900    * </p>
 901    *
 902    * <p>
 903    * This feature has not yet been benchmarked or optimized.
 904    * It may result in substantially slower code.
 905    * </p>
 906    *
 907    * @param normalize true if normalization is performed;
 908    * false if it isn't.
 909    */
 910  17190 void setNFC(boolean normalize) {
 911  17190 this.normalize = normalize;
 912    }
 913   
 914   
 915    /**
 916    * <p>
 917    * If true, this property indicates serialization will
 918    * perform Unicode normalization on all data using normalization
 919    * form C (NFC). The default is false; do not normalize.
 920    * </p>
 921    *
 922    * @return true if this serialization performs Unicode
 923    * normalization; false if it doesn't.
 924    */
 925  3370050 boolean getNFC() {
 926  3370050 return this.normalize;
 927    }
 928   
 929   
 930    }