1 /*
2 * Portions Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
3 */
4
5 /*
6 * Copyright 2005 The Apache Software Foundation.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21
22 package com.sun.org.apache.xerces.internal.impl;
23
24 import com.sun.xml.internal.stream.XMLBufferListener;
25 import com.sun.xml.internal.stream.XMLEntityStorage;
26 import com.sun.xml.internal.stream.XMLInputFactoryImpl;
27 import com.sun.xml.internal.stream.dtd.DTDGrammarUtil;
28
29 import java.io.EOFException;
30 import java.io.IOException;
31 import javax.xml.stream.XMLInputFactory;
32 import javax.xml.stream.events.XMLEvent;
33 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
34 import com.sun.org.apache.xerces.internal.util.AugmentationsImpl;
35 import com.sun.org.apache.xerces.internal.util.XMLAttributesIteratorImpl;
36 import com.sun.org.apache.xerces.internal.util.XMLChar;
37 import com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
38 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
39 import com.sun.org.apache.xerces.internal.xni.QName;
40 import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
41 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
42 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
43 import com.sun.org.apache.xerces.internal.xni.XMLString;
44 import com.sun.org.apache.xerces.internal.xni.XNIException;
45 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
46 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
47 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
48 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentScanner;
49 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
50 import com.sun.org.apache.xerces.internal.xni.Augmentations;
51 import com.sun.org.apache.xerces.internal.impl.Constants;
52 import com.sun.org.apache.xerces.internal.impl.XMLEntityHandler;
53 import com.sun.org.apache.xerces.internal.util.SecurityManager;
54 import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
55 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
56 import javax.xml.stream.XMLStreamConstants;
57 import javax.xml.stream.events.XMLEvent;
58
59 /**
60 *
61 * This class is responsible for scanning the structure and content
62 * of document fragments.
63 *
64 * This class has been modified as per the new design which is more suited to
65 * efficiently build pull parser. Lot of improvements have been done and
66 * the code has been added to support stax functionality/features.
67 *
68 * @author Neeraj Bajaj SUN Microsystems
69 * @author K.Venugopal SUN Microsystems
70 * @author Glenn Marcy, IBM
71 * @author Andy Clark, IBM
72 * @author Arnaud Le Hors, IBM
73 * @author Eric Ye, IBM
74 * @author Sunitha Reddy, SUN Microsystems
75 *
76 */
77 public class XMLDocumentFragmentScannerImpl
78 extends XMLScanner
79 implements XMLDocumentScanner, XMLComponent, XMLEntityHandler, XMLBufferListener {
80
81 //
82 // Constants
83 //
84
85 protected int fElementAttributeLimit;
86
87 /** External subset resolver. **/
88 protected ExternalSubsetResolver fExternalSubsetResolver;
89
90 // scanner states
91
92 //XXX this should be divided into more states.
93 /** Scanner state: start of markup. */
94 protected static final int SCANNER_STATE_START_OF_MARKUP = 21;
95
96 /** Scanner state: content. */
97 protected static final int SCANNER_STATE_CONTENT = 22;
98
99 /** Scanner state: processing instruction. */
100 protected static final int SCANNER_STATE_PI = 23;
101
102 /** Scanner state: DOCTYPE. */
103 protected static final int SCANNER_STATE_DOCTYPE = 24;
104
105 /** Scanner state: XML Declaration */
106 protected static final int SCANNER_STATE_XML_DECL = 25;
107
108 /** Scanner state: root element. */
109 protected static final int SCANNER_STATE_ROOT_ELEMENT = 26;
110
111 /** Scanner state: comment. */
112 protected static final int SCANNER_STATE_COMMENT = 27;
113
114 /** Scanner state: reference. */
115 protected static final int SCANNER_STATE_REFERENCE = 28;
116
117 // <book type="hard"> reading attribute name 'type'
118 protected static final int SCANNER_STATE_ATTRIBUTE = 29;
119
120 // <book type="hard"> //reading attribute value.
121 protected static final int SCANNER_STATE_ATTRIBUTE_VALUE = 30;
122
123 /** Scanner state: trailing misc. USED BY DOCUMENT_SCANNER_IMPL*/
124 //protected static final int SCANNER_STATE_TRAILING_MISC = 32;
125
126 /** Scanner state: end of input. */
127 protected static final int SCANNER_STATE_END_OF_INPUT = 33;
128
129 /** Scanner state: terminated. */
130 protected static final int SCANNER_STATE_TERMINATED = 34;
131
132 /** Scanner state: CDATA section. */
133 protected static final int SCANNER_STATE_CDATA = 35;
134
135 /** Scanner state: Text declaration. */
136 protected static final int SCANNER_STATE_TEXT_DECL = 36;
137
138 /** Scanner state: Text declaration. */
139 protected static final int SCANNER_STATE_CHARACTER_DATA = 37;
140
141 //<book type="hard">foo</book>
142 protected static final int SCANNER_STATE_START_ELEMENT_TAG = 38;
143
144 //<book type="hard">foo</book> reading </book>
145 protected static final int SCANNER_STATE_END_ELEMENT_TAG = 39;
146
147 protected static final int SCANNER_STATE_CHAR_REFERENCE = 40;
148 protected static final int SCANNER_STATE_BUILT_IN_REFS = 41;
149
150 // feature identifiers
151
152
153 /** Feature identifier: notify built-in refereces. */
154 protected static final String NOTIFY_BUILTIN_REFS =
155 Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_BUILTIN_REFS_FEATURE;
156
157 /** Property identifier: entity resolver. */
158 protected static final String ENTITY_RESOLVER =
159 Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
160
161 // recognized features and properties
162
163 /** Recognized features. */
164 private static final String[] RECOGNIZED_FEATURES = {
165 NAMESPACES,
166 VALIDATION,
167 NOTIFY_BUILTIN_REFS,
168 NOTIFY_CHAR_REFS,
169 Constants.STAX_REPORT_CDATA_EVENT
170 };
171
172 /** Feature defaults. */
173 private static final Boolean[] FEATURE_DEFAULTS = {
174 Boolean.TRUE,
175 null,
176 Boolean.FALSE,
177 Boolean.FALSE,
178 Boolean.TRUE
179 };
180
181 /** Recognized properties. */
182 private static final String[] RECOGNIZED_PROPERTIES = {
183 SYMBOL_TABLE,
184 ERROR_REPORTER,
185 ENTITY_MANAGER,
186 };
187
188 /** Property defaults. */
189 private static final Object[] PROPERTY_DEFAULTS = {
190 null,
191 null,
192 null,
193 };
194
195 protected static final char [] cdata = {'[','C','D','A','T','A','['};
196 protected static final char [] xmlDecl = {'<','?','x','m','l'};
197 protected static final char [] endTag = {'<','/'};
198 // debugging
199
200 /** Debug scanner state. */
201 private static final boolean DEBUG_SCANNER_STATE = false;
202
203 /** Debug driver. */
204 private static final boolean DEBUG_DISPATCHER = false;
205
206 /** Debug content driver scanning. */
207 protected static final boolean DEBUG_START_END_ELEMENT = false;
208
209
210 /** Debug driver next */
211 protected static final boolean DEBUG_NEXT = false ;
212
213 /** Debug driver next */
214 protected static final boolean DEBUG = false;
215 protected static final boolean DEBUG_COALESCE = false;
216 //
217 // Data
218 //
219
220 // protected data
221
222 /** Document handler. */
223 protected XMLDocumentHandler fDocumentHandler;
224 protected int fScannerLastState ;
225
226 /** Entity Storage */
227 protected XMLEntityStorage fEntityStore;
228
229 /** Entity stack. */
230 protected int[] fEntityStack = new int[4];
231
232 /** Markup depth. */
233 protected int fMarkupDepth;
234
235 //is the element empty
236 protected boolean fEmptyElement ;
237
238 //track if we are reading attributes, this is usefule while
239 //there is a callback
240 protected boolean fReadingAttributes = false;
241
242 /** Scanner state. */
243 protected int fScannerState;
244
245 /** SubScanner state: inside scanContent method. */
246 protected boolean fInScanContent = false;
247 protected boolean fLastSectionWasCData = false;
248 protected boolean fLastSectionWasEntityReference = false;
249 protected boolean fLastSectionWasCharacterData = false;
250
251 /** has external dtd */
252 protected boolean fHasExternalDTD;
253
254 /** Standalone. */
255 protected boolean fStandalone;
256 protected String fVersion;
257
258 // element information
259
260 /** Current element. */
261 protected QName fCurrentElement;
262
263 /** Element stack. */
264 protected ElementStack fElementStack = new ElementStack();
265 protected ElementStack2 fElementStack2 = new ElementStack2();
266
267 // other info
268
269 /** Document system identifier.
270 * REVISIT: So what's this used for? - NG
271 * protected String fDocumentSystemId;
272 ******/
273
274 protected String fPITarget ;
275
276 //xxx do we need to create an extra XMLString object... look for using fTempString for collecting all the data values
277 protected XMLString fPIData = new XMLString();
278
279 // features
280
281
282 /** Notify built-in references. */
283 protected boolean fNotifyBuiltInRefs = false;
284
285 //STAX related properties
286 //defaultValues.
287 protected boolean fReplaceEntityReferences = true;
288 protected boolean fSupportExternalEntities = false;
289 protected boolean fReportCdataEvent = false ;
290 protected boolean fIsCoalesce = false ;
291 protected String fDeclaredEncoding = null;
292
293 // drivers
294
295 /** Active driver. */
296 protected Driver fDriver;
297
298 /** Content driver. */
299 protected Driver fContentDriver = createContentDriver();
300
301 // temporary variables
302
303 /** Element QName. */
304 protected QName fElementQName = new QName();
305
306 /** Attribute QName. */
307 protected QName fAttributeQName = new QName();
308
309 /**
310 * CHANGED: Using XMLAttributesIteratorImpl instead of XMLAttributesImpl. This class
311 * implements Iterator interface so we can directly give Attributes in the form of
312 * iterator.
313 */
314 protected XMLAttributesIteratorImpl fAttributes = new XMLAttributesIteratorImpl();
315
316
317 /** String. */
318 protected XMLString fTempString = new XMLString();
319
320 /** String. */
321 protected XMLString fTempString2 = new XMLString();
322
323 /** Array of 3 strings. */
324 private String[] fStrings = new String[3];
325
326 /** Making the buffer accesible to derived class -- String buffer. */
327 protected XMLStringBuffer fStringBuffer = new XMLStringBuffer();
328
329 /** Making the buffer accesible to derived class -- String buffer. */
330 protected XMLStringBuffer fStringBuffer2 = new XMLStringBuffer();
331
332 /** stores character data. */
333 /** Making the buffer accesible to derived class -- stores PI data */
334 protected XMLStringBuffer fContentBuffer = new XMLStringBuffer();
335
336 /** Single character array. */
337 private final char[] fSingleChar = new char[1];
338 private String fCurrentEntityName = null;
339
340 // New members
341 protected boolean fScanToEnd = false;
342
343 protected DTDGrammarUtil dtdGrammarUtil= null;
344
345 protected boolean fAddDefaultAttr = false;
346
347 protected boolean foundBuiltInRefs = false;
348
349 protected SecurityManager fSecurityManager = null;
350
351 //skip element algorithm
352 static final short MAX_DEPTH_LIMIT = 5 ;
353 static final short ELEMENT_ARRAY_LENGTH = 200 ;
354 static final short MAX_POINTER_AT_A_DEPTH = 4 ;
355 static final boolean DEBUG_SKIP_ALGORITHM = false;
356 //create a elemnet array of length equal to ELEMENT_ARRAY_LENGTH
357 String [] fElementArray = new String[ELEMENT_ARRAY_LENGTH] ;
358 //pointer location where last element was skipped
359 short fLastPointerLocation = 0 ;
360 short fElementPointer = 0 ;
361 //2D array to store pointer info
362 short [] [] fPointerInfo = new short[MAX_DEPTH_LIMIT] [MAX_POINTER_AT_A_DEPTH] ;
363 protected String fElementRawname ;
364 protected boolean fShouldSkip = false;
365 protected boolean fAdd = false ;
366 protected boolean fSkip = false;
367
368 /** Reusable Augmentations. */
369 private Augmentations fTempAugmentations = null;
370 //
371 // Constructors
372 //
373
374 /** Default constructor. */
375 public XMLDocumentFragmentScannerImpl() {
376 } // <init>()
377
378 //
379 // XMLDocumentScanner methods
380 //
381
382 /**
383 * Sets the input source.
384 *
385 * @param inputSource The input source.
386 *
387 * @throws IOException Thrown on i/o error.
388 */
389 public void setInputSource(XMLInputSource inputSource) throws IOException {
390 fEntityManager.setEntityHandler(this);
391 fEntityManager.startEntity("$fragment$", inputSource, false, true);
392 // fDocumentSystemId = fEntityManager.expandSystemId(inputSource.getSystemId());
393 } // setInputSource(XMLInputSource)
394
395 /**
396 * Scans a document.
397 *
398 * @param complete True if the scanner should scan the document
399 * completely, pushing all events to the registered
400 * document handler. A value of false indicates that
401 * that the scanner should only scan the next portion
402 * of the document and return. A scanner instance is
403 * permitted to completely scan a document if it does
404 * not support this "pull" scanning model.
405 *
406 * @return True if there is more to scan, false otherwise.
407 */
408 /* public boolean scanDocument(boolean complete)
409 throws IOException, XNIException {
410
411 // keep dispatching "events"
412 fEntityManager.setEntityHandler(this);
413
414 return true;
415
416 } // scanDocument(boolean):boolean
417 */
418
419 public boolean scanDocument(boolean complete)
420 throws IOException, XNIException {
421
422 // keep dispatching "events"
423 fEntityManager.setEntityHandler(this);
424 //System.out.println(" get Document Handler in NSDocumentHandler " + fDocumentHandler );
425
426 int event = next();
427 do {
428 switch (event) {
429 case XMLStreamConstants.START_DOCUMENT :
430 //fDocumentHandler.startDocument(fEntityManager.getEntityScanner(),fEntityManager.getEntityScanner().getVersion(),fNamespaceContext,null);// not able to get
431 break;
432 case XMLStreamConstants.START_ELEMENT :
433 //System.out.println(" in scann element");
434 //fDocumentHandler.startElement(getElementQName(),fAttributes,null);
435 break;
436 case XMLStreamConstants.CHARACTERS :
437 fDocumentHandler.characters(getCharacterData(),null);
438 break;
439 case XMLStreamConstants.SPACE:
440 //check if getCharacterData() is the right function to retrieve ignorableWhitespace information.
441 //System.out.println("in the space");
442 //fDocumentHandler.ignorableWhitespace(getCharacterData(), null);
443 break;
444 case XMLStreamConstants.ENTITY_REFERENCE :
445 //entity reference callback are given in startEntity
446 break;
447 case XMLStreamConstants.PROCESSING_INSTRUCTION :
448 fDocumentHandler.processingInstruction(getPITarget(),getPIData(),null);
449 break;
450 case XMLStreamConstants.COMMENT :
451 //System.out.println(" in COMMENT of the XMLNSDocumentScannerImpl");
452 fDocumentHandler.comment(getCharacterData(),null);
453 break;
454 case XMLStreamConstants.DTD :
455 //all DTD related callbacks are handled in DTDScanner.
456 //1. Stax doesn't define DTD states as it does for XML Document.
457 //therefore we don't need to take care of anything here. So Just break;
458 break;
459 case XMLStreamConstants.CDATA:
460 fDocumentHandler.startCDATA(null);
461 //xxx: check if CDATA values comes from getCharacterData() function
462 fDocumentHandler.characters(getCharacterData(),null);
463 fDocumentHandler.endCDATA(null);
464 //System.out.println(" in CDATA of the XMLNSDocumentScannerImpl");
465 break;
466 case XMLStreamConstants.NOTATION_DECLARATION :
467 break;
468 case XMLStreamConstants.ENTITY_DECLARATION :
469 break;
470 case XMLStreamConstants.NAMESPACE :
471 break;
472 case XMLStreamConstants.ATTRIBUTE :
473 break;
474 case XMLStreamConstants.END_ELEMENT :
475 //do not give callback here.
476 //this callback is given in scanEndElement function.
477 //fDocumentHandler.endElement(getElementQName(),null);
478 break;
479 default :
480 throw new InternalError("processing event: " + event);
481
482 }
483 //System.out.println("here in before calling next");
484 event = next();
485 //System.out.println("here in after calling next");
486 } while (event!=XMLStreamConstants.END_DOCUMENT && complete);
487
488 if(event == XMLStreamConstants.END_DOCUMENT) {
489 fDocumentHandler.endDocument(null);
490 return false;
491 }
492
493 return true;
494
495 } // scanDocument(boolean):boolean
496
497
498
499 public com.sun.org.apache.xerces.internal.xni.QName getElementQName(){
500 if(fScannerLastState == XMLEvent.END_ELEMENT){
501 fElementQName.setValues(fElementStack.getLastPoppedElement());
502 }
503 return fElementQName ;
504 }
505
506 /** return the next state on the input
507 * @return int
508 */
509
510 public int next() throws IOException, XNIException {
511 return fDriver.next();
512 }
513
514 //
515 // XMLComponent methods
516 //
517
518 /**
519 * Resets the component. The component can query the component manager
520 * about any features and properties that affect the operation of the
521 * component.
522 *
523 * @param componentManager The component manager.
524 *
525 * @throws SAXException Thrown by component on initialization error.
526 * For example, if a feature or property is
527 * required for the operation of the component, the
528 * component manager may throw a
529 * SAXNotRecognizedException or a
530 * SAXNotSupportedException.
531 */
532
533 public void reset(XMLComponentManager componentManager)
534 throws XMLConfigurationException {
535
536 super.reset(componentManager);
537
538 // other settings
539 // fDocumentSystemId = null;
540
541 // sax features
542 //fAttributes.setNamespaces(fNamespaces);
543
544 // xerces features
545 try{
546 fReportCdataEvent = componentManager.getFeature(Constants.STAX_REPORT_CDATA_EVENT);
547 } catch (XMLConfigurationException e) {
548 e.printStackTrace();
549 //note that default value of this feature is true in stax configuration
550 fReportCdataEvent = true;
551 }
552
553 try {
554 fSecurityManager = (SecurityManager)componentManager.getProperty(Constants.SECURITY_MANAGER);
555 } catch (XMLConfigurationException e) {
556 fSecurityManager = null;
557 }
558 fElementAttributeLimit = (fSecurityManager != null)?fSecurityManager.getElementAttrLimit():0;
559
560 try {
561 fNotifyBuiltInRefs = componentManager.getFeature(NOTIFY_BUILTIN_REFS);
562 } catch (XMLConfigurationException e) {
563 fNotifyBuiltInRefs = false;
564 }
565
566 try {
567 Object resolver = componentManager.getProperty(ENTITY_RESOLVER);
568 fExternalSubsetResolver = (resolver instanceof ExternalSubsetResolver) ?
569 (ExternalSubsetResolver) resolver : null;
570 } catch (XMLConfigurationException e) {
571 fExternalSubsetResolver = null;
572 }
573
574 // initialize vars
575 fMarkupDepth = 0;
576 fCurrentElement = null;
577 fElementStack.clear();
578 fHasExternalDTD = false;
579 fStandalone = false;
580 fInScanContent = false;
581 //skipping algorithm
582 fShouldSkip = false;
583 fAdd = false;
584 fSkip = false;
585
586 //attribute
587 fReadingAttributes = false;
588 //xxx: external entities are supported in Xerces
589 // it would be good to define feature for this case
590 fSupportExternalEntities = true;
591 fReplaceEntityReferences = true;
592 fIsCoalesce = false;
593
594 // setup Driver
595 setScannerState(SCANNER_STATE_CONTENT);
596 setDriver(fContentDriver);
597 fEntityStore = fEntityManager.getEntityStore();
598
599 dtdGrammarUtil = null;
600
601
602 //fEntityManager.test();
603 } // reset(XMLComponentManager)
604
605
606 public void reset(PropertyManager propertyManager){
607
608 super.reset(propertyManager);
609
610 // other settings
611 // fDocumentSystemId = null;
612 fNamespaces = ((Boolean)propertyManager.getProperty(XMLInputFactory.IS_NAMESPACE_AWARE)).booleanValue();
613 fNotifyBuiltInRefs = false ;
614
615 // initialize vars
616 fMarkupDepth = 0;
617 fCurrentElement = null;
618 fShouldSkip = false;
619 fAdd = false;
620 fSkip = false;
621 fElementStack.clear();
622 //fElementStack2.clear();
623 fHasExternalDTD = false;
624 fStandalone = false;
625 //fReplaceEntityReferences = true;
626 //fSupportExternalEntities = true;
627 Boolean bo = (Boolean)propertyManager.getProperty(XMLInputFactoryImpl.IS_REPLACING_ENTITY_REFERENCES);
628 fReplaceEntityReferences = bo.booleanValue();
629 bo = (Boolean)propertyManager.getProperty(XMLInputFactoryImpl.IS_SUPPORTING_EXTERNAL_ENTITIES);
630 fSupportExternalEntities = bo.booleanValue();
631 Boolean cdata = (Boolean)propertyManager.getProperty(Constants.ZEPHYR_PROPERTY_PREFIX + Constants.STAX_REPORT_CDATA_EVENT) ;
632 if(cdata != null)
633 fReportCdataEvent = cdata.booleanValue() ;
634 Boolean coalesce = (Boolean)propertyManager.getProperty(XMLInputFactory.IS_COALESCING) ;
635 if(coalesce != null)
636 fIsCoalesce = coalesce.booleanValue();
637 fReportCdataEvent = fIsCoalesce ? false : (fReportCdataEvent && true) ;
638 //if fIsCoalesce is set to true, set the value of fReplaceEntityReferences to true,
639 //if fIsCoalesce is set to false, take the value of fReplaceEntityReferences as set by application
640 fReplaceEntityReferences = fIsCoalesce ? true : fReplaceEntityReferences;
641 // setup Driver
642 //we dont need to do this -- nb.
643 //setScannerState(SCANNER_STATE_CONTENT);
644 //setDriver(fContentDriver);
645 fEntityStore = fEntityManager.getEntityStore();
646 //fEntityManager.test();
647
648 dtdGrammarUtil = null;
649
650 } // reset(XMLComponentManager)
651
652 /**
653 * Returns a list of feature identifiers that are recognized by
654 * this component. This method may return null if no features
655 * are recognized by this component.
656 */
657 public String[] getRecognizedFeatures() {
658 return (String[])(RECOGNIZED_FEATURES.clone());
659 } // getRecognizedFeatures():String[]
660
661 /**
662 * Sets the state of a feature. This method is called by the component
663 * manager any time after reset when a feature changes state.
664 * <p>
665 * <strong>Note:</strong> Components should silently ignore features
666 * that do not affect the operation of the component.
667 *
668 * @param featureId The feature identifier.
669 * @param state The state of the feature.
670 *
671 * @throws SAXNotRecognizedException The component should not throw
672 * this exception.
673 * @throws SAXNotSupportedException The component should not throw
674 * this exception.
675 */
676 public void setFeature(String featureId, boolean state)
677 throws XMLConfigurationException {
678
679 super.setFeature(featureId, state);
680
681 // Xerces properties
682 if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) {
683 String feature = featureId.substring(Constants.XERCES_FEATURE_PREFIX.length());
684 if (feature.equals(Constants.NOTIFY_BUILTIN_REFS_FEATURE)) {
685 fNotifyBuiltInRefs = state;
686 }
687 }
688
689 } // setFeature(String,boolean)
690
691 /**
692 * Returns a list of property identifiers that are recognized by
693 * this component. This method may return null if no properties
694 * are recognized by this component.
695 */
696 public String[] getRecognizedProperties() {
697 return (String[])(RECOGNIZED_PROPERTIES.clone());
698 } // getRecognizedProperties():String[]
699
700 /**
701 * Sets the value of a property. This method is called by the component
702 * manager any time after reset when a property changes value.
703 * <p>
704 * <strong>Note:</strong> Components should silently ignore properties
705 * that do not affect the operation of the component.
706 *
707 * @param propertyId The property identifier.
708 * @param value The value of the property.
709 *
710 * @throws SAXNotRecognizedException The component should not throw
711 * this exception.
712 * @throws SAXNotSupportedException The component should not throw
713 * this exception.
714 */
715 public void setProperty(String propertyId, Object value)
716 throws XMLConfigurationException {
717
718 super.setProperty(propertyId, value);
719
720 // Xerces properties
721 if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) {
722 final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length();
723 if (suffixLength == Constants.ENTITY_MANAGER_PROPERTY.length() &&
724 propertyId.endsWith(Constants.ENTITY_MANAGER_PROPERTY)) {
725 fEntityManager = (XMLEntityManager)value;
726 return;
727 }
728 if (suffixLength == Constants.ENTITY_RESOLVER_PROPERTY.length() &&
729 propertyId.endsWith(Constants.ENTITY_RESOLVER_PROPERTY)) {
730 fExternalSubsetResolver = (value instanceof ExternalSubsetResolver) ?
731 (ExternalSubsetResolver) value : null;
732 return;
733 }
734 }
735
736
737 // Xerces properties
738 if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) {
739 String property = propertyId.substring(Constants.XERCES_PROPERTY_PREFIX.length());
740 if (property.equals(Constants.ENTITY_MANAGER_PROPERTY)) {
741 fEntityManager = (XMLEntityManager)value;
742 }
743 return;
744 }
745
746 } // setProperty(String,Object)
747
748 /**
749 * Returns the default state for a feature, or null if this
750 * component does not want to report a default value for this
751 * feature.
752 *
753 * @param featureId The feature identifier.
754 *
755 * @since Xerces 2.2.0
756 */
757 public Boolean getFeatureDefault(String featureId) {
758 for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
759 if (RECOGNIZED_FEATURES[i].equals(featureId)) {
760 return FEATURE_DEFAULTS[i];
761 }
762 }
763 return null;
764 } // getFeatureDefault(String):Boolean
765
766 /**
767 * Returns the default state for a property, or null if this
768 * component does not want to report a default value for this
769 * property.
770 *
771 * @param propertyId The property identifier.
772 *
773 * @since Xerces 2.2.0
774 */
775 public Object getPropertyDefault(String propertyId) {
776 for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
777 if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
778 return PROPERTY_DEFAULTS[i];
779 }
780 }
781 return null;
782 } // getPropertyDefault(String):Object
783
784 //
785 // XMLDocumentSource methods
786 //
787
788 /**
789 * setDocumentHandler
790 *
791 * @param documentHandler
792 */
793 public void setDocumentHandler(XMLDocumentHandler documentHandler) {
794 fDocumentHandler = documentHandler;
795 //System.out.println(" In Set DOCUMENT HANDLER" + fDocumentHandler + " scanner =" + this);
796 } // setDocumentHandler(XMLDocumentHandler)
797
798
799 /** Returns the document handler */
800 public XMLDocumentHandler getDocumentHandler(){
801 return fDocumentHandler;
802 }
803
804 //
805 // XMLEntityHandler methods
806 //
807
808 /**
809 * This method notifies of the start of an entity. The DTD has the
810 * pseudo-name of "[dtd]" parameter entity names start with '%'; and
811 * general entities are just specified by their name.
812 *
813 * @param name The name of the entity.
814 * @param identifier The resource identifier.
815 * @param encoding The auto-detected IANA encoding name of the entity
816 * stream. This value will be null in those situations
817 * where the entity encoding is not auto-detected (e.g.
818 * internal entities or a document entity that is
819 * parsed from a java.io.Reader).
820 *
821 * @throws XNIException Thrown by handler to signal an error.
822 */
823 public void startEntity(String name,
824 XMLResourceIdentifier identifier,
825 String encoding, Augmentations augs) throws XNIException {
826
827 // keep track of this entity before fEntityDepth is increased
828 if (fEntityDepth == fEntityStack.length) {
829 int[] entityarray = new int[fEntityStack.length * 2];
830 System.arraycopy(fEntityStack, 0, entityarray, 0, fEntityStack.length);
831 fEntityStack = entityarray;
832 }
833 fEntityStack[fEntityDepth] = fMarkupDepth;
834
835 super.startEntity(name, identifier, encoding, augs);
836
837 // WFC: entity declared in external subset in standalone doc
838 if(fStandalone && fEntityStore.isEntityDeclInExternalSubset(name)) {
839 reportFatalError("MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE",
840 new Object[]{name});
841 }
842
843 /** we are not calling the handlers yet.. */
844 // call handler
845 if (fDocumentHandler != null && !fScanningAttribute) {
846 if (!name.equals("[xml]")) {
847 fDocumentHandler.startGeneralEntity(name, identifier, encoding, null);
848 }
849 }
850
851 } // startEntity(String,XMLResourceIdentifier,String)
852
853 /**
854 * This method notifies the end of an entity. The DTD has the pseudo-name
855 * of "[dtd]" parameter entity names start with '%'; and general entities
856 * are just specified by their name.
857 *
858 * @param name The name of the entity.
859 *
860 * @throws XNIException Thrown by handler to signal an error.
861 */
862 public void endEntity(String name, Augmentations augs) throws IOException, XNIException {
863
864 /**
865 * // flush possible pending output buffer - see scanContent
866 * if (fInScanContent && fStringBuffer.length != 0
867 * && fDocumentHandler != null) {
868 * fDocumentHandler.characters(fStringBuffer, null);
869 * fStringBuffer.length = 0; // make sure we know it's been flushed
870 * }
871 */
872 super.endEntity(name, augs);
873
874 // make sure markup is properly balanced
875 if (fMarkupDepth != fEntityStack[fEntityDepth]) {
876 reportFatalError("MarkupEntityMismatch", null);
877 }
878
879 /**/
880 // call handler
881 if (fDocumentHandler != null && !fScanningAttribute) {
882 if (!name.equals("[xml]")) {
883 fDocumentHandler.endGeneralEntity(name, null);
884 }
885 }
886
887
888 } // endEntity(String)
889
890 //
891 // Protected methods
892 //
893
894 // Driver factory methods
895
896 /** Creates a content Driver. */
897 protected Driver createContentDriver() {
898 return new FragmentContentDriver();
899 } // createContentDriver():Driver
900
901 // scanning methods
902
903 /**
904 * Scans an XML or text declaration.
905 * <p>
906 * <pre>
907 * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
908 * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
909 * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" )
910 * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
911 * [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'")
912 * | ('"' ('yes' | 'no') '"'))
913 *
914 * [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
915 * </pre>
916 *
917 * @param scanningTextDecl True if a text declaration is to
918 * be scanned instead of an XML
919 * declaration.
920 */
921 protected void scanXMLDeclOrTextDecl(boolean scanningTextDecl)
922 throws IOException, XNIException {
923
924 // scan decl
925 super.scanXMLDeclOrTextDecl(scanningTextDecl, fStrings);
926 fMarkupDepth--;
927
928 // pseudo-attribute values
929 String version = fStrings[0];
930 String encoding = fStrings[1];
931 String standalone = fStrings[2];
932 fDeclaredEncoding = encoding;
933 // set standalone
934 fStandalone = standalone != null && standalone.equals("yes");
935 ///xxx see where its used.. this is not used anywhere. it may be useful for entity to store this information
936 //but this information is only related with Document Entity.
937 fEntityManager.setStandalone(fStandalone);
938
939
940 // call handler
941 if (fDocumentHandler != null) {
942 if (scanningTextDecl) {
943 fDocumentHandler.textDecl(version, encoding, null);
944 } else {
945 fDocumentHandler.xmlDecl(version, encoding, standalone, null);
946 }
947 }
948
949 if(version != null){
950 fEntityScanner.setVersion(version);
951 fEntityScanner.setXMLVersion(version);
952 }
953 // set encoding on reader, only if encoding was not specified by the application explicitly
954 if (encoding != null && !fEntityScanner.getCurrentEntity().isEncodingExternallySpecified()) {
955 fEntityScanner.setEncoding(encoding);
956 }
957
958 } // scanXMLDeclOrTextDecl(boolean)
959
960 public String getPITarget(){
961 return fPITarget ;
962 }
963
964 public XMLStringBuffer getPIData(){
965 return fContentBuffer ;
966 }
967
968 //XXX: why not this function behave as per the state of the parser?
969 public XMLString getCharacterData(){
970 if(fUsebuffer){
971 return fContentBuffer ;
972 }else{
973 return fTempString;
974 }
975
976 }
977
978
979 /**
980 * Scans a processing data. This is needed to handle the situation
981 * where a document starts with a processing instruction whose
982 * target name <em>starts with</em> "xml". (e.g. xmlfoo)
983 *
984 * @param target The PI target
985 * @param data The XMLStringBuffer to fill in with the data
986 */
987 protected void scanPIData(String target, XMLStringBuffer data)
988 throws IOException, XNIException {
989
990 super.scanPIData(target, data);
991
992 //set the PI target and values
993 fPITarget = target ;
994
995 fMarkupDepth--;
996
997 } // scanPIData(String)
998
999 /**
1000 * Scans a comment.
1001 * <p>
1002 * <pre>
1003 * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
1004 * </pre>
1005 * <p>
1006 * <strong>Note:</strong> Called after scanning past '<!--'
1007 */
1008 protected void scanComment() throws IOException, XNIException {
1009 fContentBuffer.clear();
1010 scanComment(fContentBuffer);
1011 //getTextCharacters can also be called for reading comments
1012 fUsebuffer = true;
1013 fMarkupDepth--;
1014
1015 } // scanComment()
1016
1017 //xxx value returned by this function may not remain valid if another event is scanned.
1018 public String getComment(){
1019 return fContentBuffer.toString();
1020 }
1021
1022 void addElement(String rawname){
1023 if(fElementPointer < ELEMENT_ARRAY_LENGTH){
1024 //storing element raw name in a linear list of array
1025 fElementArray[fElementPointer] = rawname ;
1026 //storing elemnetPointer for particular element depth
1027
1028 if(DEBUG_SKIP_ALGORITHM){
1029 StringBuffer sb = new StringBuffer() ;
1030 sb.append(" Storing element information ") ;
1031 sb.append(" fElementPointer = " + fElementPointer) ;
1032 sb.append(" fElementRawname = " + fElementQName.rawname) ;
1033 sb.append(" fElementStack.fDepth = " + fElementStack.fDepth);
1034 System.out.println(sb.toString()) ;
1035 }
1036
1037 //store pointer information only when element depth is less MAX_DEPTH_LIMIT
1038 if(fElementStack.fDepth < MAX_DEPTH_LIMIT){
1039 short column = storePointerForADepth(fElementPointer);
1040 if(column > 0){
1041 short pointer = getElementPointer((short)fElementStack.fDepth, (short)(column - 1) );
1042 //identity comparison shouldn't take much time and we can rely on this
1043 //since its guaranteed to have same object id for same string.
1044 if(rawname == fElementArray[pointer]){
1045 fShouldSkip = true ;
1046 fLastPointerLocation = pointer ;
1047 //reset the things and return.
1048 resetPointer((short)fElementStack.fDepth , column) ;
1049 fElementArray[fElementPointer] = null ;
1050 return ;
1051 }else{
1052 fShouldSkip = false ;
1053 }
1054 }
1055 }
1056 fElementPointer++ ;
1057 }
1058 }
1059
1060
1061 void resetPointer(short depth, short column){
1062 fPointerInfo[depth] [column] = (short)0;
1063 }
1064
1065 //returns column information at which pointer was stored.
1066 short storePointerForADepth(short elementPointer){
1067 short depth = (short) fElementStack.fDepth ;
1068
1069 //Stores element pointer locations at particular depth , only 4 pointer locations
1070 //are stored at particular depth for now.
1071 for(short i = 0 ; i < MAX_POINTER_AT_A_DEPTH ; i++){
1072
1073 if(canStore(depth, i)){
1074 fPointerInfo[depth][i] = elementPointer ;
1075 if(DEBUG_SKIP_ALGORITHM){
1076 StringBuffer sb = new StringBuffer() ;
1077 sb.append(" Pointer information ") ;
1078 sb.append(" fElementPointer = " + fElementPointer) ;
1079 sb.append(" fElementStack.fDepth = " + fElementStack.fDepth);
1080 sb.append(" column = " + i ) ;
1081 System.out.println(sb.toString()) ;
1082 }
1083 return i;
1084 }
1085 //else
1086 //pointer was not stored because we reached the limit
1087 }
1088 return -1 ;
1089 }
1090
1091 boolean canStore(short depth, short column){
1092 //colum = 0 , means first element at particular depth
1093 //column = 1, means second element at particular depth
1094 // calle should make sure that it doesn't call for value outside allowed co-ordinates
1095 return fPointerInfo[depth][column] == 0 ? true : false ;
1096 }
1097
1098
1099 short getElementPointer(short depth, short column){
1100 //colum = 0 , means first element at particular depth
1101 //column = 1, means second element at particular depth
1102 // calle should make sure that it doesn't call for value outside allowed co-ordinates
1103 return fPointerInfo[depth][column] ;
1104 }
1105
1106 //this function assumes that string passed is not null and skips
1107 //the following string from the buffer this makes sure
1108 boolean skipFromTheBuffer(String rawname) throws IOException{
1109 if(fEntityScanner.skipString(rawname)){
1110 char c = (char)fEntityScanner.peekChar() ;
1111 //If the start element was completely skipped we should encounter either ' '(space),
1112 //or '/' (in case of empty element) or '>'
1113 if( c == ' ' || c == '/' || c == '>'){
1114 fElementRawname = rawname ;
1115 return true ;
1116 } else{
1117 return false;
1118 }
1119 } else
1120 return false ;
1121 }
1122
1123 boolean skipQElement(String rawname) throws IOException{
1124
1125 final int c = fEntityScanner.getChar(rawname.length());
1126 //if this character is still valid element name -- this means string can't match
1127 if(XMLChar.isName(c)){
1128 return false;
1129 }else{
1130 return fEntityScanner.skipString(rawname);
1131 }
1132 }
1133
1134 protected boolean skipElement() throws IOException {
1135
1136 if(!fShouldSkip) return false ;
1137
1138 if(fLastPointerLocation != 0){
1139 //Look at the next element stored in the array list.. we might just get a match.
1140 String rawname = fElementArray[fLastPointerLocation + 1] ;
1141 if(rawname != null && skipFromTheBuffer(rawname)){
1142 fLastPointerLocation++ ;
1143 if(DEBUG_SKIP_ALGORITHM){
1144 System.out.println("Element " + fElementRawname + " was SKIPPED at pointer location = " + fLastPointerLocation);
1145 }
1146 return true ;
1147 } else{
1148 //reset it back to zero... we haven't got the correct subset yet.
1149 fLastPointerLocation = 0 ;
1150
1151 }
1152 }
1153 //xxx: we can put some logic here as from what column it should start looking
1154 //for now we always start at 0
1155 //fallback to tolerant algorithm, it would look for differnt element stored at different
1156 //depth and get us the pointer location.
1157 return fShouldSkip && skipElement((short)0);
1158
1159 }
1160
1161 //start of the column at which it should try searching
1162 boolean skipElement(short column) throws IOException {
1163 short depth = (short)fElementStack.fDepth ;
1164
1165 if(depth > MAX_DEPTH_LIMIT){
1166 return fShouldSkip = false ;
1167 }
1168 for(short i = column ; i < MAX_POINTER_AT_A_DEPTH ; i++){
1169 short pointer = getElementPointer(depth , i ) ;
1170
1171 if(pointer == 0){
1172 return fShouldSkip = false ;
1173 }
1174
1175 if(fElementArray[pointer] != null && skipFromTheBuffer(fElementArray[pointer])){
1176 if(DEBUG_SKIP_ALGORITHM){
1177 System.out.println();
1178 System.out.println("Element " + fElementRawname + " was SKIPPED at depth = " + fElementStack.fDepth + " column = " + column );
1179 System.out.println();
1180 }
1181 fLastPointerLocation = pointer ;
1182 return fShouldSkip = true ;
1183 }
1184 }
1185 return fShouldSkip = false ;
1186 }
1187
1188 /**
1189 * Scans a start element. This method will handle the binding of
1190 * namespace information and notifying the handler of the start
1191 * of the element.
1192 * <p>
1193 * <pre>
1194 * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
1195 * [40] STag ::= '<' Name (S Attribute)* S? '>'
1196 * </pre>
1197 * <p>
1198 * <strong>Note:</strong> This method assumes that the leading
1199 * '<' character has been consumed.
1200 * <p>
1201 * <strong>Note:</strong> This method uses the fElementQName and
1202 * fAttributes variables. The contents of these variables will be
1203 * destroyed. The caller should copy important information out of
1204 * these variables before calling this method.
1205 * NB: Content in fAttributes is valid only till the state of the parser is XMLEvent.START_ELEMENT
1206 *
1207 * @return True if element is empty. (i.e. It matches
1208 * production [44].
1209 */
1210 // fElementQName will have the details of element just read..
1211 // fAttributes will have the details of all the attributes.
1212 protected boolean scanStartElement()
1213 throws IOException, XNIException {
1214
1215 if (DEBUG_START_END_ELEMENT) System.out.println( this.getClass().toString() + ">>> scanStartElement()");
1216 //when skipping is true and no more elements should be added
1217 if(fSkip && !fAdd){
1218 //get the stored element -- if everything goes right this should match the
1219 //token in the buffer
1220
1221 QName name = fElementStack.getNext();
1222
1223 if(DEBUG_SKIP_ALGORITHM){
1224 System.out.println("Trying to skip String = " + name.rawname);
1225 }
1226
1227 //Be conservative -- if skipping fails -- stop.
1228 fSkip = fEntityScanner.skipString(name.rawname);
1229
1230 if(fSkip){
1231 if(DEBUG_SKIP_ALGORITHM){
1232 System.out.println("Element SUCESSFULLY skipped = " + name.rawname);
1233 }
1234 fElementStack.push();
1235 fElementQName = name;
1236 }else{
1237 //if skipping fails reposition the stack or fallback to normal way of processing
1238 fElementStack.reposition();
1239 if(DEBUG_SKIP_ALGORITHM){
1240 System.out.println("Element was NOT skipped, REPOSITIONING stack" );
1241 }
1242 }
1243 }
1244
1245 //we are still at the stage of adding elements
1246 //the elements were not matched or
1247 //fSkip is not set to true
1248 if(!fSkip || fAdd){
1249 //get the next element from the stack
1250 fElementQName = fElementStack.nextElement();
1251 // name
1252 if (fNamespaces) {
1253 fEntityScanner.scanQName(fElementQName);
1254 } else {
1255 String name = fEntityScanner.scanName();
1256 fElementQName.setValues(null, name, name, null);
1257 }
1258
1259 if(DEBUG)System.out.println("Element scanned in start element is " + fElementQName.toString());
1260 if(DEBUG_SKIP_ALGORITHM){
1261 if(fAdd){
1262 System.out.println("Elements are being ADDED -- elemet added is = " + fElementQName.rawname + " at count = " + fElementStack.fCount);
1263 }
1264 }
1265
1266 }
1267
1268 //when the elements are being added , we need to check if we are set for skipping the elements
1269 if(fAdd){
1270 //this sets the value of fAdd variable
1271 fElementStack.matchElement(fElementQName);
1272 }
1273
1274
1275 //xxx: We dont need another pointer, fCurrentElement, we can use fElementQName
1276 fCurrentElement = fElementQName;
1277
1278 String rawname = fElementQName.rawname;
1279
1280 fEmptyElement = false;
1281
1282 fAttributes.removeAllAttributes();
1283
1284 if(!seekCloseOfStartTag()){
1285 fReadingAttributes = true;
1286 fAttributeCacheUsedCount =0;
1287 fStringBufferIndex =0;
1288 fAddDefaultAttr = true;
1289 do {
1290 scanAttribute(fAttributes);
1291 if (fSecurityManager != null && fAttributes.getLength() > fElementAttributeLimit){
1292 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1293 "ElementAttributeLimit",
1294 new Object[]{rawname, new Integer(fAttributes.getLength()) },
1295 XMLErrorReporter.SEVERITY_FATAL_ERROR );
1296 }
1297
1298 } while (!seekCloseOfStartTag());
1299 fReadingAttributes=false;
1300 }
1301
1302 if (fEmptyElement) {
1303 //decrease the markup depth..
1304 fMarkupDepth--;
1305
1306 // check that this element was opened in the same entity
1307 if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
1308 reportFatalError("ElementEntityMismatch",
1309 new Object[]{fCurrentElement.rawname});
1310 }
1311 // call handler
1312 if (fDocumentHandler != null) {
1313 fDocumentHandler.emptyElement(fElementQName, fAttributes, null);
1314 }
1315
1316 //We should not be popping out the context here in endELement becaause the namespace context is still
1317 //valid when parser is at the endElement state.
1318 //if (fNamespaces) {
1319 // fNamespaceContext.popContext();
1320 //}
1321
1322 //pop the element off the stack..
1323 fElementStack.popElement();
1324
1325 } else {
1326
1327 if(dtdGrammarUtil != null)
1328 dtdGrammarUtil.startElement(fElementQName, fAttributes);
1329 if(fDocumentHandler != null){
1330 //complete element and attributes are traversed in this function so we can send a callback
1331 //here.
1332 //<strong>we shouldn't be sending callback in scanDocument()</strong>
1333 fDocumentHandler.startElement(fElementQName, fAttributes, null);
1334 }
1335 }
1336
1337
1338 if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() + "<<< scanStartElement(): "+fEmptyElement);
1339 return fEmptyElement;
1340
1341 } // scanStartElement():boolean
1342
1343 /**
1344 * Looks for the close of start tag, i.e. if it finds '>' or '/>'
1345 * Characters are consumed.
1346 */
1347 protected boolean seekCloseOfStartTag() throws IOException, XNIException {
1348 // spaces
1349 boolean sawSpace = fEntityScanner.skipSpaces();
1350
1351 // end tag?
1352 final int c = fEntityScanner.peekChar();
1353 if (c == '>') {
1354 fEntityScanner.scanChar();
1355 return true;
1356 } else if (c == '/') {
1357 fEntityScanner.scanChar();
1358 if (!fEntityScanner.skipChar('>')) {
1359 reportFatalError("ElementUnterminated",
1360 new Object[]{fElementQName.rawname});
1361 }
1362 fEmptyElement = true;
1363 return true;
1364 } else if (!isValidNameStartChar(c) || !sawSpace) {
1365 reportFatalError("ElementUnterminated", new Object[]{fElementQName.rawname});
1366 }
1367
1368 return false;
1369 }
1370
1371 public boolean hasAttributes(){
1372 return fAttributes.getLength() > 0 ? true : false ;
1373 }
1374
1375
1376 /**
1377 * Scans an attribute.
1378 * <p>
1379 * <pre>
1380 * [41] Attribute ::= Name Eq AttValue
1381 * </pre>
1382 * <p>
1383 * <strong>Note:</strong> This method assumes that the next
1384 * character on the stream is the first character of the attribute
1385 * name.
1386 * <p>
1387 * <strong>Note:</strong> This method uses the fAttributeQName and
1388 * fQName variables. The contents of these variables will be
1389 * destroyed.
1390 *
1391 * @param attributes The attributes list for the scanned attribute.
1392 */
1393
1394 /**
1395 * protected void scanAttribute(AttributeIteratorImpl attributes)
1396 * throws IOException, XNIException {
1397 * if (DEBUG_START_END_ELEMENT) System.out.println(">>> scanAttribute()");
1398 *
1399 *
1400 * // name
1401 * if (fNamespaces) {
1402 * fEntityScanner.scanQName(fAttributeQName);
1403 * }
1404 * else {
1405 * String name = fEntityScanner.scanName();
1406 * fAttributeQName.setValues(null, name, name, null);
1407 * }
1408 *
1409 * // equals
1410 * fEntityScanner.skipSpaces();
1411 * if (!fEntityScanner.skipChar('=')) {
1412 * reportFatalError("EqRequiredInAttribute",
1413 * new Object[]{fAttributeQName.rawname});
1414 * }
1415 * fEntityScanner.skipSpaces();
1416 *
1417 *
1418 * // content
1419 * int oldLen = attributes.getLength();
1420 */
1421 /**xxx there is one check of duplicate attribute that has been removed.
1422 * attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null);
1423 *
1424 * // WFC: Unique Att Spec
1425 * if (oldLen == attributes.getLength()) {
1426 * reportFatalError("AttributeNotUnique",
1427 * new Object[]{fCurrentElement.rawname,
1428 * fAttributeQName.rawname});
1429 * }
1430 */
1431
1432 /*
1433 //REVISIT: one more case needs to be included: external PE and standalone is no
1434 boolean isVC = fHasExternalDTD && !fStandalone;
1435 scanAttributeValue(fTempString, fTempString2,
1436 fAttributeQName.rawname, attributes,
1437 oldLen, isVC);
1438
1439 //attributes.setValue(oldLen, fTempString.toString());
1440 //attributes.setNonNormalizedValue(oldLen, fTempString2.toString());
1441 //attributes.setSpecified(oldLen, true);
1442
1443 AttributeImpl attribute = new AttributeImpl(fAttributeQName.prefix,fAttributeQName.localpart,fAttributeQName.uri,fTempString.toString(),fTempString2.toString(),XMLSymbols.fCDATASymbol,true);
1444 fAttributes.addAttribute(attribute);
1445 if (DEBUG_START_END_ELEMENT) System.out.println("<<< scanAttribute()");
1446 } // scanAttribute(XMLAttributes)
1447
1448 */
1449
1450 /** return the attribute iterator implementation */
1451 public XMLAttributesIteratorImpl getAttributeIterator(){
1452 if(dtdGrammarUtil != null && fAddDefaultAttr){
1453 dtdGrammarUtil.addDTDDefaultAttrs(fElementQName,fAttributes);
1454 fAddDefaultAttr = false;
1455 }
1456 return fAttributes;
1457 }
1458
1459 /** return if the doucment is standalone */
1460 public boolean isStandAlone(){
1461 return fStandalone ;
1462 }
1463 /**
1464 * Scans an attribute name value pair.
1465 * <p>
1466 * <pre>
1467 * [41] Attribute ::= Name Eq AttValue
1468 * </pre>
1469 * <p>
1470 * <strong>Note:</strong> This method assumes that the next
1471 * character on the stream is the first character of the attribute
1472 * name.
1473 * <p>
1474 * <strong>Note:</strong> This method uses the fAttributeQName and
1475 * fQName variables. The contents of these variables will be
1476 * destroyed.
1477 *
1478 * @param attributes The attributes list for the scanned attribute.
1479 */
1480
1481 protected void scanAttribute(XMLAttributes attributes)
1482 throws IOException, XNIException {
1483 if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +">>> scanAttribute()");
1484
1485 // name
1486 if (fNamespaces) {
1487 fEntityScanner.scanQName(fAttributeQName);
1488 } else {
1489 String name = fEntityScanner.scanName();
1490 fAttributeQName.setValues(null, name, name, null);
1491 }
1492
1493 // equals
1494 fEntityScanner.skipSpaces();
1495 if (!fEntityScanner.skipChar('=')) {
1496 reportFatalError("EqRequiredInAttribute",
1497 new Object[] {fCurrentElement.rawname, fAttributeQName.rawname});
1498 }
1499 fEntityScanner.skipSpaces();
1500
1501 int attIndex = 0 ;
1502 //REVISIT: one more case needs to be included: external PE and standalone is no
1503 boolean isVC = fHasExternalDTD && !fStandalone;
1504 //fTempString would store attribute value
1505 ///fTempString2 would store attribute non-normalized value
1506
1507 //this function doesn't use 'attIndex'. We are adding the attribute later
1508 //after we have figured out that current attribute is not namespace declaration
1509 //since scanAttributeValue doesn't use attIndex parameter therefore we
1510 //can safely add the attribute later..
1511 XMLString tmpStr = getString();
1512
1513 scanAttributeValue(tmpStr, fTempString2,
1514 fAttributeQName.rawname, attributes,
1515 attIndex, isVC);
1516
1517 // content
1518 int oldLen = attributes.getLength();
1519 //if the attribute name already exists.. new value is replaced with old value
1520 attIndex = attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null);
1521
1522 // WFC: Unique Att Spec
1523 //attributes count will be same if the current attribute name already exists for this element name.
1524 //this means there are two duplicate attributes.
1525 if (oldLen == attributes.getLength()) {
1526 reportFatalError("AttributeNotUnique",
1527 new Object[]{fCurrentElement.rawname,
1528 fAttributeQName.rawname});
1529 }
1530
1531 //tmpString contains attribute value
1532 //we are passing null as the attribute value
1533 attributes.setValue(attIndex, null, tmpStr);
1534
1535 ///xxx: nonNormalizedValue is not being set as it is not required by SAX & DOM
1536 //attributes.setNonNormalizedValue(oldLen, fTempString2.toString());
1537 attributes.setSpecified(attIndex, true);
1538
1539 if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +"<<< scanAttribute()");
1540
1541 } // scanAttribute(XMLAttributes)
1542
1543 /**
1544 * Scans element content.
1545 *
1546 * @return Returns the next character on the stream.
1547 */
1548 //CHANGED:
1549 //EARLIER: scanContent()
1550 //NOW: scanContent(XMLStringBuffer)
1551 //It makes things easy if this functions takes XMLStringBuffer as parameter..
1552 //this function appends the data to the buffer.
1553 protected int scanContent(XMLStringBuffer content) throws IOException, XNIException {
1554 //set the fTempString length to 0 before passing it on to scanContent
1555 //scanContent sets the correct co-ordinates as per the content read
1556 fTempString.length = 0;
1557 int c = fEntityScanner.scanContent(fTempString);
1558 content.append(fTempString);
1559 fTempString.length = 0;
1560 if (c == '\r') {
1561 // happens when there is the character reference
1562 //xxx: We know the next chracter.. we should just skip it and add ']' directlry
1563 fEntityScanner.scanChar();
1564 content.append((char)c);
1565 c = -1;
1566 } else if (c == ']') {
1567 //fStringBuffer.clear();
1568 //xxx: We know the next chracter.. we should just skip it and add ']' directlry
1569 content.append((char)fEntityScanner.scanChar());
1570 // remember where we are in case we get an endEntity before we
1571 // could flush the buffer out - this happens when we're parsing an
1572 // entity which ends with a ]
1573 fInScanContent = true;
1574 //
1575 // We work on a single character basis to handle cases such as:
1576 // ']]]>' which we might otherwise miss.
1577 //
1578 if (fEntityScanner.skipChar(']')) {
1579 content.append(']');
1580 while (fEntityScanner.skipChar(']')) {
1581 content.append(']');
1582 }
1583 if (fEntityScanner.skipChar('>')) {
1584 reportFatalError("CDEndInContent", null);
1585 }
1586 }
1587 fInScanContent = false;
1588 c = -1;
1589 }
1590 if (fDocumentHandler != null && content.length > 0) {
1591 //fDocumentHandler.characters(content, null);
1592 }
1593 return c;
1594
1595 } // scanContent():int
1596
1597
1598 /**
1599 * Scans a CDATA section.
1600 * <p>
1601 * <strong>Note:</strong> This method uses the fTempString and
1602 * fStringBuffer variables.
1603 *
1604 * @param complete True if the CDATA section is to be scanned
1605 * completely.
1606 *
1607 * @return True if CDATA is completely scanned.
1608 */
1609 //CHANGED:
1610 protected boolean scanCDATASection(XMLStringBuffer contentBuffer, boolean complete)
1611 throws IOException, XNIException {
1612
1613 // call handler
1614 if (fDocumentHandler != null) {
1615 //fDocumentHandler.startCDATA(null);
1616 }
1617
1618 while (true) {
1619 //scanData will fill the contentBuffer
1620 if (!fEntityScanner.scanData("]]>", contentBuffer)) {
1621 break ;
1622 /** We dont need all this code if we pass ']]>' as delimeter..
1623 * int brackets = 2;
1624 * while (fEntityScanner.skipChar(']')) {
1625 * brackets++;
1626 * }
1627 *
1628 * //When we find more than 2 square brackets
1629 * if (fDocumentHandler != null && brackets > 2) {
1630 * //we dont need to clear the buffer..
1631 * //contentBuffer.clear();
1632 * for (int i = 2; i < brackets; i++) {
1633 * contentBuffer.append(']');
1634 * }
1635 * fDocumentHandler.characters(contentBuffer, null);
1636 * }
1637 *
1638 * if (fEntityScanner.skipChar('>')) {
1639 * break;
1640 * }
1641 * if (fDocumentHandler != null) {
1642 * //we dont need to clear the buffer now..
1643 * //contentBuffer.clear();
1644 * contentBuffer.append("]]");
1645 * fDocumentHandler.characters(contentBuffer, null);
1646 * }
1647 **/
1648 } else {
1649 int c = fEntityScanner.peekChar();
1650 if (c != -1 && isInvalidLiteral(c)) {
1651 if (XMLChar.isHighSurrogate(c)) {
1652 //contentBuffer.clear();
1653 //scan surrogates if any....
1654 scanSurrogates(contentBuffer);
1655 } else {
1656 reportFatalError("InvalidCharInCDSect",
1657 new Object[]{Integer.toString(c,16)});
1658 fEntityScanner.scanChar();
1659 }
1660 }
1661 //by this time we have also read surrogate contents if any...
1662 if (fDocumentHandler != null) {
1663 //fDocumentHandler.characters(contentBuffer, null);
1664 }
1665 }
1666 }
1667 fMarkupDepth--;
1668
1669 if (fDocumentHandler != null && contentBuffer.length > 0) {
1670 //fDocumentHandler.characters(contentBuffer, null);
1671 }
1672
1673 // call handler
1674 if (fDocumentHandler != null) {
1675 //fDocumentHandler.endCDATA(null);
1676 }
1677
1678 return true;
1679
1680 } // scanCDATASection(XMLStringBuffer, boolean):boolean
1681
1682 /**
1683 * Scans an end element.
1684 * <p>
1685 * <pre>
1686 * [42] ETag ::= '</' Name S? '>'
1687 * </pre>
1688 * <p>
1689 * <strong>Note:</strong> This method uses the fElementQName variable.
1690 * The contents of this variable will be destroyed. The caller should
1691 * copy the needed information out of this variable before calling
1692 * this method.
1693 *
1694 * @return The element depth.
1695 */
1696 protected int scanEndElement() throws IOException, XNIException {
1697 if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +">>> scanEndElement()");
1698
1699 // pop context
1700 QName endElementName = fElementStack.popElement();
1701
1702 String rawname = endElementName.rawname;
1703 if(DEBUG)System.out.println("endElementName = " + endElementName.toString());
1704 // Take advantage of the fact that next string _should_ be "fElementQName.rawName",
1705 //In scanners most of the time is consumed on checks done for XML characters, we can
1706 // optimize on it and avoid the checks done for endElement,
1707 //we will also avoid symbol table lookup - neeraj.bajaj@sun.com
1708
1709 // this should work both for namespace processing true or false...
1710
1711 //REVISIT: if the string is not the same as expected.. we need to do better error handling..
1712 //We can skip this for now... In any case if the string doesn't match -- document is not well formed.
1713
1714 if (!fEntityScanner.skipString(endElementName.rawname)) {
1715 reportFatalError("ETagRequired", new Object[]{rawname});
1716 }
1717
1718 // end
1719 fEntityScanner.skipSpaces();
1720 if (!fEntityScanner.skipChar('>')) {
1721 reportFatalError("ETagUnterminated",
1722 new Object[]{rawname});
1723 }
1724 fMarkupDepth--;
1725
1726 //we have increased the depth for two markup "<" characters
1727 fMarkupDepth--;
1728
1729 // check that this element was opened in the same entity
1730 if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
1731 reportFatalError("ElementEntityMismatch",
1732 new Object[]{rawname});
1733 }
1734
1735 //We should not be popping out the context here in endELement becaause the namespace context is still
1736 //valid when parser is at the endElement state.
1737
1738 //if (fNamespaces) {
1739 // fNamespaceContext.popContext();
1740 //}
1741
1742 // call handler
1743 if (fDocumentHandler != null ) {
1744 //end element is scanned in this function so we can send a callback
1745 //here.
1746 //<strong>we shouldn't be sending callback in scanDocument()</strong>
1747
1748 fDocumentHandler.endElement(endElementName, null);
1749 }
1750 if(dtdGrammarUtil != null)
1751 dtdGrammarUtil.endElement(endElementName);
1752
1753 return fMarkupDepth;
1754
1755 } // scanEndElement():int
1756
1757 /**
1758 * Scans a character reference.
1759 * <p>
1760 * <pre>
1761 * [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
1762 * </pre>
1763 */
1764 protected void scanCharReference()
1765 throws IOException, XNIException {
1766
1767 fStringBuffer2.clear();
1768 int ch = scanCharReferenceValue(fStringBuffer2, null);
1769 fMarkupDepth--;
1770 if (ch != -1) {
1771 // call handler
1772
1773 if (fDocumentHandler != null) {
1774 if (fNotifyCharRefs) {
1775 fDocumentHandler.startGeneralEntity(fCharRefLiteral, null, null, null);
1776 }
1777 Augmentations augs = null;
1778 if (fValidation && ch <= 0x20) {
1779 if (fTempAugmentations != null) {
1780 fTempAugmentations.removeAllItems();
1781 }
1782 else {
1783 fTempAugmentations = new AugmentationsImpl();
1784 }
1785 augs = fTempAugmentations;
1786 augs.putItem(Constants.CHAR_REF_PROBABLE_WS, Boolean.TRUE);
1787 }
1788 //xxx: How do we deal with this - how to return charReferenceValues
1789 //now this is being commented because this is taken care in scanDocument()
1790 //fDocumentHandler.characters(fStringBuffer2, null);
1791 if (fNotifyCharRefs) {
1792 fDocumentHandler.endGeneralEntity(fCharRefLiteral, null);
1793 }
1794 }
1795 }
1796
1797 } // scanCharReference()
1798
1799
1800 /**
1801 * Scans an entity reference.
1802 *
1803 * @return returns true if the new entity is started. If it was built-in entity
1804 * 'false' is returned.
1805 * @throws IOException Thrown if i/o error occurs.
1806 * @throws XNIException Thrown if handler throws exception upon
1807 * notification.
1808 */
1809 protected void scanEntityReference(XMLStringBuffer content) throws IOException, XNIException {
1810 String name = fEntityScanner.scanName();
1811 if (name == null) {
1812 reportFatalError("NameRequiredInReference", null);
1813 }
1814 if (!fEntityScanner.skipChar(';')) {
1815 reportFatalError("SemicolonRequiredInReference", new Object []{name});
1816 }
1817 if (fEntityStore.isUnparsedEntity(name)) {
1818 reportFatalError("ReferenceToUnparsedEntity", new Object[]{name});
1819 }
1820 fMarkupDepth--;
1821 fCurrentEntityName = name;
1822
1823 // handle built-in entities
1824 if (name == fAmpSymbol) {
1825 handleCharacter('&', fAmpSymbol, content);
1826 fScannerState = SCANNER_STATE_BUILT_IN_REFS;
1827 return ;
1828 } else if (name == fLtSymbol) {
1829 handleCharacter('<', fLtSymbol, content);
1830 fScannerState = SCANNER_STATE_BUILT_IN_REFS;
1831 return ;
1832 } else if (name == fGtSymbol) {
1833 handleCharacter('>', fGtSymbol, content);
1834 fScannerState = SCANNER_STATE_BUILT_IN_REFS;
1835 return ;
1836 } else if (name == fQuotSymbol) {
1837 handleCharacter('"', fQuotSymbol, content);
1838 fScannerState = SCANNER_STATE_BUILT_IN_REFS;
1839 return ;
1840 } else if (name == fAposSymbol) {
1841 handleCharacter('\'', fAposSymbol, content);
1842 fScannerState = SCANNER_STATE_BUILT_IN_REFS;
1843 return ;
1844 }
1845
1846 //1. if the entity is external and support to external entities is not required
1847 // 2. or entities should not be replaced
1848 //3. or if it is built in entity reference.
1849 if((fEntityStore.isExternalEntity(name) && !fSupportExternalEntities) || (!fEntityStore.isExternalEntity(name) && !fReplaceEntityReferences) || foundBuiltInRefs){
1850 fScannerState = SCANNER_STATE_REFERENCE;
1851 return ;
1852 }
1853 // start general entity
1854 if (!fEntityStore.isDeclaredEntity(name)) {
1855 //REVISIT: one more case needs to be included: external PE and standalone is no
1856 if ( fHasExternalDTD && !fStandalone) {
1857 if (fValidation)
1858 fErrorReporter.reportError(fEntityScanner, XMLMessageFormatter.XML_DOMAIN,"EntityNotDeclared",
1859 new Object[]{name}, XMLErrorReporter.SEVERITY_ERROR);
1860 } else
1861 reportFatalError("EntityNotDeclared", new Object[]{name});
1862 }
1863 //we are starting the entity even if the entity was not declared
1864 //if that was the case it its taken care in XMLEntityManager.startEntity()
1865 //we immediately call the endEntity. Application gets to know if there was
1866 //any entity that was not declared.
1867 fEntityManager.startEntity(name, false);
1868 //set the scaner state to content.. parser will automatically revive itself at any point of time.
1869 //setScannerState(SCANNER_STATE_CONTENT);
1870 //return true ;
1871 } // scanEntityReference()
1872
1873 // utility methods
1874
1875 /**
1876 * Calls document handler with a single character resulting from
1877 * built-in entity resolution.
1878 *
1879 * @param c
1880 * @param entity built-in name
1881 * @param XMLStringBuffer append the character to buffer
1882 *
1883 * we really dont need to call this function -- this function is only required when
1884 * we integrate with rest of Xerces2. SO maintaining the current behavior and still
1885 * calling this function to hanlde built-in entity reference.
1886 *
1887 */
1888 private void handleCharacter(char c, String entity, XMLStringBuffer content) throws XNIException {
1889 foundBuiltInRefs = true;
1890 content.append(c);
1891 if (fDocumentHandler != null) {
1892 fSingleChar[0] = c;
1893 if (fNotifyBuiltInRefs) {
1894 fDocumentHandler.startGeneralEntity(entity, null, null, null);
1895 }
1896 fTempString.setValues(fSingleChar, 0, 1);
1897 //fDocumentHandler.characters(fTempString, null);
1898
1899 if (fNotifyBuiltInRefs) {
1900 fDocumentHandler.endGeneralEntity(entity, null);
1901 }
1902 }
1903 } // handleCharacter(char)
1904
1905 // helper methods
1906
1907 /**
1908 * Sets the scanner state.
1909 *
1910 * @param state The new scanner state.
1911 */
1912 protected final void setScannerState(int state) {
1913
1914 fScannerState = state;
1915 if (DEBUG_SCANNER_STATE) {
1916 System.out.print("### setScannerState: ");
1917 //System.out.print(fScannerState);
1918 System.out.print(getScannerStateName(state));
1919 System.out.println();
1920 }
1921
1922 } // setScannerState(int)
1923
1924
1925 /**
1926 * Sets the Driver.
1927 *
1928 * @param Driver The new Driver.
1929 */
1930 protected final void setDriver(Driver driver) {
1931 fDriver = driver;
1932 if (DEBUG_DISPATCHER) {
1933 System.out.print("%%% setDriver: ");
1934 System.out.print(getDriverName(driver));
1935 System.out.println();
1936 }
1937 }
1938
1939 //
1940 // Private methods
1941 //
1942
1943 /** Returns the scanner state name. */
1944 protected String getScannerStateName(int state) {
1945
1946 switch (state) {
1947 case SCANNER_STATE_DOCTYPE: return "SCANNER_STATE_DOCTYPE";
1948 case SCANNER_STATE_ROOT_ELEMENT: return "SCANNER_STATE_ROOT_ELEMENT";
1949 case SCANNER_STATE_START_OF_MARKUP: return "SCANNER_STATE_START_OF_MARKUP";
1950 case SCANNER_STATE_COMMENT: return "SCANNER_STATE_COMMENT";
1951 case SCANNER_STATE_PI: return "SCANNER_STATE_PI";
1952 case SCANNER_STATE_CONTENT: return "SCANNER_STATE_CONTENT";
1953 case SCANNER_STATE_REFERENCE: return "SCANNER_STATE_REFERENCE";
1954 case SCANNER_STATE_END_OF_INPUT: return "SCANNER_STATE_END_OF_INPUT";
1955 case SCANNER_STATE_TERMINATED: return "SCANNER_STATE_TERMINATED";
1956 case SCANNER_STATE_CDATA: return "SCANNER_STATE_CDATA";
1957 case SCANNER_STATE_TEXT_DECL: return "SCANNER_STATE_TEXT_DECL";
1958 case SCANNER_STATE_ATTRIBUTE: return "SCANNER_STATE_ATTRIBUTE";
1959 case SCANNER_STATE_ATTRIBUTE_VALUE: return "SCANNER_STATE_ATTRIBUTE_VALUE";
1960 case SCANNER_STATE_START_ELEMENT_TAG: return "SCANNER_STATE_START_ELEMENT_TAG";
1961 case SCANNER_STATE_END_ELEMENT_TAG: return "SCANNER_STATE_END_ELEMENT_TAG";
1962 case SCANNER_STATE_CHARACTER_DATA: return "SCANNER_STATE_CHARACTER_DATA" ;
1963 }
1964
1965 return "??? ("+state+')';
1966
1967 } // getScannerStateName(int):String
1968 public String getEntityName(){
1969 //return the cached name
1970 return fCurrentEntityName;
1971 }
1972
1973 /** Returns the driver name. */
1974 public String getDriverName(Driver driver) {
1975
1976 if (DEBUG_DISPATCHER) {
1977 if (driver != null) {
1978 String name = driver.getClass().getName();
1979 int index = name.lastIndexOf('.');
1980 if (index != -1) {
1981 name = name.substring(index + 1);
1982 index = name.lastIndexOf('$');
1983 if (index != -1) {
1984 name = name.substring(index + 1);
1985 }
1986 }
1987 return name;
1988 }
1989 }
1990 return "null";
1991
1992 } // getDriverName():String
1993
1994 //
1995 // Classes
1996 //
1997
1998 /**
1999 * @author Neeraj Bajaj, Sun Microsystems.
2000 */
2001 protected static final class Element {
2002
2003 //
2004 // Data
2005 //
2006
2007 /** Symbol. */
2008 public QName qname;
2009
2010 //raw name stored as characters
2011 public char[] fRawname;
2012
2013 /** The next Element entry. */
2014 public Element next;
2015
2016 //
2017 // Constructors
2018 //
2019
2020 /**
2021 * Constructs a new Element from the given QName and next Element
2022 * reference.
2023 */
2024 public Element(QName qname, Element next) {
2025 this.qname.setValues(qname);
2026 this.fRawname = qname.rawname.toCharArray();
2027 this.next = next;
2028 }
2029
2030 } // class Element
2031
2032 /**
2033 * Element stack.
2034 *
2035 * @author Neeraj Bajaj, Sun Microsystems.
2036 */
2037 protected class ElementStack2 {
2038
2039 //
2040 // Data
2041 //
2042
2043 /** The stack data. */
2044 protected QName [] fQName = new QName[20];
2045
2046 //Element depth
2047 protected int fDepth;
2048 //total number of elements
2049 protected int fCount;
2050 //current position
2051 protected int fPosition;
2052 //Mark refers to the position
2053 protected int fMark;
2054
2055 protected int fLastDepth ;
2056
2057 //
2058 // Constructors
2059 //
2060
2061 /** Default constructor. */
2062 public ElementStack2() {
2063 for (int i = 0; i < fQName.length; i++) {
2064 fQName[i] = new QName();
2065 }
2066 fMark = fPosition = 1;
2067 } // <init>()
2068
2069 public void resize(){
2070 /**
2071 * int length = fElements.length;
2072 * Element [] temp = new Element[length * 2];
2073 * System.arraycopy(fElements, 0, temp, 0, length);
2074 * fElements = temp;
2075 */
2076 //resize QNames
2077 int oldLength = fQName.length;
2078 QName [] tmp = new QName[oldLength * 2];
2079 System.arraycopy(fQName, 0, tmp, 0, oldLength);
2080 fQName = tmp;
2081
2082 for (int i = oldLength; i < fQName.length; i++) {
2083 fQName[i] = new QName();
2084 }
2085
2086 }
2087
2088
2089 //
2090 // Public methods
2091 //
2092
2093 /** Check if the element scanned during the start element
2094 *matches the stored element.
2095 *
2096 *@return true if the match suceeds.
2097 */
2098 public boolean matchElement(QName element) {
2099 //last depth is the depth when last elemnt was pushed
2100 //if last depth is greater than current depth
2101 if(DEBUG_SKIP_ALGORITHM){
2102 System.out.println("fLastDepth = " + fLastDepth);
2103 System.out.println("fDepth = " + fDepth);
2104 }
2105 boolean match = false;
2106 if(fLastDepth > fDepth && fDepth <= 2){
2107 if(DEBUG_SKIP_ALGORITHM){
2108 System.out.println("Checking if the elements match " + element.rawname + " , " + fQName[fDepth].rawname);
2109 }
2110 if(element.rawname == fQName[fDepth].rawname){
2111 fAdd = false;
2112 //mark this position
2113 //decrease the depth by 1 as arrays are 0 based
2114 fMark = fDepth - 1;
2115 //we found the match and from next element skipping will start, add 1
2116 fPosition = fMark + 1 ;
2117 match = true;
2118 //Once we get match decrease the count -- this was increased by nextElement()
2119 --fCount;
2120 if(DEBUG_SKIP_ALGORITHM){
2121 System.out.println("fAdd FALSE -- NOW ELEMENT SHOULD NOT BE ADDED");
2122 System.out.println("fMark = " + fMark);
2123 System.out.println("fPosition = " + fPosition);
2124 System.out.println("fDepth = " + fDepth);
2125 System.out.println("fCount = " + fCount);
2126 }
2127 }else{
2128 fAdd = true;
2129 if(DEBUG_SKIP_ALGORITHM)System.out.println("fAdd is " + fAdd);
2130 }
2131 }
2132 //store the last depth
2133 fLastDepth = fDepth++;
2134 return match;
2135 } // pushElement(QName):QName
2136
2137 /**
2138 * This function doesn't increase depth. The function in this function is
2139 *broken down into two functions for efficiency. <@see>matchElement</see>.
2140 * This function just returns the pointer to the object and its values are set.
2141 *
2142 *@return QName reference to the next element in the list
2143 */
2144 public QName nextElement() {
2145
2146 //if number of elements becomes equal to the length of array -- stop the skipping
2147 if (fCount == fQName.length) {
2148 fShouldSkip = false;
2149 fAdd = false;
2150 if(DEBUG_SKIP_ALGORITHM)System.out.println("SKIPPING STOPPED, fShouldSkip = " + fShouldSkip);
2151 //xxx: this is not correct, we are returning the last element
2152 //this wont make any difference since flag has been set to 'false'
2153 return fQName[--fCount];
2154 }
2155 if(DEBUG_SKIP_ALGORITHM){
2156 System.out.println("fCount = " + fCount);
2157 }
2158 return fQName[fCount++];
2159
2160 }
2161
2162 /** Note that this function is considerably different than nextElement()
2163 * This function just returns the previously stored elements
2164 */
2165 public QName getNext(){
2166 //when position reaches number of elements in the list..
2167 //set the position back to mark, making it a circular linked list.
2168 if(fPosition == fCount){
2169 fPosition = fMark;
2170 }
2171 return fQName[fPosition++];
2172 }
2173
2174 /** returns the current depth
2175 */
2176 public int popElement(){
2177 return fDepth--;
2178 }
2179
2180
2181 /** Clears the stack without throwing away existing QName objects. */
2182 public void clear() {
2183 fLastDepth = 0;
2184 fDepth = 0;
2185 fCount = 0 ;
2186 fPosition = fMark = 1;
2187 } // clear()
2188
2189 } // class ElementStack
2190
2191 /**
2192 * Element stack. This stack operates without synchronization, error
2193 * checking, and it re-uses objects instead of throwing popped items
2194 * away.
2195 *
2196 * @author Andy Clark, IBM
2197 */
2198 protected class ElementStack {
2199
2200 //
2201 // Data
2202 //
2203
2204 /** The stack data. */
2205 protected QName[] fElements;
2206 protected int [] fInt = new int[20];
2207
2208
2209 //Element depth
2210 protected int fDepth;
2211 //total number of elements
2212 protected int fCount;
2213 //current position
2214 protected int fPosition;
2215 //Mark refers to the position
2216 protected int fMark;
2217
2218 protected int fLastDepth ;
2219
2220 //
2221 // Constructors
2222 //
2223
2224 /** Default constructor. */
2225 public ElementStack() {
2226 fElements = new QName[20];
2227 for (int i = 0; i < fElements.length; i++) {
2228 fElements[i] = new QName();
2229 }
2230 } // <init>()
2231
2232 //
2233 // Public methods
2234 //
2235
2236 /**
2237 * Pushes an element on the stack.
2238 * <p>
2239 * <strong>Note:</strong> The QName values are copied into the
2240 * stack. In other words, the caller does <em>not</em> orphan
2241 * the element to the stack. Also, the QName object returned
2242 * is <em>not</em> orphaned to the caller. It should be
2243 * considered read-only.
2244 *
2245 * @param element The element to push onto the stack.
2246 *
2247 * @return Returns the actual QName object that stores the
2248 */
2249 //XXX: THIS FUNCTION IS NOT USED
2250 public QName pushElement(QName element) {
2251 if (fDepth == fElements.length) {
2252 QName[] array = new QName[fElements.length * 2];
2253 System.arraycopy(fElements, 0, array, 0, fDepth);
2254 fElements = array;
2255 for (int i = fDepth; i < fElements.length; i++) {
2256 fElements[i] = new QName();
2257 }
2258 }
2259 fElements[fDepth].setValues(element);
2260 return fElements[fDepth++];
2261 } // pushElement(QName):QName
2262
2263
2264 /** Note that this function is considerably different than nextElement()
2265 * This function just returns the previously stored elements
2266 */
2267 public QName getNext(){
2268 //when position reaches number of elements in the list..
2269 //set the position back to mark, making it a circular linked list.
2270 if(fPosition == fCount){
2271 fPosition = fMark;
2272 }
2273 //store the position of last opened tag at particular depth
2274 //fInt[++fDepth] = fPosition;
2275 if(DEBUG_SKIP_ALGORITHM){
2276 System.out.println("Element at fPosition = " + fPosition + " is " + fElements[fPosition].rawname);
2277 }
2278 //return fElements[fPosition++];
2279 return fElements[fPosition];
2280 }
2281
2282 /** This function should be called only when element was skipped sucessfully.
2283 * 1. Increase the depth - because element was sucessfully skipped.
2284 *2. Store the position of the element token in array "last opened tag" at depth.
2285 *3. increase the position counter so as to point to the next element in the array
2286 */
2287 public void push(){
2288
2289 fInt[++fDepth] = fPosition++;
2290 }
2291
2292 /** Check if the element scanned during the start element
2293 *matches the stored element.
2294 *
2295 *@return true if the match suceeds.
2296 */
2297 public boolean matchElement(QName element) {
2298 //last depth is the depth when last elemnt was pushed
2299 //if last depth is greater than current depth
2300 //if(DEBUG_SKIP_ALGORITHM){
2301 // System.out.println("Check if the element " + element.rawname + " matches");
2302 // System.out.println("fLastDepth = " + fLastDepth);
2303 // System.out.println("fDepth = " + fDepth);
2304 //}
2305 boolean match = false;
2306 if(fLastDepth > fDepth && fDepth <= 3){
2307 if(DEBUG_SKIP_ALGORITHM){
2308 System.out.println("----------ENTERED THE LOOP WHERE WE CHECK FOR MATCHING OF ELMENT-----");
2309 System.out.println("Depth = " + fDepth + " Checking if INCOMING element " + element.rawname + " match STORED ELEMENT " + fElements[fDepth - 1].rawname);
2310 }
2311 if(element.rawname == fElements[fDepth - 1].rawname){
2312 fAdd = false;
2313 //mark this position
2314 //decrease the depth by 1 as arrays are 0 based
2315 fMark = fDepth - 1;
2316 //we found the match
2317 fPosition = fMark;
2318 match = true;
2319 //Once we get match decrease the count -- this was increased by nextElement()
2320 --fCount;
2321 if(DEBUG_SKIP_ALGORITHM){
2322 System.out.println("NOW ELEMENT SHOULD NOT BE ADDED, fAdd is set to false");
2323 System.out.println("fMark = " + fMark);
2324 System.out.println("fPosition = " + fPosition);
2325 System.out.println("fDepth = " + fDepth);
2326 System.out.println("fCount = " + fCount);
2327 System.out.println("---------MATCH SUCEEDED-----------------");
2328 System.out.println("");
2329 }
2330 }else{
2331 fAdd = true;
2332 if(DEBUG_SKIP_ALGORITHM)System.out.println("fAdd is " + fAdd);
2333 }
2334 }
2335 //store the position for the current depth
2336 //when we are adding the elements, when skipping
2337 //starts even then this should be tracked ie. when
2338 //calling getNext()
2339 if(match){
2340 //from next element skipping will start, add 1
2341 fInt[fDepth] = fPosition++;
2342 } else{
2343 if(DEBUG_SKIP_ALGORITHM){
2344 System.out.println("At depth = " + fDepth + "array position is = " + (fCount - 1));
2345 }
2346 //sicne fInt[fDepth] contains pointer to the element array which are 0 based.
2347 fInt[fDepth] = fCount - 1;
2348 }
2349
2350 //if number of elements becomes equal to the length of array -- stop the skipping
2351 //xxx: should we do "fCount == fInt.length"
2352 if (fCount == fElements.length) {
2353 fSkip = false;
2354 fAdd = false;
2355 //reposition the stack -- it seems to be too complex document and there is no symmerty in structure
2356 reposition();
2357 if(DEBUG_SKIP_ALGORITHM){
2358 System.out.println("ALL THE ELMENTS IN ARRAY HAVE BEEN FILLED");
2359 System.out.println("REPOSITIONING THE STACK");
2360 System.out.println("-----------SKIPPING STOPPED----------");
2361 System.out.println("");
2362 }
2363 return false;
2364 }
2365 if(DEBUG_SKIP_ALGORITHM){
2366 if(match){
2367 System.out.println("Storing fPosition = " + fInt[fDepth] + " at fDepth = " + fDepth);
2368 }else{
2369 System.out.println("Storing fCount = " + fInt[fDepth] + " at fDepth = " + fDepth);
2370 }
2371 }
2372 //store the last depth
2373 fLastDepth = fDepth;
2374 return match;
2375 } // matchElement(QName):QName
2376
2377
2378 /**
2379 * Returns the next element on the stack.
2380 *
2381 * @return Returns the actual QName object. Callee should
2382 * use this object to store the details of next element encountered.
2383 */
2384 public QName nextElement() {
2385 if(fSkip){
2386 fDepth++;
2387 //boundary checks are done in matchElement()
2388