KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xerces > impl > XMLEntityScanner


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.xerces.impl;
18
19 import java.io.EOFException JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.util.Locale JavaDoc;
22
23 import org.apache.xerces.impl.io.UCSReader;
24 import org.apache.xerces.impl.msg.XMLMessageFormatter;
25 import org.apache.xerces.util.SymbolTable;
26 import org.apache.xerces.util.XMLChar;
27 import org.apache.xerces.util.XMLStringBuffer;
28 import org.apache.xerces.xni.QName;
29 import org.apache.xerces.xni.XMLLocator;
30 import org.apache.xerces.xni.XMLString;
31
32 /**
33  * Implements the entity scanner methods.
34  *
35  * @xerces.internal
36  *
37  * @author Andy Clark, IBM
38  * @author Neil Graham, IBM
39  * @version $Id: XMLEntityScanner.java,v 1.24 2004/10/25 16:09:07 mrglavas Exp $
40  */

41
42 public class XMLEntityScanner implements XMLLocator {
43
44     // constants
45
private static final boolean DEBUG_ENCODINGS = false;
46     private static final boolean DEBUG_BUFFER = false;
47
48     //
49
// Data
50
//
51

52     private XMLEntityManager fEntityManager = null;
53     protected XMLEntityManager.ScannedEntity fCurrentEntity = null;
54
55     protected SymbolTable fSymbolTable = null;
56
57     protected int fBufferSize = XMLEntityManager.DEFAULT_BUFFER_SIZE;
58
59     /**
60      * Error reporter. This property identifier is:
61      * http://apache.org/xml/properties/internal/error-reporter
62      */

63     protected XMLErrorReporter fErrorReporter;
64     //
65
// Constructors
66
//
67

68     /** Default constructor. */
69     public XMLEntityScanner() {
70     } // <init>()
71

72     //
73
// XMLEntityScanner methods
74
//
75

76     /**
77      * Returns the base system identifier of the currently scanned
78      * entity, or null if none is available.
79      */

80     public String JavaDoc getBaseSystemId() {
81         return (fCurrentEntity != null && fCurrentEntity.entityLocation != null) ? fCurrentEntity.entityLocation.getExpandedSystemId() : null;
82     } // getBaseSystemId():String
83

84     /**
85      * Sets the encoding of the scanner. This method is used by the
86      * scanners if the XMLDecl or TextDecl line contains an encoding
87      * pseudo-attribute.
88      * <p>
89      * <strong>Note:</strong> The underlying character reader on the
90      * current entity will be changed to accomodate the new encoding.
91      * However, the new encoding is ignored if the current reader was
92      * not constructed from an input stream (e.g. an external entity
93      * that is resolved directly to the appropriate java.io.Reader
94      * object).
95      *
96      * @param encoding The IANA encoding name of the new encoding.
97      *
98      * @throws IOException Thrown if the new encoding is not supported.
99      *
100      * @see org.apache.xerces.util.EncodingMap
101      */

102     public void setEncoding(String JavaDoc encoding) throws IOException JavaDoc {
103
104         if (DEBUG_ENCODINGS) {
105             System.out.println("$$$ setEncoding: "+encoding);
106         }
107
108         if (fCurrentEntity.stream != null) {
109             // if the encoding is the same, don't change the reader and
110
// re-use the original reader used by the OneCharReader
111
// NOTE: Besides saving an object, this overcomes deficiencies
112
// in the UTF-16 reader supplied with the standard Java
113
// distribution (up to and including 1.3). The UTF-16
114
// decoder buffers 8K blocks even when only asked to read
115
// a single char! -Ac
116
if (fCurrentEntity.encoding == null ||
117                 !fCurrentEntity.encoding.equals(encoding)) {
118                 // UTF-16 is a bit of a special case. If the encoding is UTF-16,
119
// and we know the endian-ness, we shouldn't change readers.
120
// If it's ISO-10646-UCS-(2|4), then we'll have to deduce
121
// the endian-ness from the encoding we presently have.
122
if(fCurrentEntity.encoding != null && fCurrentEntity.encoding.startsWith("UTF-16")) {
123                     String JavaDoc ENCODING = encoding.toUpperCase(Locale.ENGLISH);
124                     if(ENCODING.equals("UTF-16")) return;
125                     if(ENCODING.equals("ISO-10646-UCS-4")) {
126                         if(fCurrentEntity.encoding.equals("UTF-16BE")) {
127                             fCurrentEntity.reader = new UCSReader(fCurrentEntity.stream, UCSReader.UCS4BE);
128                         } else {
129                             fCurrentEntity.reader = new UCSReader(fCurrentEntity.stream, UCSReader.UCS4LE);
130                         }
131                         return;
132                     }
133                     if(ENCODING.equals("ISO-10646-UCS-2")) {
134                         if(fCurrentEntity.encoding.equals("UTF-16BE")) {
135                             fCurrentEntity.reader = new UCSReader(fCurrentEntity.stream, UCSReader.UCS2BE);
136                         } else {
137                             fCurrentEntity.reader = new UCSReader(fCurrentEntity.stream, UCSReader.UCS2LE);
138                         }
139                         return;
140                     }
141                 }
142                 // wrap a new reader around the input stream, changing
143
// the encoding
144
if (DEBUG_ENCODINGS) {
145                     System.out.println("$$$ creating new reader from stream: "+
146                                     fCurrentEntity.stream);
147                 }
148                 //fCurrentEntity.stream.reset();
149
fCurrentEntity.setReader(fCurrentEntity.stream, encoding, null);
150                 fCurrentEntity.encoding = encoding;
151             } else {
152                 if (DEBUG_ENCODINGS)
153                     System.out.println("$$$ reusing old reader on stream");
154             }
155         }
156
157     } // setEncoding(String)
158

159     /**
160      * Sets the XML version. This method is used by the
161      * scanners to report the value of the version pseudo-attribute
162      * in an XML or text declaration.
163      *
164      * @param xmlVersion the XML version of the current entity
165      */

166     public void setXMLVersion(String JavaDoc xmlVersion) {
167         fCurrentEntity.xmlVersion = xmlVersion;
168     } // setXMLVersion(String)
169

170     /** Returns true if the current entity being scanned is external. */
171     public boolean isExternal() {
172         return fCurrentEntity.isExternal();
173     } // isExternal():boolean
174

175     /**
176      * Returns the next character on the input.
177      * <p>
178      * <strong>Note:</strong> The character is <em>not</em> consumed.
179      *
180      * @throws IOException Thrown if i/o error occurs.
181      * @throws EOFException Thrown on end of file.
182      */

183     public int peekChar() throws IOException JavaDoc {
184         if (DEBUG_BUFFER) {
185             System.out.print("(peekChar: ");
186             XMLEntityManager.print(fCurrentEntity);
187             System.out.println();
188         }
189
190         // load more characters, if needed
191
if (fCurrentEntity.position == fCurrentEntity.count) {
192             load(0, true);
193         }
194
195         // peek at character
196
int c = fCurrentEntity.ch[fCurrentEntity.position];
197
198         // return peeked character
199
if (DEBUG_BUFFER) {
200             System.out.print(")peekChar: ");
201             XMLEntityManager.print(fCurrentEntity);
202             if (fCurrentEntity.isExternal()) {
203                 System.out.println(" -> '"+(c!='\r'?(char)c:'\n')+"'");
204             }
205             else {
206                 System.out.println(" -> '"+(char)c+"'");
207             }
208         }
209         if (fCurrentEntity.isExternal()) {
210             return c != '\r' ? c : '\n';
211         }
212         else {
213             return c;
214         }
215
216     } // peekChar():int
217

218     /**
219      * Returns the next character on the input.
220      * <p>
221      * <strong>Note:</strong> The character is consumed.
222      *
223      * @throws IOException Thrown if i/o error occurs.
224      * @throws EOFException Thrown on end of file.
225      */

226     public int scanChar() throws IOException JavaDoc {
227         if (DEBUG_BUFFER) {
228             System.out.print("(scanChar: ");
229             XMLEntityManager.print(fCurrentEntity);
230             System.out.println();
231         }
232
233         // load more characters, if needed
234
if (fCurrentEntity.position == fCurrentEntity.count) {
235             load(0, true);
236         }
237
238         // scan character
239
int c = fCurrentEntity.ch[fCurrentEntity.position++];
240         boolean external = false;
241         if (c == '\n' ||
242             (c == '\r' && (external = fCurrentEntity.isExternal()))) {
243             fCurrentEntity.lineNumber++;
244             fCurrentEntity.columnNumber = 1;
245             if (fCurrentEntity.position == fCurrentEntity.count) {
246                 fCurrentEntity.ch[0] = (char)c;
247                 load(1, false);
248             }
249             if (c == '\r' && external) {
250                 if (fCurrentEntity.ch[fCurrentEntity.position++] != '\n') {
251                     fCurrentEntity.position--;
252                 }
253                 c = '\n';
254             }
255         }
256
257         // return character that was scanned
258
if (DEBUG_BUFFER) {
259             System.out.print(")scanChar: ");
260             XMLEntityManager.print(fCurrentEntity);
261             System.out.println(" -> '"+(char)c+"'");
262         }
263         fCurrentEntity.columnNumber++;
264         return c;
265
266     } // scanChar():int
267

268     /**
269      * Returns a string matching the NMTOKEN production appearing immediately
270      * on the input as a symbol, or null if NMTOKEN Name string is present.
271      * <p>
272      * <strong>Note:</strong> The NMTOKEN characters are consumed.
273      * <p>
274      * <strong>Note:</strong> The string returned must be a symbol. The
275      * SymbolTable can be used for this purpose.
276      *
277      * @throws IOException Thrown if i/o error occurs.
278      * @throws EOFException Thrown on end of file.
279      *
280      * @see org.apache.xerces.util.SymbolTable
281      * @see org.apache.xerces.util.XMLChar#isName
282      */

283     public String JavaDoc scanNmtoken() throws IOException JavaDoc {
284         if (DEBUG_BUFFER) {
285             System.out.print("(scanNmtoken: ");
286             XMLEntityManager.print(fCurrentEntity);
287             System.out.println();
288         }
289
290         // load more characters, if needed
291
if (fCurrentEntity.position == fCurrentEntity.count) {
292             load(0, true);
293         }
294
295         // scan nmtoken
296
int offset = fCurrentEntity.position;
297         while (XMLChar.isName(fCurrentEntity.ch[fCurrentEntity.position])) {
298             if (++fCurrentEntity.position == fCurrentEntity.count) {
299                 int length = fCurrentEntity.position - offset;
300                 if (length == fCurrentEntity.ch.length) {
301                     // bad luck we have to resize our buffer
302
char[] tmp = new char[fCurrentEntity.ch.length << 1];
303                     System.arraycopy(fCurrentEntity.ch, offset,
304                                      tmp, 0, length);
305                     fCurrentEntity.ch = tmp;
306                 }
307                 else {
308                     System.arraycopy(fCurrentEntity.ch, offset,
309                                      fCurrentEntity.ch, 0, length);
310                 }
311                 offset = 0;
312                 if (load(length, false)) {
313                     break;
314                 }
315             }
316         }
317         int length = fCurrentEntity.position - offset;
318         fCurrentEntity.columnNumber += length;
319
320         // return nmtoken
321
String JavaDoc symbol = null;
322         if (length > 0) {
323             symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length);
324         }
325         if (DEBUG_BUFFER) {
326             System.out.print(")scanNmtoken: ");
327             XMLEntityManager.print(fCurrentEntity);
328             System.out.println(" -> "+String.valueOf(symbol));
329         }
330         return symbol;
331
332     } // scanNmtoken():String
333

334     /**
335      * Returns a string matching the Name production appearing immediately
336      * on the input as a symbol, or null if no Name string is present.
337      * <p>
338      * <strong>Note:</strong> The Name characters are consumed.
339      * <p>
340      * <strong>Note:</strong> The string returned must be a symbol. The
341      * SymbolTable can be used for this purpose.
342      *
343      * @throws IOException Thrown if i/o error occurs.
344      * @throws EOFException Thrown on end of file.
345      *
346      * @see org.apache.xerces.util.SymbolTable
347      * @see org.apache.xerces.util.XMLChar#isName
348      * @see org.apache.xerces.util.XMLChar#isNameStart
349      */

350     public String JavaDoc scanName() throws IOException JavaDoc {
351         if (DEBUG_BUFFER) {
352             System.out.print("(scanName: ");
353             XMLEntityManager.print(fCurrentEntity);
354             System.out.println();
355         }
356
357         // load more characters, if needed
358
if (fCurrentEntity.position == fCurrentEntity.count) {
359             load(0, true);
360         }
361
362         // scan name
363
int offset = fCurrentEntity.position;
364         if (XMLChar.isNameStart(fCurrentEntity.ch[offset])) {
365             if (++fCurrentEntity.position == fCurrentEntity.count) {
366                 fCurrentEntity.ch[0] = fCurrentEntity.ch[offset];
367                 offset = 0;
368                 if (load(1, false)) {
369                     fCurrentEntity.columnNumber++;
370                     String JavaDoc symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 1);
371                     if (DEBUG_BUFFER) {
372                         System.out.print(")scanName: ");
373                         XMLEntityManager.print(fCurrentEntity);
374                         System.out.println(" -> "+String.valueOf(symbol));
375                     }
376                     return symbol;
377                 }
378             }
379             while (XMLChar.isName(fCurrentEntity.ch[fCurrentEntity.position])) {
380                 if (++fCurrentEntity.position == fCurrentEntity.count) {
381                     int length = fCurrentEntity.position - offset;
382                     if (length == fCurrentEntity.ch.length) {
383                         // bad luck we have to resize our buffer
384
char[] tmp = new char[fCurrentEntity.ch.length << 1];
385                         System.arraycopy(fCurrentEntity.ch, offset,
386                                          tmp, 0, length);
387                         fCurrentEntity.ch = tmp;
388                     }
389                     else {
390                         System.arraycopy(fCurrentEntity.ch, offset,
391                                          fCurrentEntity.ch, 0, length);
392                     }
393                     offset = 0;
394                     if (load(length, false)) {
395                         break;
396                     }
397                 }
398             }
399         }
400         int length = fCurrentEntity.position - offset;
401         fCurrentEntity.columnNumber += length;
402
403         // return name
404
String JavaDoc symbol = null;
405         if (length > 0) {
406             symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length);
407         }
408         if (DEBUG_BUFFER) {
409             System.out.print(")scanName: ");
410             XMLEntityManager.print(fCurrentEntity);
411             System.out.println(" -> "+String.valueOf(symbol));
412         }
413         return symbol;
414
415     } // scanName():String
416

417     /**
418      * Returns a string matching the NCName production appearing immediately
419      * on the input as a symbol, or null if no NCName string is present.
420      * <p>
421      * <strong>Note:</strong> The NCName characters are consumed.
422      * <p>
423      * <strong>Note:</strong> The string returned must be a symbol. The
424      * SymbolTable can be used for this purpose.
425      *
426      * @throws IOException Thrown if i/o error occurs.
427      * @throws EOFException Thrown on end of file.
428      *
429      * @see org.apache.xerces.util.SymbolTable
430      * @see org.apache.xerces.util.XMLChar#isNCName
431      * @see org.apache.xerces.util.XMLChar#isNCNameStart
432      */

433     public String JavaDoc scanNCName() throws IOException JavaDoc {
434         if (DEBUG_BUFFER) {
435             System.out.print("(scanNCName: ");
436             XMLEntityManager.print(fCurrentEntity);
437             System.out.println();
438         }
439
440         // load more characters, if needed
441
if (fCurrentEntity.position == fCurrentEntity.count) {
442             load(0, true);
443         }
444
445         // scan name
446
int offset = fCurrentEntity.position;
447         if (XMLChar.isNCNameStart(fCurrentEntity.ch[offset])) {
448             if (++fCurrentEntity.position == fCurrentEntity.count) {
449                 fCurrentEntity.ch[0] = fCurrentEntity.ch[offset];
450                 offset = 0;
451                 if (load(1, false)) {
452                     fCurrentEntity.columnNumber++;
453                     String JavaDoc symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 1);
454                     if (DEBUG_BUFFER) {
455                         System.out.print(")scanNCName: ");
456                         XMLEntityManager.print(fCurrentEntity);
457                         System.out.println(" -> "+String.valueOf(symbol));
458                     }
459                     return symbol;
460                 }
461             }
462             while (XMLChar.isNCName(fCurrentEntity.ch[fCurrentEntity.position])) {
463                 if (++fCurrentEntity.position == fCurrentEntity.count) {
464                     int length = fCurrentEntity.position - offset;
465                     if (length == fCurrentEntity.ch.length) {
466                         // bad luck we have to resize our buffer
467
char[] tmp = new char[fCurrentEntity.ch.length << 1];
468                         System.arraycopy(fCurrentEntity.ch, offset,
469                                          tmp, 0, length);
470                         fCurrentEntity.ch = tmp;
471                     }
472                     else {
473                         System.arraycopy(fCurrentEntity.ch, offset,
474                                          fCurrentEntity.ch, 0, length);
475                     }
476                     offset = 0;
477                     if (load(length, false)) {
478                         break;
479                     }
480                 }
481             }
482         }
483         int length = fCurrentEntity.position - offset;
484         fCurrentEntity.columnNumber += length;
485
486         // return name
487
String JavaDoc symbol = null;
488         if (length > 0) {
489             symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length);
490         }
491         if (DEBUG_BUFFER) {
492             System.out.print(")scanNCName: ");
493             XMLEntityManager.print(fCurrentEntity);
494             System.out.println(" -> "+String.valueOf(symbol));
495         }
496         return symbol;
497
498     } // scanNCName():String
499

500     /**
501      * Scans a qualified name from the input, setting the fields of the
502      * QName structure appropriately.
503      * <p>
504      * <strong>Note:</strong> The qualified name characters are consumed.
505      * <p>
506      * <strong>Note:</strong> The strings used to set the values of the
507      * QName structure must be symbols. The SymbolTable can be used for
508      * this purpose.
509      *
510      * @param qname The qualified name structure to fill.
511      *
512      * @return Returns true if a qualified name appeared immediately on
513      * the input and was scanned, false otherwise.
514      *
515      * @throws IOException Thrown if i/o error occurs.
516      * @throws EOFException Thrown on end of file.
517      *
518      * @see org.apache.xerces.util.SymbolTable
519      * @see org.apache.xerces.util.XMLChar#isName
520      * @see org.apache.xerces.util.XMLChar#isNameStart
521      */

522     public boolean scanQName(QName qname) throws IOException JavaDoc {
523         if (DEBUG_BUFFER) {
524             System.out.print("(scanQName, "+qname+": ");
525             XMLEntityManager.print(fCurrentEntity);
526             System.out.println();
527         }
528
529         // load more characters, if needed
530
if (fCurrentEntity.position == fCurrentEntity.count) {
531             load(0, true);
532         }
533
534         // scan qualified name
535
int offset = fCurrentEntity.position;
536         if (XMLChar.isNCNameStart(fCurrentEntity.ch[offset])) {
537             if (++fCurrentEntity.position == fCurrentEntity.count) {
538                 fCurrentEntity.ch[0] = fCurrentEntity.ch[offset];
539                 offset = 0;
540                 if (load(1, false)) {
541                     fCurrentEntity.columnNumber++;
542                     String JavaDoc name =
543                         fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 1);
544                     qname.setValues(null, name, name, null);
545                     if (DEBUG_BUFFER) {
546                         System.out.print(")scanQName, "+qname+": ");
547                         XMLEntityManager.print(fCurrentEntity);
548                         System.out.println(" -> true");
549                     }
550                     return true;
551                 }
552             }
553             int index = -1;
554             while (XMLChar.isName(fCurrentEntity.ch[fCurrentEntity.position])) {
555                 char c = fCurrentEntity.ch[fCurrentEntity.position];
556
557                 if (c == ':') {
558                     if (index != -1) {
559                         break;
560                     }
561                     index = fCurrentEntity.position;
562                 }
563                 if (++fCurrentEntity.position == fCurrentEntity.count) {
564                     int length = fCurrentEntity.position - offset;
565                     if (length == fCurrentEntity.ch.length) {
566                         // bad luck we have to resize our buffer
567
char[] tmp = new char[fCurrentEntity.ch.length << 1];
568                         System.arraycopy(fCurrentEntity.ch, offset,
569                                          tmp, 0, length);
570                         fCurrentEntity.ch = tmp;
571                     }
572                     else {
573                         System.arraycopy(fCurrentEntity.ch, offset,
574                                          fCurrentEntity.ch, 0, length);
575                     }
576                     if (index != -1) {
577                         index = index - offset;
578                     }
579                     offset = 0;
580                     if (load(length, false)) {
581                         break;
582                     }
583                 }
584             }
585             int length = fCurrentEntity.position - offset;
586             fCurrentEntity.columnNumber += length;
587             if (length > 0) {
588                 String JavaDoc prefix = null;
589                 String JavaDoc localpart = null;
590                 String JavaDoc rawname = fSymbolTable.addSymbol(fCurrentEntity.ch,
591                                                         offset, length);
592                 if (index != -1) {
593                     int prefixLength = index - offset;
594                     prefix = fSymbolTable.addSymbol(fCurrentEntity.ch,
595                                                     offset, prefixLength);
596                     int len = length - prefixLength - 1;
597                     int startLocal = index +1;
598                     if (!XMLChar.isNCNameStart(fCurrentEntity.ch[startLocal])){
599                         fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
600                                                  "IllegalQName",
601                                                   null,
602                                                   XMLErrorReporter.SEVERITY_FATAL_ERROR);
603                     }
604                     localpart = fSymbolTable.addSymbol(fCurrentEntity.ch,
605                                                        startLocal, len);
606
607                 }
608                 else {
609                     localpart = rawname;
610                 }
611                 qname.setValues(prefix, localpart, rawname, null);
612                 if (DEBUG_BUFFER) {
613                     System.out.print(")scanQName, "+qname+": ");
614                     XMLEntityManager.print(fCurrentEntity);
615                     System.out.println(" -> true");
616                 }
617                 return true;
618             }
619         }
620
621         // no qualified name found
622
if (DEBUG_BUFFER) {
623             System.out.print(")scanQName, "+qname+": ");
624             XMLEntityManager.print(fCurrentEntity);
625             System.out.println(" -> false");
626         }
627         return false;
628
629     } // scanQName(QName):boolean
630

631     /**
632      * Scans a range of parsed character data, setting the fields of the
633      * XMLString structure, appropriately.
634      * <p>
635      * <strong>Note:</strong> The characters are consumed.
636      * <p>
637      * <strong>Note:</strong> This method does not guarantee to return
638      * the longest run of parsed character data. This method may return
639      * before markup due to reaching the end of the input buffer or any
640      * other reason.
641      * <p>
642      * <strong>Note:</strong> The fields contained in the XMLString
643      * structure are not guaranteed to remain valid upon subsequent calls
644      * to the entity scanner. Therefore, the caller is responsible for
645      * immediately using the returned character data or making a copy of
646      * the character data.
647      *
648      * @param content The content structure to fill.
649      *
650      * @return Returns the next character on the input, if known. This
651      * value may be -1 but this does <em>note</em> designate
652      * end of file.
653      *
654      * @throws IOException Thrown if i/o error occurs.
655      * @throws EOFException Thrown on end of file.
656      */

657     public int scanContent(XMLString content) throws IOException JavaDoc {
658         if (DEBUG_BUFFER) {
659             System.out.print("(scanContent: ");
660             XMLEntityManager.print(fCurrentEntity);
661             System.out.println();
662         }
663
664         // load more characters, if needed
665
if (fCurrentEntity.position == fCurrentEntity.count) {
666             load(0, true);
667         }
668         else if (fCurrentEntity.position == fCurrentEntity.count - 1) {
669             fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1];
670             load(1, false);
671             fCurrentEntity.position = 0;
672             fCurrentEntity.startPosition = 0;
673         }
674
675         // normalize newlines
676
int offset = fCurrentEntity.position;
677         int c = fCurrentEntity.ch[offset];
678         int newlines = 0;
679         boolean external = fCurrentEntity.isExternal();
680         if (c == '\n' || (c == '\r' && external)) {
681             if (DEBUG_BUFFER) {
682                 System.out.print("[newline, "+offset+", "+fCurrentEntity.position+": ");
683                 XMLEntityManager.print(fCurrentEntity);
684                 System.out.println();
685             }
686             do {
687                 c = fCurrentEntity.ch[fCurrentEntity.position++];
688                 if (c == '\r' && external) {
689                     newlines++;
690                     fCurrentEntity.lineNumber++;
691                     fCurrentEntity.columnNumber = 1;
692                     if (fCurrentEntity.position == fCurrentEntity.count) {
693                         offset = 0;
694                         fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
695                         fCurrentEntity.position = newlines;
696                         fCurrentEntity.startPosition = newlines;
697                         if (load(newlines, false)) {
698                             break;
699                         }
700                     }
701                     if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') {
702                         fCurrentEntity.position++;
703                         offset++;
704                     }
705                     /*** NEWLINE NORMALIZATION ***/
706                     else {
707                         newlines++;
708                     }
709                 }
710                 else if (c == '\n') {
711                     newlines++;
712                     fCurrentEntity.lineNumber++;
713                     fCurrentEntity.columnNumber = 1;
714                     if (fCurrentEntity.position == fCurrentEntity.count) {
715                         offset = 0;
716                         fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
717                         fCurrentEntity.position = newlines;
718                         fCurrentEntity.startPosition = newlines;
719                         if (load(newlines, false)) {
720                             break;
721                         }
722                     }
723                 }
724                 else {
725                     fCurrentEntity.position--;
726                     break;
727                 }
728             } while (fCurrentEntity.position < fCurrentEntity.count - 1);
729             for (int i = offset; i < fCurrentEntity.position; i++) {
730                 fCurrentEntity.ch[i] = '\n';
731             }
732             int length = fCurrentEntity.position - offset;
733             if (fCurrentEntity.position == fCurrentEntity.count - 1) {
734                 content.setValues(fCurrentEntity.ch, offset, length);
735                 if (DEBUG_BUFFER) {
736                     System.out.print("]newline, "+offset+", "+fCurrentEntity.position+": ");
737                     XMLEntityManager.print(fCurrentEntity);
738                     System.out.println();
739                 }
740                 return -1;
741             }
742             if (DEBUG_BUFFER) {
743                 System.out.print("]newline, "+offset+", "+fCurrentEntity.position+": ");
744                 XMLEntityManager.print(fCurrentEntity);
745                 System.out.println();
746             }
747         }
748
749         // inner loop, scanning for content
750
while (fCurrentEntity.position < fCurrentEntity.count) {
751             c = fCurrentEntity.ch[fCurrentEntity.position++];
752             if (!XMLChar.isContent(c)) {
753                 fCurrentEntity.position--;
754                 break;
755             }
756         }
757         int length = fCurrentEntity.position - offset;
758         fCurrentEntity.columnNumber += length - newlines;
759         content.setValues(fCurrentEntity.ch, offset, length);
760
761         // return next character
762
if (fCurrentEntity.position != fCurrentEntity.count) {
763             c = fCurrentEntity.ch[fCurrentEntity.position];
764             // REVISIT: Does this need to be updated to fix the
765
// #x0D ^#x0A newline normalization problem? -Ac
766
if (c == '\r' && external) {
767                 c = '\n';
768             }
769         }
770         else {
771             c = -1;
772         }
773         if (DEBUG_BUFFER) {
774             System.out.print(")scanContent: ");
775             XMLEntityManager.print(fCurrentEntity);
776             System.out.println(" -> '"+(char)c+"'");
777         }
778         return c;
779
780     } // scanContent(XMLString):int
781

782     /**
783      * Scans a range of attribute value data, setting the fields of the
784      * XMLString structure, appropriately.
785      * <p>
786      * <strong>Note:</strong> The characters are consumed.
787      * <p>
788      * <strong>Note:</strong> This method does not guarantee to return
789      * the longest run of attribute value data. This method may return
790      * before the quote character due to reaching the end of the input
791      * buffer or any other reason.
792      * <p>
793      * <strong>Note:</strong> The fields contained in the XMLString
794      * structure are not guaranteed to remain valid upon subsequent calls
795      * to the entity scanner. Therefore, the caller is responsible for
796      * immediately using the returned character data or making a copy of
797      * the character data.
798      *
799      * @param quote The quote character that signifies the end of the
800      * attribute value data.
801      * @param content The content structure to fill.
802      *
803      * @return Returns the next character on the input, if known. This
804      * value may be -1 but this does <em>note</em> designate
805      * end of file.
806      *
807      * @throws IOException Thrown if i/o error occurs.
808      * @throws EOFException Thrown on end of file.
809      */

810     public int scanLiteral(int quote, XMLString content)
811         throws IOException JavaDoc {
812         if (DEBUG_BUFFER) {
813             System.out.print("(scanLiteral, '"+(char)quote+"': ");
814             XMLEntityManager.print(fCurrentEntity);
815             System.out.println();
816         }
817
818         // load more characters, if needed
819
if (fCurrentEntity.position == fCurrentEntity.count) {
820             load(0, true);
821         }
822         else if (fCurrentEntity.position == fCurrentEntity.count - 1) {
823             fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1];
824             load(1, false);
825             fCurrentEntity.position = 0;
826             fCurrentEntity.startPosition = 0;
827         }
828
829         // normalize newlines
830
int offset = fCurrentEntity.position;
831         int c = fCurrentEntity.ch[offset];
832         int newlines = 0;
833         boolean external = fCurrentEntity.isExternal();
834         if (c == '\n' || (c == '\r' && external)) {
835             if (DEBUG_BUFFER) {
836                 System.out.print("[newline, "+offset+", "+fCurrentEntity.position+": ");
837                 XMLEntityManager.print(fCurrentEntity);
838                 System.out.println();
839             }
840             do {
841                 c = fCurrentEntity.ch[fCurrentEntity.position++];
842                 if (c == '\r' && external) {
843                     newlines++;
844                     fCurrentEntity.lineNumber++;
845                     fCurrentEntity.columnNumber = 1;
846                     if (fCurrentEntity.position == fCurrentEntity.count) {
847                         offset = 0;
848                         fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
849                         fCurrentEntity.position = newlines;
850                         fCurrentEntity.startPosition = newlines;
851                         if (load(newlines, false)) {
852                             break;
853                         }
854                     }
855                     if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') {
856                         fCurrentEntity.position++;
857                         offset++;
858                     }
859                     /*** NEWLINE NORMALIZATION ***/
860                     else {
861                         newlines++;
862                     }
863                     /***/
864                 }
865                 else if (c == '\n') {
866                     newlines++;
867                     fCurrentEntity.lineNumber++;
868                     fCurrentEntity.columnNumber = 1;
869                     if (fCurrentEntity.position == fCurrentEntity.count) {
870                         offset = 0;
871                         fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
872                         fCurrentEntity.position = newlines;
873                         fCurrentEntity.startPosition = newlines;
874                         if (load(newlines, false)) {
875                             break;
876                         }
877                     }
878                 }
879                 else {
880                     fCurrentEntity.position--;
881                     break;
882                 }
883             } while (fCurrentEntity.position < fCurrentEntity.count - 1);
884             for (int i = offset; i < fCurrentEntity.position; i++) {
885                 fCurrentEntity.ch[i] = '\n';
886             }
887             int length = fCurrentEntity.position - offset;
888             if (fCurrentEntity.position == fCurrentEntity.count - 1) {
889                 content.setValues(fCurrentEntity.ch, offset, length);
890                 if (DEBUG_BUFFER) {
891                     System.out.print("]newline, "+offset+", "+fCurrentEntity.position+": ");
892                     XMLEntityManager.print(fCurrentEntity);
893                     System.out.println();
894                 }
895                 return -1;
896             }
897             if (DEBUG_BUFFER) {
898                 System.out.print("]newline, "+offset+", "+fCurrentEntity.position+": ");
899                 XMLEntityManager.print(fCurrentEntity);
900                 System.out.println();
901             }
902         }
903
904         // scan literal value
905
while (fCurrentEntity.position < fCurrentEntity.count) {
906             c = fCurrentEntity.ch[fCurrentEntity.position++];
907             if ((c == quote &&
908                  (!fCurrentEntity.literal || external))
909                 || c == '%' || !XMLChar.isContent(c)) {
910                 fCurrentEntity.position--;
911                 break;
912             }
913         }
914         int length = fCurrentEntity.position - offset;
915         fCurrentEntity.columnNumber += length - newlines;
916         content.setValues(fCurrentEntity.ch, offset, length);
917
918         // return next character
919
if (fCurrentEntity.position != fCurrentEntity.count) {
920             c = fCurrentEntity.ch[fCurrentEntity.position];
921             // NOTE: We don't want to accidentally signal the
922
// end of the literal if we're expanding an
923
// entity appearing in the literal. -Ac
924
if (c == quote && fCurrentEntity.literal) {
925                 c = -1;
926             }
927         }
928         else {
929             c = -1;
930         }
931         if (DEBUG_BUFFER) {
932             System.out.print(")scanLiteral, '"+(char)quote+"': ");
933             XMLEntityManager.print(fCurrentEntity);
934             System.out.println(" -> '"+(char)c+"'");
935         }
936         return c;
937
938     } // scanLiteral(int,XMLString):int
939

940     /**
941      * Scans a range of character data up to the specified delimiter,
942      * setting the fields of the XMLString structure, appropriately.
943      * <p>
944      * <strong>Note:</strong> The characters are consumed.
945      * <p>
946      * <strong>Note:</strong> This assumes that the internal buffer is
947      * at least the same size, or bigger, than the length of the delimiter
948      * and that the delimiter contains at least one character.
949      * <p>
950      * <strong>Note:</strong> This method does not guarantee to return
951      * the longest run of character data. This method may return before
952      * the delimiter due to reaching the end of the input buffer or any
953      * other reason.
954      * <p>
955      * <strong>Note:</strong> The fields contained in the XMLString
956      * structure are not guaranteed to remain valid upon subsequent calls
957      * to the entity scanner. Therefore, the caller is responsible for
958      * immediately using the returned character data or making a copy of
959      * the character data.
960      *
961      * @param delimiter The string that signifies the end of the character
962      * data to be scanned.
963      * @param data The data structure to fill.
964      *
965      * @return Returns true if there is more data to scan, false otherwise.
966      *
967      * @throws IOException Thrown if i/o error occurs.
968      * @throws EOFException Thrown on end of file.
969      */

970     public boolean scanData(String JavaDoc delimiter, XMLStringBuffer buffer)
971         throws IOException JavaDoc {
972
973         // REVISIT: This method does not need to use a string buffer.
974
// The change would avoid the array copies and increase
975
// performance. -Ac
976
//
977
// Currently, this method is called for scanning CDATA
978
// sections, comments, and processing instruction data.
979
// So if this code is updated to NOT buffer, the scanning
980
// code for comments and processing instructions will
981
// need to be updated to do its own buffering. The code
982
// for CDATA sections is safe as-is. -Ac
983

984         boolean found = false;
985         int delimLen = delimiter.length();
986         char charAt0 = delimiter.charAt(0);
987         boolean external = fCurrentEntity.isExternal();
988         if (DEBUG_BUFFER) {
989             System.out.print("(scanData: ");
990             XMLEntityManager.print(fCurrentEntity);
991             System.out.println();
992         }
993
994         // load more characters, if needed
995

996         if (fCurrentEntity.position == fCurrentEntity.count) {
997             load(0, true);
998         }
999
1000        boolean bNextEntity = false;
1001
1002        while ((fCurrentEntity.position > fCurrentEntity.count - delimLen)
1003            && (!bNextEntity))
1004        {
1005          System.arraycopy(fCurrentEntity.ch,
1006                           fCurrentEntity.position,
1007                           fCurrentEntity.ch,
1008                           0,
1009                           fCurrentEntity.count - fCurrentEntity.position);
1010
1011          bNextEntity = load(fCurrentEntity.count - fCurrentEntity.position, false);
1012          fCurrentEntity.position = 0;
1013          fCurrentEntity.startPosition = 0;
1014        }
1015
1016        if (fCurrentEntity.position > fCurrentEntity.count - delimLen) {
1017            // something must be wrong with the input: e.g., file ends in an unterminated comment
1018
int length = fCurrentEntity.count - fCurrentEntity.position;
1019            buffer.append (fCurrentEntity.ch, fCurrentEntity.position, length);
1020            fCurrentEntity.columnNumber += fCurrentEntity.count;
1021            fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
1022            fCurrentEntity.position = fCurrentEntity.count;
1023            fCurrentEntity.startPosition = fCurrentEntity.count;
1024            load(0,true);
1025            return false;
1026        }
1027
1028        // normalize newlines
1029
int offset = fCurrentEntity.position;
1030        int c = fCurrentEntity.ch[offset];
1031        int newlines = 0;
1032        if (c == '\n' || (c == '\r' && external)) {
1033            if (DEBUG_BUFFER) {
1034                System.out.print("[newline, "+offset+", "+fCurrentEntity.position+": ");
1035                XMLEntityManager.print(fCurrentEntity);
1036                System.out.println();
1037            }
1038            do {
1039                c = fCurrentEntity.ch[fCurrentEntity.position++];
1040                if (c == '\r' && external) {
1041                    newlines++;
1042                    fCurrentEntity.lineNumber++;
1043                    fCurrentEntity.columnNumber = 1;
1044                    if (fCurrentEntity.position == fCurrentEntity.count) {
1045                        offset = 0;
1046                        fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
1047                        fCurrentEntity.position = newlines;
1048                        fCurrentEntity.startPosition = newlines;
1049                        if (load(newlines, false)) {
1050                            break;
1051                        }
1052                    }
1053                    if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') {
1054                        fCurrentEntity.position++;
1055                        offset++;
1056                    }
1057                    /*** NEWLINE NORMALIZATION ***/
1058                    else {
1059                        newlines++;
1060                    }
1061                }
1062                else if (c == '\n') {
1063                    newlines++;
1064                    fCurrentEntity.lineNumber++;
1065                    fCurrentEntity.columnNumber = 1;
1066                    if (fCurrentEntity.position == fCurrentEntity.count) {
1067                        offset = 0;
1068                        fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
1069                        fCurrentEntity.position = newlines;
1070                        fCurrentEntity.startPosition = newlines;
1071                        fCurrentEntity.count = newlines;
1072                        if (load(newlines, false)) {
1073                            break;
1074                        }
1075                    }
1076                }
1077                else {
1078                    fCurrentEntity.position--;
1079                    break;
1080                }
1081            } while (fCurrentEntity.position < fCurrentEntity.count - 1);
1082            for (int i = offset; i < fCurrentEntity.position; i++) {
1083                fCurrentEntity.ch[i] = '\n';
1084            }
1085            int length = fCurrentEntity.position - offset;
1086            if (fCurrentEntity.position == fCurrentEntity.count - 1) {
1087                buffer.append(fCurrentEntity.ch, offset, length);
1088                if (DEBUG_BUFFER) {
1089                    System.out.print("]newline, "+offset+", "+fCurrentEntity.position+": ");
1090                    XMLEntityManager.print(fCurrentEntity);
1091                    System.out.println();
1092                }
1093                return true;
1094            }
1095            if (DEBUG_BUFFER) {
1096                System.out.print("]newline, "+offset+", "+fCurrentEntity.position+": ");
1097                XMLEntityManager.print(fCurrentEntity);
1098                System.out.println();
1099            }
1100        }
1101
1102        // iterate over buffer looking for delimiter
1103
OUTER: while (fCurrentEntity.position < fCurrentEntity.count) {
1104            c = fCurrentEntity.ch[fCurrentEntity.position++];
1105            if (c == charAt0) {
1106                // looks like we just hit the delimiter
1107
int delimOffset = fCurrentEntity.position - 1;
1108                for (int i = 1; i < delimLen; i++) {
1109                    if (fCurrentEntity.position == fCurrentEntity.count) {
1110                        fCurrentEntity.position -= i;
1111                        break OUTER;
1112                    }
1113                    c = fCurrentEntity.ch[fCurrentEntity.position++];
1114                    if (delimiter.charAt(i) != c) {
1115                        fCurrentEntity.position--;
1116                        break;
1117                    }
1118                }
1119                if (fCurrentEntity.position == delimOffset + delimLen) {
1120                    found = true;
1121                    break;
1122                }
1123            }
1124            else if (c == '\n' || (external && c == '\r')) {
1125                fCurrentEntity.position--;
1126                break;
1127            }
1128            else if (XMLChar.isInvalid(c)) {
1129                fCurrentEntity.position--;
1130                int length = fCurrentEntity.position - offset;
1131                fCurrentEntity.columnNumber += length - newlines;
1132                buffer.append(fCurrentEntity.ch, offset, length);
1133                return true;
1134            }
1135        }
1136        int length = fCurrentEntity.position - offset;
1137        fCurrentEntity.columnNumber += length - newlines;
1138        if (found) {
1139            length -= delimLen;
1140        }
1141        buffer.append (fCurrentEntity.ch, offset, length);
1142
1143        // return true if string was skipped
1144
if (DEBUG_BUFFER) {
1145            System.out.print(")scanData: ");
1146            XMLEntityManager.print(fCurrentEntity);
1147            System.out.println(" -> " + !found);
1148        }
1149        return !found;
1150
1151    } // scanData(String,XMLString):boolean
1152

1153    /**
1154     * Skips a character appearing immediately on the input.
1155     * <p>
1156     * <strong>Note:</strong> The character is consumed only if it matches
1157     * the specified character.
1158     *
1159     * @param c The character to skip.
1160     *
1161     * @return Returns true if the character was skipped.
1162     *
1163     * @throws IOException Thrown if i/o error occurs.
1164     * @throws EOFException Thrown on end of file.
1165     */

1166    public boolean skipChar(int c) throws IOException JavaDoc {
1167        if (DEBUG_BUFFER) {
1168            System.out.print("(skipChar, '"+(char)c+"': ");
1169            XMLEntityManager.print(fCurrentEntity);
1170            System.out.println();
1171        }
1172
1173        // load more characters, if needed
1174
if (fCurrentEntity.position == fCurrentEntity.count) {
1175            load(0, true);
1176        }
1177
1178        // skip character
1179
int cc = fCurrentEntity.ch[fCurrentEntity.position];
1180        if (cc == c) {
1181            fCurrentEntity.position++;
1182            if (c == '\n') {
1183                fCurrentEntity.lineNumber++;
1184                fCurrentEntity.columnNumber = 1;
1185            }
1186            else {
1187                fCurrentEntity.columnNumber++;
1188            }
1189            if (DEBUG_BUFFER) {
1190                System.out.print(")skipChar, '"+(char)c+"': ");
1191                XMLEntityManager.print(fCurrentEntity);
1192                System.out.println(" -> true");
1193            }
1194            return true;
1195        }
1196        else if (c == '\n' && cc == '\r' && fCurrentEntity.isExternal()) {
1197            // handle newlines
1198
if (fCurrentEntity.position == fCurrentEntity.count) {
1199                fCurrentEntity.ch[0] = (char)cc;
1200                load(1, false);
1201            }
1202            fCurrentEntity.position++;
1203            if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') {
1204                fCurrentEntity.position++;
1205            }
1206            fCurrentEntity.lineNumber++;
1207            fCurrentEntity.columnNumber = 1;
1208            if (DEBUG_BUFFER) {
1209                System.out.print(")skipChar, '"+(char)c+"': ");
1210                XMLEntityManager.print(fCurrentEntity);
1211                System.out.println(" -> true");
1212            }
1213            return true;
1214        }
1215
1216        // character was not skipped
1217
if (DEBUG_BUFFER) {
1218            System.out.print(")skipChar, '"+(char)c+"': ");
1219            XMLEntityManager.print(fCurrentEntity);
1220            System.out.println(" -> false");
1221        }
1222        return false;
1223
1224    } // skipChar(int):boolean
1225

1226    /**
1227     * Skips space characters appearing immediately on the input.
1228     * <p>
1229     * <strong>Note:</strong> The characters are consumed only if they are
1230     * space characters.
1231     *
1232     * @return Returns true if at least one space character was skipped.
1233     *
1234     * @throws IOException Thrown if i/o error occurs.
1235     * @throws EOFException Thrown on end of file.
1236     *
1237     * @see org.apache.xerces.util.XMLChar#isSpace
1238     */

1239    public boolean skipSpaces() throws IOException JavaDoc {
1240        if (DEBUG_BUFFER) {
1241            System.out.print("(skipSpaces: ");
1242            XMLEntityManager.print(fCurrentEntity);
1243            System.out.println();
1244        }
1245
1246        // load more characters, if needed
1247
if (fCurrentEntity.position == fCurrentEntity.count) {
1248            load(0, true);
1249        }
1250
1251        // skip spaces
1252
int c = fCurrentEntity.ch[fCurrentEntity.position];
1253        if (XMLChar.isSpace(c)) {
1254            boolean external = fCurrentEntity.isExternal();
1255            do {
1256                boolean entityChanged = false;
1257                // handle newlines
1258
if (c == '\n' || (external && c == '\r')) {
1259                    fCurrentEntity.lineNumber++;
1260                    fCurrentEntity.columnNumber = 1;
1261                    if (fCurrentEntity.position == fCurrentEntity.count - 1) {
1262                        fCurrentEntity.ch[0] = (char)c;
1263                        entityChanged = load(1, true);
1264                        if (!entityChanged) {
1265                            // the load change the position to be 1,
1266
// need to restore it when entity not changed
1267
fCurrentEntity.position = 0;
1268                            fCurrentEntity.startPosition = 0;
1269                        }
1270                    }
1271                    if (c == '\r' && external) {
1272                        // REVISIT: Does this need to be updated to fix the
1273
// #x0D ^#x0A newline normalization problem? -Ac
1274
if (fCurrentEntity.ch[++fCurrentEntity.position] != '\n') {
1275                            fCurrentEntity.position--;
1276                        }
1277                    }
1278                    /*** NEWLINE NORMALIZATION ***
1279                    else {
1280                        if (fCurrentEntity.ch[fCurrentEntity.position + 1] == '\r'
1281                            && external) {
1282                            fCurrentEntity.position++;
1283                        }
1284                    }
1285                    /***/

1286                }
1287                else {
1288                    fCurrentEntity.columnNumber++;
1289                }
1290                // load more characters, if needed
1291
if (!entityChanged)
1292                    fCurrentEntity.position++;
1293                if (fCurrentEntity.position == fCurrentEntity.count) {
1294                    load(0, true);
1295                }
1296            } while (XMLChar.isSpace(c = fCurrentEntity.ch[fCurrentEntity.position]));
1297            if (DEBUG_BUFFER) {
1298                System.out.print(")skipSpaces: ");
1299                XMLEntityManager.print(fCurrentEntity);
1300                System.out.println(" -> true");
1301            }
1302            return true;
1303        }
1304
1305        // no spaces were found
1306
if (DEBUG_BUFFER) {
1307            System.out.print(")skipSpaces: ");
1308            XMLEntityManager.print(fCurrentEntity);
1309            System.out.println(" -> false");
1310        }
1311        return false;
1312
1313    } // skipSpaces():boolean
1314

1315    /**
1316     * Skips space characters appearing immediately on the input that would
1317     * match non-terminal S (0x09, 0x0A, 0x0D, 0x20) before end of line
1318     * normalization is performed. This is useful when scanning structures
1319     * such as the XMLDecl and TextDecl that can only contain US-ASCII
1320     * characters.
1321     * <p>
1322     * <strong>Note:</strong> The characters are consumed only if they would
1323     * match non-terminal S before end of line normalization is performed.
1324     *
1325     * @return Returns true if at least one space character was skipped.
1326     *
1327     * @throws IOException Thrown if i/o error occurs.
1328     * @throws EOFException Thrown on end of file.
1329     *
1330     * @see org.apache.xerces.util.XMLChar#isSpace
1331     */

1332    public boolean skipDeclSpaces() throws IOException JavaDoc {
1333        if (DEBUG_BUFFER) {
1334            System.out.print("(skipDeclSpaces: ");
1335            XMLEntityManager.print(fCurrentEntity);
1336            System.out.println();
1337        }
1338
1339        // load more characters, if needed
1340
if (fCurrentEntity.position == fCurrentEntity.count) {
1341            load(0, true);
1342        }
1343
1344        // skip spaces
1345
int c = fCurrentEntity.ch[fCurrentEntity.position];
1346        if (XMLChar.isSpace(c)) {
1347            boolean external = fCurrentEntity.isExternal();
1348            do {
1349                boolean entityChanged = false;
1350                // handle newlines
1351
if (c == '\n' || (external && c == '\r')) {
1352                    fCurrentEntity.lineNumber++;
1353                    fCurrentEntity.columnNumber = 1;
1354                    if (fCurrentEntity.position == fCurrentEntity.count - 1) {
1355                        fCurrentEntity.ch[0] = (char)c;
1356                        entityChanged = load(1, true);
1357                        if (!entityChanged) {
1358                            // the load change the position to be 1,
1359
// need to restore it when entity not changed
1360
fCurrentEntity.position = 0;
1361                            fCurrentEntity.startPosition = 0;
1362                        }
1363                    }
1364                    if (c == '\r' && external) {
1365                        // REVISIT: Does this need to be updated to fix the
1366
// #x0D ^#x0A newline normalization problem? -Ac
1367
if (fCurrentEntity.ch[++fCurrentEntity.position] != '\n') {
1368                            fCurrentEntity.position--;
1369                        }
1370                    }
1371                    /*** NEWLINE NORMALIZATION ***
1372                    else {
1373                        if (fCurrentEntity.ch[fCurrentEntity.position + 1] == '\r'
1374                            && external) {
1375                            fCurrentEntity.position++;
1376                        }
1377                    }
1378                    /***/

1379                }
1380                else {
1381                    fCurrentEntity.columnNumber++;
1382                }
1383                // load more characters, if needed
1384
if (!entityChanged)
1385                    fCurrentEntity.position++;
1386                if (fCurrentEntity.position == fCurrentEntity.count) {
1387                    load(0, true);
1388                }
1389            } while (XMLChar.isSpace(c = fCurrentEntity.ch[fCurrentEntity.position]));
1390            if (DEBUG_BUFFER) {
1391                System.out.print(")skipDeclSpaces: ");
1392                XMLEntityManager.print(fCurrentEntity);
1393                System.out.println(" -> true");
1394            }
1395            return true;
1396        }
1397
1398        // no spaces were found
1399
if (DEBUG_BUFFER) {
1400            System.out.print(")skipDeclSpaces: ");
1401            XMLEntityManager.print(fCurrentEntity);
1402            System.out.println(" -> false");
1403        }
1404        return false;
1405
1406    } // skipDeclSpaces():boolean
1407

1408    /**
1409     * Skips the specified string appearing immediately on the input.
1410     * <p>
1411     * <strong>Note:</strong> The characters are consumed only if they are
1412     * space characters.
1413     *
1414     * @param s The string to skip.
1415     *
1416     * @return Returns true if the string was skipped.
1417     *
1418     * @throws IOException Thrown if i/o error occurs.
1419     * @throws EOFException Thrown on end of file.
1420     */

1421    public boolean skipString(String JavaDoc s) throws IOException JavaDoc {
1422        if (DEBUG_BUFFER) {
1423            System.out.print("(skipString, \""+s+"\": ");
1424            XMLEntityManager.print(fCurrentEntity);
1425            System.out.println();
1426        }
1427
1428        // load more characters, if needed
1429
if (fCurrentEntity.position == fCurrentEntity.count) {
1430            load(0, true);
1431        }
1432
1433        // skip string
1434
final int length = s.length();
1435        for (int i = 0; i < length; i++) {
1436            char c = fCurrentEntity.ch[fCurrentEntity.position++];
1437            if (c != s.charAt(i)) {
1438                fCurrentEntity.position -= i + 1;
1439                if (DEBUG_BUFFER) {
1440                    System.out.print(")skipString, \""+s+"\": ");
1441                    XMLEntityManager.print(fCurrentEntity);
1442                    System.out.println(" -> false");
1443                }
1444                return false;
1445            }
1446            if (i < length - 1 && fCurrentEntity.position == fCurrentEntity.count) {
1447                System.arraycopy(fCurrentEntity.ch, fCurrentEntity.count - i - 1, fCurrentEntity.ch, 0, i + 1);
1448                // REVISIT: Can a string to be skipped cross an
1449
// entity boundary? -Ac
1450
if (load(i + 1, false)) {
1451                    fCurrentEntity.startPosition -= i + 1;
1452                    fCurrentEntity.position -= i + 1;
1453                    if (DEBUG_BUFFER) {
1454                        System.out.print(")skipString, \""+s+"\": ");
1455                        XMLEntityManager.print(fCurrentEntity);
1456                        System.out.println(" -> false");
1457                    }
1458                    return false;
1459                }
1460            }
1461        }
1462        if (DEBUG_BUFFER) {
1463            System.out.print(")skipString, \""+s+"\": ");
1464            XMLEntityManager.print(fCurrentEntity);
1465            System.out.println(" -> true");
1466        }
1467        fCurrentEntity.columnNumber += length;
1468        return true;
1469
1470    } // skipString(String):boolean
1471

1472    //
1473
// Locator methods
1474
//
1475

1476    /**
1477     * Return the public identifier for the current document event.
1478     * <p>
1479     * The return value is the public identifier of the document
1480     * entity or of the external parsed entity in which the markup
1481     * triggering the event appears.
1482     *
1483     * @return A string containing the public identifier, or
1484     * null if none is available.
1485     */

1486    public String JavaDoc getPublicId() {
1487        return (fCurrentEntity != null && fCurrentEntity.entityLocation != null) ? fCurrentEntity.entityLocation.getPublicId() : null;
1488    } // getPublicId():String
1489

1490    /**
1491     * Return the expanded system identifier for the current document event.
1492     * <p>
1493     * The return value is the expanded system identifier of the document
1494     * entity or of the external parsed entity in which the markup
1495     * triggering the event appears.
1496     * <p>
1497     * If the system identifier is a URL, the parser must resolve it
1498     * fully before passing it to the application.
1499     *
1500     * @return A string containing the expanded system identifier, or null
1501     * if none is available.
1502     */

1503    public String JavaDoc getExpandedSystemId() {
1504        if (fCurrentEntity != null) {
1505            if (fCurrentEntity.entityLocation != null &&
1506                    fCurrentEntity.entityLocation.getExpandedSystemId() != null ) {
1507                return fCurrentEntity.entityLocation.getExpandedSystemId();
1508            }
1509            else {
1510                // get the current entity to return something appropriate:
1511
return fCurrentEntity.getExpandedSystemId();
1512            }
1513        }
1514        return null;
1515    } // getExpandedSystemId():String
1516

1517    /**
1518     * Return the literal system identifier for the current document event.
1519     * <p>
1520     * The return value is the literal system identifier of the document
1521     * entity or of the external parsed entity in which the markup
1522     * triggering the event appears.
1523     * <p>
1524     * @return A string containing the literal system identifier, or null
1525     * if none is available.
1526     */

1527    public String JavaDoc getLiteralSystemId() {
1528        if (fCurrentEntity != null) {
1529            if (fCurrentEntity.entityLocation != null &&
1530                    fCurrentEntity.entityLocation.getLiteralSystemId() != null ) {
1531                return fCurrentEntity.entityLocation.getLiteralSystemId();
1532            }
1533            else {
1534                // get the current entity to do it:
1535
return fCurrentEntity.getLiteralSystemId();
1536            }
1537        }
1538        return null;
1539    } // getLiteralSystemId():String
1540

1541    /**
1542     * Returns the line number where the current document event ends.
1543     * <p>
1544     * <strong>Warning:</strong> The return value from the method
1545     * is intended only as an approximation for the sake of error
1546     * reporting; it is not intended to provide sufficient information
1547     * to edit the character content of the original XML document.
1548     * <p>
1549     * The return value is an approximation of the line number
1550     * in the document entity or external parsed entity where the
1551     * markup triggering the event appears.
1552     * <p>
1553     * If possible, the line position of the first character after the
1554     * text associated with the document event should be provided.
1555     * The first line in the document is line 1.
1556     *
1557     * @return The line number, or -1 if none is available.
1558     */

1559    public int getLineNumber() {
1560        if (fCurrentEntity != null) {
1561            if (fCurrentEntity.isExternal()) {
1562                return fCurrentEntity.lineNumber;
1563            }
1564            else {
1565                // ask the current entity to return something appropriate:
1566
return fCurrentEntity.getLineNumber();
1567            }
1568        }
1569
1570        return -1;
1571
1572    } // getLineNumber():int
1573

1574    /**
1575     * Returns the column number where the current document event ends.
1576     * <p>
1577     * <strong>Warning:</strong> The return value from the method
1578     * is intended only as an approximation for the sake of error
1579     * reporting; it is not intended to provide sufficient information
1580     * to edit the character content of the original XML document.
1581     * <p>
1582     * The return value is an approximation of the column number
1583     * in the document entity or external parsed entity where the
1584     * markup triggering the event appears.
1585     * <p>
1586     * If possible, the line position of the first character after the
1587     * text associated with the document event should be provided.
1588     * The first column in each line is column 1.
1589     *
1590     * @return The column number, or -1 if none is available.
1591     */

1592    public int getColumnNumber() {
1593        if (fCurrentEntity != null) {
1594            if (fCurrentEntity.isExternal()) {
1595                return fCurrentEntity.columnNumber;
1596            }
1597            else {
1598                // ask current entity to find appropriate column number
1599
return fCurrentEntity.getColumnNumber();
1600            }
1601        }
1602
1603        return -1;
1604    } // getColumnNumber():int
1605

1606    /**
1607     * Returns the character offset where the current document event ends.
1608     * <p>
1609     * <strong>Warning:</strong> The return value from the method
1610     * is intended only as an approximation for the sake of error
1611     * reporting; it is not intended to provide sufficient information
1612     * to edit the character content of the original XML document.
1613     * <p>
1614     * The return value is an approximation of the character offset
1615     * in the document entity or external parsed entity where the
1616     * markup triggering the event appears.
1617     * <p>
1618     * If possible, the character offset of the first character after the
1619     * text associated with the document event should be provided.
1620     *
1621     * @return The character offset, or -1 if none is available.
1622     */

1623    public int getCharacterOffset() {
1624        if (fCurrentEntity != null) {
1625            if (fCurrentEntity.isExternal()) {
1626                return fCurrentEntity.baseCharOffset + (fCurrentEntity.position - fCurrentEntity.startPosition);
1627            }
1628            else {
1629                // ask current entity to find appropriate character offset
1630
return fCurrentEntity.getCharacterOffset();
1631            }
1632        }
1633        
1634        return -1;
1635    } // getCharacterOffset():int
1636

1637    /**
1638     * Returns the encoding of the current entity.
1639     * Note that, for a given entity, this value can only be
1640     * considered final once the encoding declaration has been read (or once it
1641     * has been determined that there is no such declaration) since, no encoding
1642     * having been specified on the XMLInputSource, the parser
1643     * will make an initial "guess" which could be in error.
1644     */

1645    public String JavaDoc getEncoding() {
1646        if (fCurrentEntity != null) {
1647            if (fCurrentEntity.isExternal()) {
1648                return fCurrentEntity.encoding;
1649            }
1650            else {
1651                // ask current entity to find appropriate encoding
1652
return fCurrentEntity.getEncoding();
1653            }
1654        }
1655        return null;
1656    } // getEncoding():String
1657

1658    /**
1659     * Returns the XML version of the current entity. This will normally be the
1660     * value from the XML or text declaration or defaulted by the parser. Note that
1661     * that this value may be different than the version of the processing rules
1662     * applied to the current entity. For instance, an XML 1.1 document may refer to
1663     * XML 1.0 entities. In such a case the rules of XML 1.1 are applied to the entire
1664     * document. Also note that, for a given entity, this value can only be considered
1665     * final once the XML or text declaration has been read or once it has been
1666     * determined that there is no such declaration.
1667     */

1668    public String JavaDoc getXMLVersion() {
1669        if (fCurrentEntity != null) {
1670            if (fCurrentEntity.isExternal()) {
1671                return fCurrentEntity.xmlVersion;
1672            }
1673            else {
1674                // ask current entity to find the appropriate XML version
1675
return fCurrentEntity.getXMLVersion();
1676            }
1677        }
1678        return null;
1679    } // getXMLVersion():String
1680

1681    // allow entity manager to tell us what the current entityis:
1682
public void setCurrentEntity(XMLEntityManager.ScannedEntity ent) {
1683        fCurrentEntity = ent;
1684    }
1685
1686    // set buffer size:
1687
public void setBufferSize(int size) {
1688        // REVISIT: Buffer size passed to entity scanner
1689
// was not being kept in synch with the actual size
1690
// of the buffers in each scanned entity. If any
1691
// of the buffers were actually resized, it was possible
1692
// that the parser would throw an ArrayIndexOutOfBoundsException
1693
// for documents which contained names which are longer than
1694
// the current buffer size. Conceivably the buffer size passed
1695
// to entity scanner could be used to determine a minimum size
1696
// for resizing, if doubling its size is smaller than this
1697
// minimum. -- mrglavas
1698
fBufferSize = size;
1699    }
1700
1701    // reset what little state we have...
1702
public void reset(SymbolTable symbolTable, XMLEntityManager entityManager,
1703                        XMLErrorReporter reporter) {
1704        fCurrentEntity = null;
1705        fSymbolTable = symbolTable;
1706        fEntityManager = entityManager;
1707        fErrorReporter = reporter;
1708    }
1709
1710    //
1711
// Private methods
1712
//
1713

1714    /**
1715     * Loads a chunk of text.
1716     *
1717     * @param offset The offset into the character buffer to
1718     * read the next batch of characters.
1719     * @param changeEntity True if the load should change entities
1720     * at the end of the entity, otherwise leave
1721     * the current entity in place and the entity
1722     * boundary will be signaled by the return
1723     * value.
1724     *
1725     * @returns Returns true if the entity changed as a result of this
1726     * load operation.
1727     */

1728    final boolean load(int offset, boolean changeEntity)
1729        throws IOException JavaDoc {
1730        if (DEBUG_BUFFER) {
1731            System.out.print("(load, "+offset+": ");
1732            XMLEntityManager.print(fCurrentEntity);
1733            System.out.println();
1734        }
1735
1736        fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
1737        // read characters
1738
int length = fCurrentEntity.mayReadChunks?
1739                (fCurrentEntity.ch.length - offset):
1740                (XMLEntityManager.DEFAULT_XMLDECL_BUFFER_SIZE);
1741        if (DEBUG_BUFFER) System.out.println(" length to try to read: "+length);
1742        int count = fCurrentEntity.reader.read(fCurrentEntity.ch, offset, length);
1743        if (DEBUG_BUFFER) System.out.println(" length actually read: "+count);
1744
1745        // reset count and position
1746
boolean entityChanged = false;
1747        if (count != -1) {
1748            if (count != 0) {
1749                fCurrentEntity.count = count + offset;
1750                fCurrentEntity.position = offset;
1751                fCurrentEntity.startPosition = offset;
1752            }
1753        }
1754
1755        // end of this entity
1756
else {
1757            fCurrentEntity.count = offset;
1758            fCurrentEntity.position = offset;
1759            fCurrentEntity.startPosition = offset;
1760            entityChanged = true;
1761            if (changeEntity) {
1762                fEntityManager.endEntity();
1763                if (fCurrentEntity == null) {
1764                    throw new EOFException JavaDoc();
1765                }
1766                // handle the trailing edges
1767
if (fCurrentEntity.position == fCurrentEntity.count) {
1768                    load(0, true);
1769                }
1770            }
1771        }
1772        if (DEBUG_BUFFER) {
1773            System.out.print(")load, "+offset+": ");
1774            XMLEntityManager.print(fCurrentEntity);
1775            System.out.println();
1776        }
1777
1778        return entityChanged;
1779
1780    } // load(int, boolean):boolean
1781

1782
1783} // class XMLEntityScanner
1784

1785
Popular Tags