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.jaxp.validation;
  23 
  24 import com.sun.org.apache.xerces.internal.dom.AttrImpl;
  25 import com.sun.org.apache.xerces.internal.dom.CoreDocumentImpl;
  26 import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter;
  27 import com.sun.org.apache.xerces.internal.dom.DocumentTypeImpl;
  28 import com.sun.org.apache.xerces.internal.dom.ElementImpl;
  29 import com.sun.org.apache.xerces.internal.dom.ElementNSImpl;
  30 import com.sun.org.apache.xerces.internal.dom.EntityImpl;
  31 import com.sun.org.apache.xerces.internal.dom.NotationImpl;
  32 import com.sun.org.apache.xerces.internal.dom.PSVIAttrNSImpl;
  33 import com.sun.org.apache.xerces.internal.dom.PSVIDocumentImpl;
  34 import com.sun.org.apache.xerces.internal.dom.PSVIElementNSImpl;
  35 import com.sun.org.apache.xerces.internal.impl.Constants;
  36 import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
  37 import com.sun.org.apache.xerces.internal.xni.Augmentations;
  38 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  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.XMLLocator;
  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.XMLDocumentSource;
  46 import com.sun.org.apache.xerces.internal.xs.AttributePSVI;
  47 import com.sun.org.apache.xerces.internal.xs.ElementPSVI;
  48 import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
  49 import java.util.ArrayList;
  50 import java.util.List;
  51 import javax.xml.transform.dom.DOMResult;
  52 import org.w3c.dom.CDATASection;
  53 import org.w3c.dom.Comment;
  54 import org.w3c.dom.Document;
  55 import org.w3c.dom.DocumentType;
  56 import org.w3c.dom.Element;
  57 import org.w3c.dom.Entity;
  58 import org.w3c.dom.NamedNodeMap;
  59 import org.w3c.dom.Node;
  60 import org.w3c.dom.Notation;
  61 import org.w3c.dom.ProcessingInstruction;
  62 import org.w3c.dom.Text;
  63 
  64 
  65 /**
  66  * <p>DOM result builder.</p>
  67  *
  68  * @author Michael Glavassevich, IBM
  69  */
  70 final class DOMResultBuilder implements DOMDocumentHandler {
  71 
  72     /** Table for quick check of child insertion. */
  73     private final static int[] kidOK;
  74 
  75     static {
  76         kidOK = new int[13];
  77         kidOK[Node.DOCUMENT_NODE] =
  78             1 << Node.ELEMENT_NODE | 1 << Node.PROCESSING_INSTRUCTION_NODE |
  79             1 << Node.COMMENT_NODE | 1 << Node.DOCUMENT_TYPE_NODE;
  80         kidOK[Node.DOCUMENT_FRAGMENT_NODE] =
  81         kidOK[Node.ENTITY_NODE] =
  82         kidOK[Node.ENTITY_REFERENCE_NODE] =
  83         kidOK[Node.ELEMENT_NODE] =
  84             1 << Node.ELEMENT_NODE | 1 << Node.PROCESSING_INSTRUCTION_NODE |
  85             1 << Node.COMMENT_NODE | 1 << Node.TEXT_NODE |
  86             1 << Node.CDATA_SECTION_NODE | 1 << Node.ENTITY_REFERENCE_NODE ;
  87         kidOK[Node.ATTRIBUTE_NODE] = 1 << Node.TEXT_NODE | 1 << Node.ENTITY_REFERENCE_NODE;
  88         kidOK[Node.DOCUMENT_TYPE_NODE] = 0;
  89         kidOK[Node.PROCESSING_INSTRUCTION_NODE] = 0;
  90         kidOK[Node.COMMENT_NODE] = 0;
  91         kidOK[Node.TEXT_NODE] = 0;
  92         kidOK[Node.CDATA_SECTION_NODE] = 0;
  93         kidOK[Node.NOTATION_NODE] = 0;
  94     } // static
  95 
  96     //
  97     // Data
  98     //
  99 
 100     private Document fDocument;
 101     private CoreDocumentImpl fDocumentImpl;
 102     private boolean fStorePSVI;
 103 
 104     private Node fTarget;
 105     private Node fNextSibling;
 106 
 107     private Node fCurrentNode;
 108     private Node fFragmentRoot;
 109 
 110     private final List<Node> fTargetChildren = new ArrayList<>();
 111 
 112     private boolean fIgnoreChars;
 113 
 114     private final QName fAttributeQName = new QName();
 115 
 116     public DOMResultBuilder() {}
 117 
 118     /*
 119      * DOMDocumentHandler methods
 120      */
 121 
 122     public void setDOMResult(DOMResult result) {
 123         fCurrentNode = null;
 124         fFragmentRoot = null;
 125         fIgnoreChars = false;
 126         fTargetChildren.clear();
 127         if (result != null) {
 128             fTarget = result.getNode();
 129             fNextSibling = result.getNextSibling();
 130             fDocument = (fTarget.getNodeType() == Node.DOCUMENT_NODE) ? (Document) fTarget : fTarget.getOwnerDocument();
 131             fDocumentImpl = (fDocument instanceof CoreDocumentImpl) ? (CoreDocumentImpl) fDocument : null;
 132             fStorePSVI = (fDocument instanceof PSVIDocumentImpl);
 133             return;
 134         }
 135         fTarget = null;
 136         fNextSibling = null;
 137         fDocument = null;
 138         fDocumentImpl = null;
 139         fStorePSVI = false;
 140     }
 141 
 142     public void doctypeDecl(DocumentType node) throws XNIException {
 143         /** Create new DocumentType node for the target. */
 144         if (fDocumentImpl != null) {
 145             DocumentType docType = fDocumentImpl.createDocumentType(node.getName(), node.getPublicId(), node.getSystemId());
 146             final String internalSubset = node.getInternalSubset();
 147             /** Copy internal subset. */
 148             if (internalSubset != null) {
 149                 ((DocumentTypeImpl) docType).setInternalSubset(internalSubset);
 150             }
 151             /** Copy entities. */
 152             NamedNodeMap oldMap = node.getEntities();
 153             NamedNodeMap newMap = docType.getEntities();
 154             int length = oldMap.getLength();
 155             for (int i = 0; i < length; ++i) {
 156                 Entity oldEntity = (Entity) oldMap.item(i);
 157                 EntityImpl newEntity = (EntityImpl) fDocumentImpl.createEntity(oldEntity.getNodeName());
 158                 newEntity.setPublicId(oldEntity.getPublicId());
 159                 newEntity.setSystemId(oldEntity.getSystemId());
 160                 newEntity.setNotationName(oldEntity.getNotationName());
 161                 newMap.setNamedItem(newEntity);
 162             }
 163             /** Copy notations. */
 164             oldMap = node.getNotations();
 165             newMap = docType.getNotations();
 166             length = oldMap.getLength();
 167             for (int i = 0; i < length; ++i) {
 168                 Notation oldNotation = (Notation) oldMap.item(i);
 169                 NotationImpl newNotation = (NotationImpl) fDocumentImpl.createNotation(oldNotation.getNodeName());
 170                 newNotation.setPublicId(oldNotation.getPublicId());
 171                 newNotation.setSystemId(oldNotation.getSystemId());
 172                 newMap.setNamedItem(newNotation);
 173             }
 174             append(docType);
 175         }
 176     }
 177 
 178     public void characters(Text node) throws XNIException {
 179         /** Create new Text node for the target. */
 180         append(fDocument.createTextNode(node.getNodeValue()));
 181     }
 182 
 183     public void cdata(CDATASection node) throws XNIException {
 184         /** Create new CDATASection node for the target. */
 185         append(fDocument.createCDATASection(node.getNodeValue()));
 186     }
 187 
 188     public void comment(Comment node) throws XNIException {
 189         /** Create new Comment node for the target. */
 190         append(fDocument.createComment(node.getNodeValue()));
 191     }
 192 
 193     public void processingInstruction(ProcessingInstruction node)
 194             throws XNIException {
 195         /** Create new ProcessingInstruction node for the target. */
 196         append(fDocument.createProcessingInstruction(node.getTarget(), node.getData()));
 197     }
 198 
 199     public void setIgnoringCharacters(boolean ignore) {
 200         fIgnoreChars = ignore;
 201     }
 202 
 203     /*
 204      * XMLDocumentHandler methods
 205      */
 206 
 207     public void startDocument(XMLLocator locator, String encoding,
 208             NamespaceContext namespaceContext, Augmentations augs)
 209             throws XNIException {}
 210 
 211     public void xmlDecl(String version, String encoding, String standalone,
 212             Augmentations augs) throws XNIException {}
 213 
 214     public void doctypeDecl(String rootElement, String publicId,
 215             String systemId, Augmentations augs) throws XNIException {}
 216 
 217     public void comment(XMLString text, Augmentations augs) throws XNIException {}
 218 
 219     public void processingInstruction(String target, XMLString data,
 220             Augmentations augs) throws XNIException {}
 221 
 222     public void startElement(QName element, XMLAttributes attributes,
 223             Augmentations augs) throws XNIException {
 224         Element elem;
 225         int attrCount = attributes.getLength();
 226         if (fDocumentImpl == null) {
 227             elem = fDocument.createElementNS(element.uri, element.rawname);
 228             for (int i = 0; i < attrCount; ++i) {
 229                 attributes.getName(i, fAttributeQName);
 230                 elem.setAttributeNS(fAttributeQName.uri, fAttributeQName.rawname, attributes.getValue(i));
 231             }
 232         }
 233         // If it's a Xerces DOM store type information for attributes, set idness, etc..
 234         else {
 235             elem = fDocumentImpl.createElementNS(element.uri, element.rawname, element.localpart);
 236             for (int i = 0; i < attrCount; ++i) {
 237                 attributes.getName(i, fAttributeQName);
 238                 AttrImpl attr = (AttrImpl) fDocumentImpl.createAttributeNS(fAttributeQName.uri,
 239                         fAttributeQName.rawname, fAttributeQName.localpart);
 240                 attr.setValue(attributes.getValue(i));
 241 
 242                 // write type information to this attribute
 243                 AttributePSVI attrPSVI = (AttributePSVI) attributes.getAugmentations(i).getItem (Constants.ATTRIBUTE_PSVI);
 244                 if (attrPSVI != null) {
 245                     if (fStorePSVI) {
 246                         ((PSVIAttrNSImpl) attr).setPSVI(attrPSVI);
 247                     }
 248                     Object type = attrPSVI.getMemberTypeDefinition();
 249                     if (type == null) {
 250                         type = attrPSVI.getTypeDefinition();
 251                         if (type != null) {
 252                             attr.setType (type);
 253                             if (((XSSimpleType) type).isIDType()) {
 254                                 ((ElementImpl) elem).setIdAttributeNode (attr, true);
 255                             }
 256                         }
 257                     }
 258                     else {
 259                         attr.setType (type);
 260                         if (((XSSimpleType) type).isIDType()) {
 261                             ((ElementImpl) elem).setIdAttributeNode (attr, true);
 262                         }
 263                     }
 264                 }
 265                 attr.setSpecified(attributes.isSpecified(i));
 266                 elem.setAttributeNode(attr);
 267             }
 268         }
 269         append(elem);
 270         fCurrentNode = elem;
 271         if (fFragmentRoot == null) {
 272             fFragmentRoot = elem;
 273         }
 274     }
 275 
 276     public void emptyElement(QName element, XMLAttributes attributes,
 277             Augmentations augs) throws XNIException {
 278         startElement(element, attributes, augs);
 279         endElement(element, augs);
 280     }
 281 
 282     public void startGeneralEntity(String name,
 283             XMLResourceIdentifier identifier, String encoding,
 284             Augmentations augs) throws XNIException {}
 285 
 286     public void textDecl(String version, String encoding, Augmentations augs)
 287             throws XNIException {}
 288 
 289     public void endGeneralEntity(String name, Augmentations augs)
 290             throws XNIException {}
 291 
 292     public void characters(XMLString text, Augmentations augs)
 293             throws XNIException {
 294         if (!fIgnoreChars) {
 295             append(fDocument.createTextNode(text.toString()));
 296         }
 297     }
 298 
 299     public void ignorableWhitespace(XMLString text, Augmentations augs)
 300             throws XNIException {
 301         characters(text, augs);
 302     }
 303 
 304     public void endElement(QName element, Augmentations augs)
 305             throws XNIException {
 306         // write type information to this element
 307         if (augs != null && fDocumentImpl != null) {
 308             ElementPSVI elementPSVI = (ElementPSVI)augs.getItem(Constants.ELEMENT_PSVI);
 309             if (elementPSVI != null) {
 310                 if (fStorePSVI) {
 311                     ((PSVIElementNSImpl)fCurrentNode).setPSVI(elementPSVI);
 312                 }
 313                 XSTypeDefinition type = elementPSVI.getMemberTypeDefinition();
 314                 if (type == null) {
 315                     type = elementPSVI.getTypeDefinition();
 316                 }
 317                 ((ElementNSImpl)fCurrentNode).setType(type);
 318             }
 319         }
 320 
 321         // adjust current node reference
 322         if (fCurrentNode == fFragmentRoot) {
 323             fCurrentNode = null;
 324             fFragmentRoot = null;
 325             return;
 326         }
 327         fCurrentNode = fCurrentNode.getParentNode();
 328     }
 329 
 330     public void startCDATA(Augmentations augs) throws XNIException {}
 331 
 332     public void endCDATA(Augmentations augs) throws XNIException {}
 333 
 334     public void endDocument(Augmentations augs) throws XNIException {
 335         if (fNextSibling == null) {
 336             for (Node node : fTargetChildren) {
 337                 fTarget.appendChild(node);
 338             }
 339         }
 340         else {
 341             for (Node node : fTargetChildren) {
 342                 fTarget.insertBefore(node, fNextSibling);
 343             }
 344         }
 345     }
 346 
 347     public void setDocumentSource(XMLDocumentSource source) {}
 348 
 349     public XMLDocumentSource getDocumentSource() {
 350         return null;
 351     }
 352 
 353     /*
 354      * Other methods
 355      */
 356 
 357     private void append(Node node) throws XNIException {
 358         if (fCurrentNode != null) {
 359             fCurrentNode.appendChild(node);
 360         }
 361         else {
 362             /** Check if this node can be attached to the target. */
 363             if ((kidOK[fTarget.getNodeType()] & (1 << node.getNodeType())) == 0) {
 364                 String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null);
 365                 throw new XNIException(msg);
 366             }
 367             fTargetChildren.add(node);
 368         }
 369     }
 370 
 371 } // DOMResultBuilder