1 /*
2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
3  */
4 /*
5  * Licensed to the Apache Software Foundation (ASF) under one or more
6  * contributor license agreements.  See the NOTICE file distributed with
7  * this work for additional information regarding copyright ownership.
8  * The ASF licenses this file to You under the Apache License, Version 2.0
9  * (the "License"); you may not use this file except in compliance with
10  * the License.  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 package com.sun.org.apache.xerces.internal.impl.xs.traversers;
22 
23 import com.sun.org.apache.xerces.internal.impl.validation.ValidationState;
24 import com.sun.org.apache.xerces.internal.impl.xs.SchemaNamespaceSupport;
25 import com.sun.org.apache.xerces.internal.impl.xs.SchemaSymbols;
26 import com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaException;
27 import com.sun.org.apache.xerces.internal.impl.xs.util.XInt;
28 import com.sun.org.apache.xerces.internal.util.SymbolTable;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.Stack;
32 import org.w3c.dom.Attr;
33 import org.w3c.dom.Element;
34 import org.w3c.dom.NamedNodeMap;
35 import org.w3c.dom.Node;
36 
37 /**
38  * Objects of this class hold all information pecular to a
39  * particular XML Schema document.  This is needed because
40  * namespace bindings and other settings on the <schema/> element
41  * affect the contents of that schema document alone.
42  *
43  * @xerces.internal
44  *
45  * @author Neil Graham, IBM
46  * @LastModified: Oct 2017
47  */
48 class XSDocumentInfo {
49 
50     // Data
51     protected SchemaNamespaceSupport fNamespaceSupport;
52     protected SchemaNamespaceSupport fNamespaceSupportRoot;
53     protected Stack<SchemaNamespaceSupport> SchemaNamespaceSupportStack = new Stack<>();
54 
55     // schema's attributeFormDefault
56     protected boolean fAreLocalAttributesQualified;
57 
58     // elementFormDefault
59     protected boolean fAreLocalElementsQualified;
60 
61     // [block | final]Default
62     protected short fBlockDefault;
63     protected short fFinalDefault;
64 
65     // targetNamespace
66     String fTargetNamespace;
67 
68     // represents whether this is a chameleon schema (i.e., whether its TNS is natural or comes from without)
69     protected boolean fIsChameleonSchema;
70 
71     // the root of the schema Document tree itself
72     protected Element fSchemaElement;
73 
74     // all namespaces that this document can refer to
75     List<String> fImportedNS = new ArrayList<>();
76 
77     protected ValidationState fValidationContext = new ValidationState();
78 
79     SymbolTable fSymbolTable = null;
80 
81     // attribute checker to which we'll return the attributes
82     // once we've been told that we're done with them
83     protected XSAttributeChecker fAttrChecker;
84 
85     // array of objects on the schema's root element.  This is null
86     // once returnSchemaAttrs has been called.
87     protected Object [] fSchemaAttrs;
88 
89     // list of annotations contained in the schema document. This is null
90     // once removeAnnotations has been called.
91     protected XSAnnotationInfo fAnnotations = null;
92 
93     // note that the caller must ensure to call returnSchemaAttrs()
94     // to avoid memory leaks!
XSDocumentInfo(Element schemaRoot, XSAttributeChecker attrChecker, SymbolTable symbolTable)95     XSDocumentInfo (Element schemaRoot, XSAttributeChecker attrChecker, SymbolTable symbolTable)
96                     throws XMLSchemaException {
97         fSchemaElement = schemaRoot;
98         initNamespaceSupport(schemaRoot);
99         fIsChameleonSchema = false;
100 
101         fSymbolTable = symbolTable;
102         fAttrChecker = attrChecker;
103 
104         if (schemaRoot != null) {
105             Element root = schemaRoot;
106             fSchemaAttrs = attrChecker.checkAttributes(root, true, this);
107             // schemaAttrs == null means it's not an <xsd:schema> element
108             // throw an exception, but we don't know the document systemId,
109             // so we leave that to the caller.
110             if (fSchemaAttrs == null) {
111                 throw new XMLSchemaException(null, null);
112             }
113             fAreLocalAttributesQualified =
114                 ((XInt)fSchemaAttrs[XSAttributeChecker.ATTIDX_AFORMDEFAULT]).intValue() == SchemaSymbols.FORM_QUALIFIED;
115             fAreLocalElementsQualified =
116                 ((XInt)fSchemaAttrs[XSAttributeChecker.ATTIDX_EFORMDEFAULT]).intValue() == SchemaSymbols.FORM_QUALIFIED;
117             fBlockDefault =
118                 ((XInt)fSchemaAttrs[XSAttributeChecker.ATTIDX_BLOCKDEFAULT]).shortValue();
119             fFinalDefault =
120                 ((XInt)fSchemaAttrs[XSAttributeChecker.ATTIDX_FINALDEFAULT]).shortValue();
121             fTargetNamespace =
122                 (String)fSchemaAttrs[XSAttributeChecker.ATTIDX_TARGETNAMESPACE];
123             if (fTargetNamespace != null)
124                 fTargetNamespace = symbolTable.addSymbol(fTargetNamespace);
125 
126             fNamespaceSupportRoot = new SchemaNamespaceSupport(fNamespaceSupport);
127 
128             //set namespace support
129             fValidationContext.setNamespaceSupport(fNamespaceSupport);
130             fValidationContext.setSymbolTable(symbolTable);
131             // pass null as the schema document, so that the namespace
132             // context is not popped.
133 
134             // don't return the attribute array yet!
135             //attrChecker.returnAttrArray(schemaAttrs, null);
136         }
137     }
138 
139     /**
140      * Initialize namespace support by collecting all of the namespace
141      * declarations in the root's ancestors. This is necessary to
142      * support schemas fragments, i.e. schemas embedded in other
143      * documents. See,
144      *
145      * https://jaxp.dev.java.net/issues/show_bug.cgi?id=43
146      *
147      * Requires the DOM to be created with namespace support enabled.
148      */
initNamespaceSupport(Element schemaRoot)149     private void initNamespaceSupport(Element schemaRoot) {
150         fNamespaceSupport = new SchemaNamespaceSupport();
151         fNamespaceSupport.reset();
152 
153         Node parent = schemaRoot.getParentNode();
154         while (parent != null && parent.getNodeType() == Node.ELEMENT_NODE
155                 && !parent.getNodeName().equals("DOCUMENT_NODE"))
156         {
157             Element eparent = (Element) parent;
158             NamedNodeMap map = eparent.getAttributes();
159             int length = (map != null) ? map.getLength() : 0;
160             for (int i = 0; i < length; i++) {
161                 Attr attr = (Attr) map.item(i);
162                 String uri = attr.getNamespaceURI();
163 
164                 // Check if attribute is an ns decl -- requires ns support
165                 if (uri != null && uri.equals("http://www.w3.org/2000/xmlns/")) {
166                     String prefix = attr.getLocalName().intern();
167                     if (prefix == "xmlns") prefix = "";
168                     // Declare prefix if not set -- moving upwards
169                     if (fNamespaceSupport.getURI(prefix) == null) {
170                         fNamespaceSupport.declarePrefix(prefix,
171                                 attr.getValue().intern());
172                     }
173                 }
174             }
175             parent = parent.getParentNode();
176         }
177     }
178 
179     // backup the current ns support, and use the one passed-in.
180     // if no ns support is passed-in, use the one for <schema> element
backupNSSupport(SchemaNamespaceSupport nsSupport)181     void backupNSSupport(SchemaNamespaceSupport nsSupport) {
182         SchemaNamespaceSupportStack.push(fNamespaceSupport);
183         if (nsSupport == null)
184             nsSupport = fNamespaceSupportRoot;
185         fNamespaceSupport = new SchemaNamespaceSupport(nsSupport);
186 
187         fValidationContext.setNamespaceSupport(fNamespaceSupport);
188     }
189 
restoreNSSupport()190     void restoreNSSupport() {
191         fNamespaceSupport = SchemaNamespaceSupportStack.pop();
192         fValidationContext.setNamespaceSupport(fNamespaceSupport);
193     }
194 
195     // some Object methods
toString()196     public String toString() {
197         return fTargetNamespace == null?"no targetNamspace":"targetNamespace is " + fTargetNamespace;
198     }
199 
addAllowedNS(String namespace)200     public void addAllowedNS(String namespace) {
201         fImportedNS.add(namespace == null ? "" : namespace);
202     }
203 
isAllowedNS(String namespace)204     public boolean isAllowedNS(String namespace) {
205         return fImportedNS.contains(namespace == null ? "" : namespace);
206     }
207 
208     // store whether we have reported an error about that this document
209     // can't access components from the given namespace
210     private List<String> fReportedTNS = null;
211     // check whether we need to report an error against the given uri.
212     // if we have reported an error, then we don't need to report again;
213     // otherwise we reported the error, and remember this fact.
needReportTNSError(String uri)214     final boolean needReportTNSError(String uri) {
215         if (fReportedTNS == null)
216             fReportedTNS = new ArrayList<>();
217         else if (fReportedTNS.contains(uri))
218             return false;
219         fReportedTNS.add(uri);
220         return true;
221     }
222 
223     // return the attributes on the schema element itself:
getSchemaAttrs()224     Object [] getSchemaAttrs () {
225         return fSchemaAttrs;
226     }
227 
228     // deallocate the storage set aside for the schema element's
229     // attributes
returnSchemaAttrs()230     void returnSchemaAttrs () {
231         fAttrChecker.returnAttrArray (fSchemaAttrs, null);
232         fSchemaAttrs = null;
233     }
234 
235     // adds an annotation to the list of annotations
addAnnotation(XSAnnotationInfo info)236     void addAnnotation(XSAnnotationInfo info) {
237         info.next = fAnnotations;
238         fAnnotations = info;
239     }
240 
241     // returns the list of annotations conatined in the
242     // schema document or null if the document contained no annotations.
getAnnotations()243     XSAnnotationInfo getAnnotations() {
244         return fAnnotations;
245     }
246 
247     // removes reference to annotation list
removeAnnotations()248     void removeAnnotations() {
249         fAnnotations = null;
250     }
251 
252 } // XSDocumentInfo
253