1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  * @LastModified: Oct 2017
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.xerces.internal.impl.xs.traversers;
  23 
  24 import com.sun.org.apache.xerces.internal.impl.validation.ValidationState;
  25 import com.sun.org.apache.xerces.internal.impl.xs.SchemaNamespaceSupport;
  26 import com.sun.org.apache.xerces.internal.impl.xs.SchemaSymbols;
  27 import com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaException;
  28 import com.sun.org.apache.xerces.internal.impl.xs.util.XInt;
  29 import com.sun.org.apache.xerces.internal.util.SymbolTable;
  30 import java.util.ArrayList;
  31 import java.util.List;
  32 import java.util.Stack;
  33 import org.w3c.dom.Attr;
  34 import org.w3c.dom.Element;
  35 import org.w3c.dom.NamedNodeMap;
  36 import org.w3c.dom.Node;
  37 
  38 /**
  39  * Objects of this class hold all information pecular to a
  40  * particular XML Schema document.  This is needed because
  41  * namespace bindings and other settings on the <schema/> element
  42  * affect the contents of that schema document alone.
  43  *
  44  * @xerces.internal
  45  *
  46  * @author Neil Graham, IBM
  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!
  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      */
 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
 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 
 190     void restoreNSSupport() {
 191         fNamespaceSupport = SchemaNamespaceSupportStack.pop();
 192         fValidationContext.setNamespaceSupport(fNamespaceSupport);
 193     }
 194 
 195     // some Object methods
 196     public String toString() {
 197         return fTargetNamespace == null?"no targetNamspace":"targetNamespace is " + fTargetNamespace;
 198     }
 199 
 200     public void addAllowedNS(String namespace) {
 201         fImportedNS.add(namespace == null ? "" : namespace);
 202     }
 203 
 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.
 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:
 224     Object [] getSchemaAttrs () {
 225         return fSchemaAttrs;
 226     }
 227 
 228     // deallocate the storage set aside for the schema element's
 229     // attributes
 230     void returnSchemaAttrs () {
 231         fAttrChecker.returnAttrArray (fSchemaAttrs, null);
 232         fSchemaAttrs = null;
 233     }
 234 
 235     // adds an annotation to the list of annotations
 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.
 243     XSAnnotationInfo getAnnotations() {
 244         return fAnnotations;
 245     }
 246 
 247     // removes reference to annotation list
 248     void removeAnnotations() {
 249         fAnnotations = null;
 250     }
 251 
 252 } // XSDocumentInfo