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.jaxp.validation;
22 
23 import com.sun.org.apache.xerces.internal.dom.AttrImpl;
24 import com.sun.org.apache.xerces.internal.dom.CoreDocumentImpl;
25 import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter;
26 import com.sun.org.apache.xerces.internal.dom.DocumentTypeImpl;
27 import com.sun.org.apache.xerces.internal.dom.ElementImpl;
28 import com.sun.org.apache.xerces.internal.dom.ElementNSImpl;
29 import com.sun.org.apache.xerces.internal.dom.EntityImpl;
30 import com.sun.org.apache.xerces.internal.dom.NotationImpl;
31 import com.sun.org.apache.xerces.internal.dom.PSVIAttrNSImpl;
32 import com.sun.org.apache.xerces.internal.dom.PSVIDocumentImpl;
33 import com.sun.org.apache.xerces.internal.dom.PSVIElementNSImpl;
34 import com.sun.org.apache.xerces.internal.impl.Constants;
35 import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
36 import com.sun.org.apache.xerces.internal.xni.Augmentations;
37 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
38 import com.sun.org.apache.xerces.internal.xni.QName;
39 import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
40 import com.sun.org.apache.xerces.internal.xni.XMLLocator;
41 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
42 import com.sun.org.apache.xerces.internal.xni.XMLString;
43 import com.sun.org.apache.xerces.internal.xni.XNIException;
44 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
45 import com.sun.org.apache.xerces.internal.xs.AttributePSVI;
46 import com.sun.org.apache.xerces.internal.xs.ElementPSVI;
47 import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
48 import java.util.ArrayList;
49 import java.util.List;
50 import javax.xml.transform.dom.DOMResult;
51 import org.w3c.dom.CDATASection;
52 import org.w3c.dom.Comment;
53 import org.w3c.dom.Document;
54 import org.w3c.dom.DocumentType;
55 import org.w3c.dom.Element;
56 import org.w3c.dom.Entity;
57 import org.w3c.dom.NamedNodeMap;
58 import org.w3c.dom.Node;
59 import org.w3c.dom.Notation;
60 import org.w3c.dom.ProcessingInstruction;
61 import org.w3c.dom.Text;
62 
63 
64 /**
65  * <p>DOM result builder.</p>
66  *
67  * @author Michael Glavassevich, IBM
68  * @LastModified: Oct 2017
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 
DOMResultBuilder()116     public DOMResultBuilder() {}
117 
118     /*
119      * DOMDocumentHandler methods
120      */
121 
setDOMResult(DOMResult result)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 
doctypeDecl(DocumentType node)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 
characters(Text node)178     public void characters(Text node) throws XNIException {
179         /** Create new Text node for the target. */
180         append(fDocument.createTextNode(node.getNodeValue()));
181     }
182 
cdata(CDATASection node)183     public void cdata(CDATASection node) throws XNIException {
184         /** Create new CDATASection node for the target. */
185         append(fDocument.createCDATASection(node.getNodeValue()));
186     }
187 
comment(Comment node)188     public void comment(Comment node) throws XNIException {
189         /** Create new Comment node for the target. */
190         append(fDocument.createComment(node.getNodeValue()));
191     }
192 
processingInstruction(ProcessingInstruction node)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 
setIgnoringCharacters(boolean ignore)199     public void setIgnoringCharacters(boolean ignore) {
200         fIgnoreChars = ignore;
201     }
202 
203     /*
204      * XMLDocumentHandler methods
205      */
206 
startDocument(XMLLocator locator, String encoding, NamespaceContext namespaceContext, Augmentations augs)207     public void startDocument(XMLLocator locator, String encoding,
208             NamespaceContext namespaceContext, Augmentations augs)
209             throws XNIException {}
210 
xmlDecl(String version, String encoding, String standalone, Augmentations augs)211     public void xmlDecl(String version, String encoding, String standalone,
212             Augmentations augs) throws XNIException {}
213 
doctypeDecl(String rootElement, String publicId, String systemId, Augmentations augs)214     public void doctypeDecl(String rootElement, String publicId,
215             String systemId, Augmentations augs) throws XNIException {}
216 
comment(XMLString text, Augmentations augs)217     public void comment(XMLString text, Augmentations augs) throws XNIException {}
218 
processingInstruction(String target, XMLString data, Augmentations augs)219     public void processingInstruction(String target, XMLString data,
220             Augmentations augs) throws XNIException {}
221 
startElement(QName element, XMLAttributes attributes, Augmentations augs)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 
emptyElement(QName element, XMLAttributes attributes, Augmentations augs)276     public void emptyElement(QName element, XMLAttributes attributes,
277             Augmentations augs) throws XNIException {
278         startElement(element, attributes, augs);
279         endElement(element, augs);
280     }
281 
startGeneralEntity(String name, XMLResourceIdentifier identifier, String encoding, Augmentations augs)282     public void startGeneralEntity(String name,
283             XMLResourceIdentifier identifier, String encoding,
284             Augmentations augs) throws XNIException {}
285 
textDecl(String version, String encoding, Augmentations augs)286     public void textDecl(String version, String encoding, Augmentations augs)
287             throws XNIException {}
288 
endGeneralEntity(String name, Augmentations augs)289     public void endGeneralEntity(String name, Augmentations augs)
290             throws XNIException {}
291 
characters(XMLString text, Augmentations augs)292     public void characters(XMLString text, Augmentations augs)
293             throws XNIException {
294         if (!fIgnoreChars) {
295             append(fDocument.createTextNode(text.toString()));
296         }
297     }
298 
ignorableWhitespace(XMLString text, Augmentations augs)299     public void ignorableWhitespace(XMLString text, Augmentations augs)
300             throws XNIException {
301         characters(text, augs);
302     }
303 
endElement(QName element, Augmentations augs)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 
startCDATA(Augmentations augs)330     public void startCDATA(Augmentations augs) throws XNIException {}
331 
endCDATA(Augmentations augs)332     public void endCDATA(Augmentations augs) throws XNIException {}
333 
endDocument(Augmentations augs)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 
setDocumentSource(XMLDocumentSource source)347     public void setDocumentSource(XMLDocumentSource source) {}
348 
getDocumentSource()349     public XMLDocumentSource getDocumentSource() {
350         return null;
351     }
352 
353     /*
354      * Other methods
355      */
356 
append(Node node)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
372