KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > znerd > xmlenc > XMLEncoder


1 /*
2  * $Id: XMLEncoder.java,v 1.208 2004/12/23 14:09:14 znerd Exp $
3  */

4 package org.znerd.xmlenc;
5
6 import java.io.IOException JavaDoc;
7 import java.io.UnsupportedEncodingException JavaDoc;
8 import java.io.Writer JavaDoc;
9
10 /**
11  * Encodes character streams for an XML document.
12  *
13  * <p>The following encodings are supported:
14  *
15  * <ul>
16  * <li><code>UTF-8</code>
17  * <li><code>UTF-16</code>
18  * <li><code>US-ASCII</code>, with alias <code>ASCII</code>
19  * <li>all <code>ISO-8859</code> encodings
20  * </ul>
21  *
22  * @version $Revision: 1.208 $ $Date: 2004/12/23 14:09:14 $
23  * @author Ernst de Haan (<a HREF="mailto:ernst.dehaan@nl.wanadoo.com">ernst.dehaan@nl.wanadoo.com</a>)
24  * @author Jochen Schwoerer (j.schwoerer [at] web.de)
25  * @author Anthony Goubard (<a HREF="mailto:anthony.goubard@nl.wanadoo.com">anthony.goubard@nl.wanadoo.com</a>)
26  *
27  * @since xmlenc 0.1
28  */

29 public class XMLEncoder extends Object JavaDoc {
30
31    // For this encoder, different Unicode characters are treated differently.
32
//
33
// Within attribute values, the following applies:
34
//
35
// ID Dec Description Escaping
36
// __ ______ __________________ _________________________
37
//
38
// A 0-8 Control characters -- Not allowed in XML 1.0 --
39
// B 9-10 Normal characters Never needed
40
// C 11-12 Control characters -- Not allowed in XML 1.0 --
41
// D 13 Normal character Never needed
42
// E 14-31 Control characters -- Not allowed in XML 1.0 --
43
// F 32-33 Normal characters Never needed
44
// G 34 Quote (") If quotation mark
45
// H 35-37 Normal characters Never needed
46
// I 38 Ampersand (&) If escapeAmpersands=true
47
// J 39 Apostrophe (') If quotation mark
48
// K 40-59 Normal characters Never needed
49
// L 60 Less than (<) Always
50
// M 61 Normal character Never needed
51
// N 62 Greater than (>) Always
52
// O 63-127 Normal characters Never needed
53
// P 128+ Normal characters If encoding is ASCII
54
//
55
// Outside attribute values, the following applies:
56
//
57
// ID Dec Description Escaping
58
// __ ______ __________________ _________________________
59
//
60
// A 0-8 Control characters -- Not allowed in XML 1.0 --
61
// B 9-10 Normal characters Never needed
62
// C 11-12 Control characters -- Not allowed in XML 1.0 --
63
// D 13 Normal character Never needed
64
// E 14-31 Control characters -- Not allowed in XML 1.0 --
65
// FGH 32-37 Normal characters Never needed
66
// I 38 Ampersand (&) If escapeAmpersands=true
67
// JK 39-59 Normal characters Never needed
68
// L 60 Less than (<) Always
69
// M 61 Normal character Never needed
70
// N 62 Greater than (>) Always
71
// O 63-127 Normal characters Never needed
72
// P 128+ Normal characters If encoding is ASCII
73
//
74
// The following characters are expected to be encountered the most often:
75
//
76
// 32 Space Part of range F
77
// 10 Linefeed Part of range B
78
// 13 Carriage return Range D
79
// 48-57 Digits 0-9 Part of range K
80
// 65-90 Uppercase letters A-Z Part of range O
81
// 97-122 Lowercase letters a-z Part of range O
82
//
83
// After that, the following characters are expected to be encountered the
84
// most often:
85
//
86
// 9 Tab Part of range B
87
// 33 Exclamation mark Part of range F
88
// 34 Quote Range G
89
// 35-37 Hash, dollar, percent Range H
90
// 38 Ampersand Range I
91
// 39 Apostrophe Range J
92
// 40-47 Punctuation, etc. Part of range K
93
// 58-59 Punctuation, etc. Part of range K
94
// 60 Less-than Range L
95
// 61 Equals Range M
96
// 62 Greater-than Range N
97
// 63-64 Question, at-sign Part of range O
98
// 91-96 Punctuation, etc. Part of range O
99
// 123-127 Punctuation Part of range O
100
//
101
// And the following characters are expected to be encountered the least:
102
//
103
// 128+ High characters Range P
104
//
105
//
106
// See:
107
// http://www.w3.org/TR/REC-xml
108
// http://www.jimprice.com/ascii-0-127.gif
109

110
111    //-------------------------------------------------------------------------
112
// Class functions
113
//-------------------------------------------------------------------------
114

115    /**
116     * Retrieves an <code>XMLEncoder</code> for the specified encoding. If no
117     * suitable instance can be returned, then an exception is thrown.
118     *
119     * @param encoding
120     * the name of the encoding, not <code>null</code>.
121     *
122     * @return
123     * an <code>XMLEncoder</code> instance that matches the specified
124     * encoding, never <code>null</code>.
125     *
126     * @throws IllegalArgumentException
127     * if <code>encoding == null</code>.
128     *
129     * @throws UnsupportedEncodingException
130     * if the specified encoding is not supported.
131     */

132    public static final XMLEncoder getEncoder(String JavaDoc encoding)
133    throws IllegalArgumentException JavaDoc, UnsupportedEncodingException JavaDoc {
134       return new XMLEncoder(encoding);
135    }
136
137
138    //-------------------------------------------------------------------------
139
// Class fields
140
//-------------------------------------------------------------------------
141

142    /**
143     * The first part of a declaration, before the encoding.
144     */

145    private static final char[] DECLARATION_START = "<?xml version=\"1.0\" encoding=\"".toCharArray();
146
147    /**
148     * The length of <code>DECLARATION_START</code>.
149     */

150    private static final int DECLARATION_START_LENGTH = DECLARATION_START.length;
151
152    /**
153     * The last part of a declaration, after the encoding.
154     */

155    private static final char[] DECLARATION_END = "\"?>".toCharArray();
156
157    /**
158     * The length of <code>DECLARATION_END</code>.
159     */

160    private static final int DECLARATION_END_LENGTH = DECLARATION_END.length;
161
162    /**
163     * Character array representing the string <code>"&gt;"</code>.
164     */

165    private static final char[] ESC_GREATER_THAN = new char[] { '&', 'g', 't', ';' };
166
167    /**
168     * Character array representing the string <code>"&lt;"</code>.
169     */

170    private static final char[] ESC_LESS_THAN = new char[] { '&', 'l', 't', ';' };
171
172    /**
173     * Character array representing the string <code>"&amp;amp;"</code>.
174     */

175    private static final char[] ESC_AMPERSAND = new char[] { '&', 'a', 'm', 'p', ';' };
176
177    /**
178     * Character array representing the string <code>"&amp;apos;"</code>.
179     */

180    private static final char[] ESC_APOSTROPHE = new char[] { '&', 'a', 'p', 'o', 's', ';' };
181
182    /**
183     * Character array representing the string <code>"&amp;apos;"</code>.
184     */

185    private static final char[] ESC_QUOTE = new char[] { '&', 'q', 'u', 'o', 't', ';' };
186
187    /**
188     * Character array representing the string <code>"&amp;#"</code>.
189     */

190    private static final char[] AMPERSAND_HASH = new char[] { '&', '#' };
191
192    /**
193     * Character array representing the string <code>"='"</code>.
194     */

195    private static final char[] EQUALS_APOSTROPHE = new char[] { '=', '\'' };
196
197    /**
198     * Character array representing the string <code>"=\""</code>.
199     */

200    private static final char[] EQUALS_QUOTE = new char[] { '=', '"' };
201
202
203    //-------------------------------------------------------------------------
204
// Constructor
205
//-------------------------------------------------------------------------
206

207    /**
208     * Constructs a new <code>XMLEncoder</code> instance.
209     *
210     * @param encoding
211     * the name of the encoding, not <code>null</code>.
212     *
213     * @throws IllegalArgumentException
214     * if <code>encoding == null</code>.
215     *
216     * @throws UnsupportedEncodingException
217     * if the specified encoding is not supported.
218     *
219     * @deprecated
220     * Deprecated since xmlenc 0.47.
221     * Use the factory method {@link #getEncoder(String)} instead.
222     */

223    public XMLEncoder(String JavaDoc encoding)
224    throws IllegalArgumentException JavaDoc, UnsupportedEncodingException JavaDoc {
225
226       // Check argument
227
if (encoding == null) {
228          throw new IllegalArgumentException JavaDoc("encoding == null");
229       }
230
231       // Uppercase encoding to compare it with supported encodings in a
232
// case-insensitive manner
233
String JavaDoc ucEncoding = encoding.toUpperCase();
234
235       // Check if the encoding supports all Unicode characters
236
if (ucEncoding.equals("UTF-8") || ucEncoding.equals("UTF-16")) {
237          _sevenBitEncoding = false;
238
239       // Check if this is an ISO 646-based character set (7-bit ASCII)
240
} else if (ucEncoding.equals("US-ASCII")
241               || ucEncoding.equals("ASCII")
242               || ucEncoding.startsWith("ISO-8859-")) {
243          _sevenBitEncoding = true;
244
245       // Otherwise fail
246
} else {
247          throw new UnsupportedEncodingException JavaDoc(encoding);
248       }
249
250       // Store encoding literally as passed
251
_encoding = encoding;
252       _encodingCharArray = encoding.toCharArray();
253    }
254
255
256    //-------------------------------------------------------------------------
257
// Fields
258
//-------------------------------------------------------------------------
259

260    /**
261     * The name of the encoding. Cannot be <code>null</code>.
262     */

263    private final String JavaDoc _encoding;
264
265    /**
266     * The name of the encoding as a character array. Cannot be
267     * <code>null</code>.
268     */

269    private final char[] _encodingCharArray;
270
271    /**
272     * Flag that indicates whether the encoding is based on the ISO 646
273     * character set. The value is <code>true</code> if the encoding is a 7 bit
274     * encoding, or <code>false</code> if the encoding supports all Unicode
275     * characters.
276     */

277    private final boolean _sevenBitEncoding;
278
279
280    //-------------------------------------------------------------------------
281
// Methods
282
//-------------------------------------------------------------------------
283

284    /**
285     * Returns the encoding.
286     *
287     * @return
288     * the encoding passed to the constructor, never <code>null</code>.
289     */

290    public String JavaDoc getEncoding() {
291       return _encoding;
292    }
293
294    /**
295     * Writes an XML declaration.
296     *
297     * @param out
298     * the character stream to write to, not <code>null</code>.
299     *
300     * @throws NullPointerException
301     * if <code>out == null</code>.
302     *
303     * @throws IOException
304     * if an I/O error occurs.
305     */

306    public void declaration(Writer JavaDoc out)
307    throws NullPointerException JavaDoc, IOException JavaDoc {
308       out.write(DECLARATION_START, 0, DECLARATION_START_LENGTH);
309       out.write(_encodingCharArray);
310       out.write(DECLARATION_END, 0, DECLARATION_END_LENGTH);
311    }
312
313    /**
314     * Writes the specified text. Any characters that are non-printable in this
315     * encoding will be escaped.
316     *
317     * <p />It must be specified whether ampersands should be escaped. Unless
318     * ampersands are escaped, entity references can be written.
319     *
320     * @param out
321     * the character stream to write to, not <code>null</code>.
322     *
323     * @param text
324     * the text to be written, not <code>null</code>.
325     *
326     * @param escapeAmpersands
327     * flag that indicates whether ampersands should be escaped.
328     *
329     * @throws NullPointerException
330     * if <code>out == null || text == null</code>.
331     *
332     * @throws InvalidXMLException
333     * if the specified text contains an invalid character.
334     *
335     * @throws IOException
336     * if an I/O error occurs.
337     */

338    public void text(Writer JavaDoc out, String JavaDoc text, boolean escapeAmpersands)
339    throws NullPointerException JavaDoc, InvalidXMLException, IOException JavaDoc {
340
341       text(out,
342            text.toCharArray(),
343            0,
344            text.length(),
345            escapeAmpersands);
346    }
347
348    /**
349     * Writes text from the specified character array. Any characters that are
350     * non-printable in this encoding will be escaped.
351     *
352     * <p />It must be specified whether ampersands should be escaped. Unless
353     * ampersands are escaped, entity references can be written.
354     *
355     * @param out
356     * the character stream to write to, not <code>null</code>.
357     *
358     * @param ch
359     * the character array from which to retrieve the text to be written,
360     * not <code>null</code>.
361     *
362     * @param start
363     * the start index into <code>ch</code>, must be &gt;= 0.
364     *
365     * @param length
366     * the number of characters to take from <code>ch</code>, starting at
367     * the <code>start</code> index.
368     *
369     * @param escapeAmpersands
370     * flag that indicates if ampersands should be escaped.
371     *
372     * @throws NullPointerException
373     * if <code>out == null || ch == null</code>.
374     *
375     * @throws IndexOutOfBoundsException
376     * if <code>start &lt; 0
377     * || start + length &gt; ch.length</code>; this may not be
378     * checked before the character stream is written to, so this may
379     * cause a <em>partial</em> failure.
380     *
381     * @throws InvalidXMLException
382     * if the specified text contains an invalid character.
383     *
384     * @throws IOException
385     * if an I/O error occurs.
386     */

387    public void text(Writer JavaDoc out,
388                     char[] ch,
389                     int start,
390                     int length,
391                     boolean escapeAmpersands)
392    throws NullPointerException JavaDoc,
393           IndexOutOfBoundsException JavaDoc,
394           InvalidXMLException,
395           IOException JavaDoc {
396
397       int end = start + length;
398
399       // The position after the last escaped character
400
int lastEscaped = start;
401
402       if (_sevenBitEncoding) {
403          for (int i = start; i < end; i++) {
404             int c = (int) ch[i];
405
406             if ((c >= 63 && c <= 127) || (c >= 39 && c <= 59) || (c >= 32 && c <= 37) || c == 10 || c == 13 || c == 61 || c == 9) {
407                continue;
408             } else if (c == 60) {
409                out.write(ch, lastEscaped, i - lastEscaped);
410                out.write(ESC_LESS_THAN, 0, 4);
411                lastEscaped = i + 1;
412             } else if (c == 62) {
413                out.write(ch, lastEscaped, i - lastEscaped);
414                out.write(ESC_GREATER_THAN, 0, 4);
415                lastEscaped = i + 1;
416             } else if (c == 38) {
417                if (escapeAmpersands) {
418                   out.write(ch, lastEscaped, i - lastEscaped);
419                   out.write(ESC_AMPERSAND, 0, 5);
420                   lastEscaped = i + 1;
421                }
422             } else if (c > 127) {
423                out.write(ch, lastEscaped, i - lastEscaped);
424                out.write(AMPERSAND_HASH, 0, 2);
425                out.write(Integer.toString(c));
426                out.write(';');
427                lastEscaped = i + 1;
428             } else {
429                throw new InvalidXMLException("The character 0x" + Integer.toHexString(c) + " is not valid.");
430             }
431          }
432
433       // All characters allowed in this encoding
434
} else {
435          for (int i = start; i < end; i++) {
436             int c = (int) ch[i];
437
438             if (c >= 63 || (c >= 39 && c <= 59) || (c >= 32 && c <= 37) || c == 10 || c == 13 || c == 61 || c == 9) {
439                continue;
440             } else if (c == 60) {
441                out.write(ch, lastEscaped, i - lastEscaped);
442                out.write(ESC_LESS_THAN, 0, 4);
443                lastEscaped = i + 1;
444             } else if (c == 62) {
445                out.write(ch, lastEscaped, i - lastEscaped);
446                out.write(ESC_GREATER_THAN, 0, 4);
447                lastEscaped = i + 1;
448             } else if (c == 38) {
449                if (escapeAmpersands) {
450                   out.write(ch, lastEscaped, i - lastEscaped);
451                   out.write(ESC_AMPERSAND, 0, 5);
452                   lastEscaped = i + 1;
453                }
454             } else {
455                throw new InvalidXMLException("The character 0x" + Integer.toHexString(c) + " is not valid.");
456             }
457          }
458       }
459       out.write(ch, lastEscaped, end - lastEscaped);
460    }
461
462    /**
463     * Writes the specified character. If the character is non-printable in
464     * this encoding, then it will be escaped.
465     *
466     * <p />It is safe for this method to assume that the specified character
467     * does not need to be escaped unless the encoding does not support the
468     * character.
469     *
470     * @param out
471     * the character stream to write to, not <code>null</code>.
472     *
473     * @param c
474     * the character to be written.
475     *
476     * @throws IOException
477     * if an I/O error occurs.
478     */

479    public void text(Writer JavaDoc out, char c) throws IOException JavaDoc {
480       if (_sevenBitEncoding && c > 127) {
481          out.write(AMPERSAND_HASH, 0, 2);
482          out.write(Integer.toString(c));
483          out.write(';');
484       } else {
485          out.write(c);
486       }
487    }
488
489    /**
490     * Writes the specified whitespace string.
491     *
492     * @param out
493     * the character stream to write to, not <code>null</code>.
494     *
495     * @param s
496     * the character string to be written, not <code>null</code>.
497     *
498     * @throws NullPointerException
499     * if <code>out == null || s == null</code>.
500     *
501     * @throws InvalidXMLException
502     * if the specified character string contains a character that is
503     * invalid as whitespace.
504     *
505     * @throws IOException
506     * if an I/O error occurs.
507     */

508    public void whitespace(Writer JavaDoc out, String JavaDoc s)
509    throws NullPointerException JavaDoc, InvalidXMLException, IOException JavaDoc {
510
511       char[] ch = s.toCharArray();
512       int length = ch.length;
513       whitespace(out, ch, 0, length);
514    }
515
516    /**
517     * Writes whitespace from the specified character array.
518     *
519     * @param out
520     * the character stream to write to, not <code>null</code>.
521     *
522     * @param ch
523     * the character array from which to retrieve the text to be written,
524     * not <code>null</code>.
525     *
526     * @param start
527     * the start index into <code>ch</code>, must be &gt;= 0.
528     *
529     * @param length
530     * the number of characters to take from <code>ch</code>, starting at
531     * the <code>start</code> index.
532     *
533     * @throws NullPointerException
534     * if <code>out == null || ch == null</code>.
535     *
536     * @throws IndexOutOfBoundsException
537     * if <code>start &lt; 0
538     * || start + length &gt; ch.length</code>; this may not be
539     * checked before the character stream is written to, so this may
540     * cause a <em>partial</em> failure.
541     *
542     * @throws InvalidXMLException
543     * if the specified character array contains a character that is invalid
544     * as whitespace.
545     *
546     * @throws IOException
547     * if an I/O error occurs.
548     */

549    public void whitespace(Writer JavaDoc out,
550                           char[] ch,
551                           int start,
552                           int length)
553    throws NullPointerException JavaDoc,
554           IndexOutOfBoundsException JavaDoc,
555           InvalidXMLException,
556           IOException JavaDoc {
557
558       // Check the string
559
XMLChecker.checkS(ch, start, length);
560
561       // Write the complete character string at once
562
out.write(ch, start, length);
563    }
564
565    /**
566     * Writes an attribute assignment.
567     *
568     * @param out
569     * the character stream to write to, not <code>null</code>.
570     *
571     * @param name
572     * the name of the attribute, not <code>null</code>.
573     *
574     * @param value
575     * the value of the attribute, not <code>null</code>.
576     *
577     * @param quotationMark
578     * the quotation mark, must be either the apostrophe (<code>'\''</code>)
579     * or the quote character (<code>'"'</code>).
580     *
581     * @throws NullPointerException
582     * if <code>out == null || value == null</code>.
583     *
584     * @throws IllegalArgumentException
585     * if <code>quotationMark != '\'' &amp;&amp; quotationMark != '"'</code>.
586     *
587     * @throws IOException
588     * if an I/O error occurs.
589     */

590    public void attribute(Writer JavaDoc out,
591                          String JavaDoc name,
592                          String JavaDoc value,
593                          char quotationMark,
594                          boolean escapeAmpersands)
595    throws NullPointerException JavaDoc, IOException JavaDoc {
596
597       char[] ch = value.toCharArray();
598       int length = ch.length;
599       int start = 0;
600       int end = start + length;
601
602       // TODO: Call overloaded attribute method that accepts char[]
603

604       // The position after the last escaped character
605
int lastEscaped = 0;
606
607       // Double quotes
608
if (quotationMark == '"') {
609
610          out.write(' ');
611          out.write(name);
612
613          out.write(EQUALS_QUOTE, 0, 2);
614
615          if (_sevenBitEncoding) {
616             for (int i = start; i < end; i++) {
617                int c = (int) ch[i];
618
619                if ((c >= 63 && c <= 127) || (c >= 39 && c <= 59) || (c >= 32 && c <= 37 && c != 34) || c == 10 || c == 13 || c == 61 || c == 9) {
620                   continue;
621                } else if (c == 60) {
622                   out.write(ch, lastEscaped, i - lastEscaped);
623                   out.write(ESC_LESS_THAN, 0, 4);
624                   lastEscaped = i + 1;
625                } else if (c == 62) {
626                   out.write(ch, lastEscaped, i - lastEscaped);
627                   out.write(ESC_GREATER_THAN, 0, 4);
628                   lastEscaped = i + 1;
629                } else if (c == 34) {
630                   out.write(ch, lastEscaped, i - lastEscaped);
631                   out.write(ESC_QUOTE, 0, 6);
632                   lastEscaped = i + 1;
633                } else if (c == 38) {
634                   if (escapeAmpersands) {
635                      out.write(ch, lastEscaped, i - lastEscaped);
636                      out.write(ESC_AMPERSAND, 0, 5);
637                      lastEscaped = i + 1;
638                   }
639                } else if (c > 127) {
640                   out.write(ch, lastEscaped, i - lastEscaped);
641                   out.write(AMPERSAND_HASH, 0, 2);
642                   out.write(Integer.toString(c));
643                   out.write(';');
644                   lastEscaped = i + 1;
645                } else {
646                   throw new InvalidXMLException("The character 0x" + Integer.toHexString(c) + " is not valid.");
647                }
648             }
649
650          // All characters allowed in this encoding
651
} else {
652             for (int i = start; i < end; i++) {
653                int c = (int) ch[i];
654
655                if (c >= 63 || (c >= 40 && c <= 59) || (c >= 32 && c <= 37) || c == 10 || c == 13 || c == 61 || c == 9) {
656                   continue;
657                } else if (c == 60) {
658                   out.write(ch, lastEscaped, i - lastEscaped);
659                   out.write(ESC_LESS_THAN, 0, 4);
660                   lastEscaped = i + 1;
661                } else if (c == 62) {
662                   out.write(ch, lastEscaped, i - lastEscaped);
663                   out.write(ESC_GREATER_THAN, 0, 4);
664                   lastEscaped = i + 1;
665                } else if (c == 39) {
666                   out.write(ch, lastEscaped, i - lastEscaped);
667                   out.write(ESC_APOSTROPHE, 0, 6);
668                   lastEscaped = i + 1;
669                } else if (c == 38) {
670                   if (escapeAmpersands) {
671                      out.write(ch, lastEscaped, i - lastEscaped);
672                      out.write(ESC_AMPERSAND, 0, 5);
673                      lastEscaped = i + 1;
674                   }
675                } else {
676                   throw new InvalidXMLException("The character 0x" + Integer.toHexString(c) + " is not valid.");
677                }
678             }
679          }
680
681          out.write(ch, lastEscaped, length - lastEscaped);
682          out.write(quotationMark);
683
684
685       // Single quotes (apostrophes)
686
} else if (quotationMark == '\'') {
687          out.write(' ');
688          out.write(name);
689
690          out.write(EQUALS_APOSTROPHE, 0, 2);
691
692          if (_sevenBitEncoding) {
693             for (int i = start; i < end; i++) {
694                int c = (int) ch[i];
695
696                if ((c >= 63 && c <= 127) || (c >= 40 && c <= 59) || (c >= 32 && c <= 37) || c == 10 || c == 13 || c == 61 || c == 9) {
697                   continue;
698                } else if (c == 60) {
699                   out.write(ch, lastEscaped, i - lastEscaped);
700                   out.write(ESC_LESS_THAN, 0, 4);
701                   lastEscaped = i + 1;
702                } else if (c == 62) {
703                   out.write(ch, lastEscaped, i - lastEscaped);
704                   out.write(ESC_GREATER_THAN, 0, 4);
705                   lastEscaped = i + 1;
706                } else if (c == 39) {
707                   out.write(ch, lastEscaped, i - lastEscaped);
708                   out.write(ESC_APOSTROPHE, 0, 6);
709                   lastEscaped = i + 1;
710                } else if (c == 38) {
711                   if (escapeAmpersands) {
712                      out.write(ch, lastEscaped, i - lastEscaped);
713                      out.write(ESC_AMPERSAND, 0, 5);
714                      lastEscaped = i + 1;
715                   }
716                } else if (c > 127) {
717                   out.write(ch, lastEscaped, i - lastEscaped);
718                   out.write(AMPERSAND_HASH, 0, 2);
719                   out.write(Integer.toString(c));
720                   out.write(';');
721                   lastEscaped = i + 1;
722                } else {
723                   throw new InvalidXMLException("The character 0x" + Integer.toHexString(c) + " is not valid.");
724                }
725             }
726
727          // All characters allowed in this encoding
728
} else {
729             for (int i = start; i < end; i++) {
730                int c = (int) ch[i];
731
732                if (c >= 63 || (c >= 40 && c <= 59) || (c >= 32 && c <= 37) || c == 10 || c == 13 || c == 61 || c == 9) {
733                   continue;
734                } else if (c == 60) {
735                   out.write(ch, lastEscaped, i - lastEscaped);
736                   out.write(ESC_LESS_THAN, 0, 4);
737                   lastEscaped = i + 1;
738                } else if (c == 62) {
739                   out.write(ch, lastEscaped, i - lastEscaped);
740                   out.write(ESC_GREATER_THAN, 0, 4);
741                   lastEscaped = i + 1;
742                } else if (c == 39) {
743                   out.write(ch, lastEscaped, i - lastEscaped);
744                   out.write(ESC_APOSTROPHE, 0, 6);
745                   lastEscaped = i + 1;
746                } else if (c == 38) {
747                   if (escapeAmpersands) {
748                      out.write(ch, lastEscaped, i - lastEscaped);
749                      out.write(ESC_AMPERSAND, 0, 5);
750                      lastEscaped = i + 1;
751                   }
752                } else {
753                   throw new InvalidXMLException("The character 0x" + Integer.toHexString(c) + " is not valid.");
754                }
755             }
756          }
757
758          out.write(ch, lastEscaped, length - lastEscaped);
759          out.write(quotationMark);
760
761       // Invalid quotation mark character
762
} else {
763          String JavaDoc error = "Character 0x"
764                       + Integer.toHexString((int) quotationMark)
765                       + " ('"
766                       + quotationMark
767                       + "') is not a valid quotation mark.";
768          throw new IllegalArgumentException JavaDoc(error);
769       }
770    }
771 }
772
Popular Tags