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.xpointer;
22 
23 import com.sun.org.apache.xerces.internal.impl.Constants;
24 import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
25 import com.sun.org.apache.xerces.internal.util.SymbolTable;
26 import com.sun.org.apache.xerces.internal.xni.Augmentations;
27 import com.sun.org.apache.xerces.internal.xni.QName;
28 import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
29 import com.sun.org.apache.xerces.internal.xni.XNIException;
30 import com.sun.org.apache.xerces.internal.xs.AttributePSVI;
31 import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
32 
33 /**
34  * <p>
35  * Implements the XPointerPart interface and handles processing of
36  * ShortHand Pointers.  It identifies at most one element in the
37  * resource's information set; specifically, the first one (if any)
38  * in document order that has a matching NCName as an identifier.
39  * </p>
40  *
41  */
42 final class ShortHandPointer implements XPointerPart {
43 
44     // The name of the ShortHand pointer
45     private String fShortHandPointer;
46 
47     // The name of the ShortHand pointer
48     private boolean fIsFragmentResolved = false;
49 
50     // SymbolTable
51     private SymbolTable fSymbolTable;
52 
53     //
54     // Constructors
55     //
ShortHandPointer()56     public ShortHandPointer() {
57     }
58 
ShortHandPointer(SymbolTable symbolTable)59     public ShortHandPointer(SymbolTable symbolTable) {
60         fSymbolTable = symbolTable;
61     }
62 
63     /**
64      * The XPointerProcessor takes care of this.  Simply set the ShortHand Pointer here.
65      *
66      * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#parseXPointer(java.lang.String)
67      */
parseXPointer(String part)68     public void parseXPointer(String part) throws XNIException {
69         fShortHandPointer = part;
70         // reset fIsFragmentResolved
71         fIsFragmentResolved = false;
72     }
73 
74     /**
75      * Resolves the XPointer ShortHand pointer based on the rules defined in
76      * Section 3.2 of the XPointer Framework Recommendation.
77      * Note that in the current implementation only supports DTD determined ID's.
78      *
79      * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#resolveXPointer(com.sun.org.apache.xerces.internal.xni.QName, com.sun.org.apache.xerces.internal.xni.XMLAttributes, com.sun.org.apache.xerces.internal.xni.Augmentations, int event)
80      */
81     int fMatchingChildCount = 0;
resolveXPointer(QName element, XMLAttributes attributes, Augmentations augs, int event)82     public boolean resolveXPointer(QName element, XMLAttributes attributes,
83             Augmentations augs, int event) throws XNIException {
84 
85         // reset fIsFragmentResolved
86         if (fMatchingChildCount == 0) {
87             fIsFragmentResolved = false;
88         }
89 
90         // On startElement or emptyElement, if no matching elements or parent
91         // elements were found, check for a matching idenfitier.
92         if (event == XPointerPart.EVENT_ELEMENT_START) {
93             if (fMatchingChildCount == 0) {
94                 fIsFragmentResolved = hasMatchingIdentifier(element, attributes, augs,
95                     event);
96             }
97             if (fIsFragmentResolved) {
98                fMatchingChildCount++;
99             }
100         } else if (event == XPointerPart.EVENT_ELEMENT_EMPTY) {
101             if (fMatchingChildCount == 0) {
102                 fIsFragmentResolved = hasMatchingIdentifier(element, attributes, augs,
103                     event);
104             }
105         }
106         else {
107             // On endElement, decrease the matching child count if the child or
108             // its parent was resolved.
109             if (fIsFragmentResolved) {
110                 fMatchingChildCount--;
111             }
112         }
113 
114         return fIsFragmentResolved ;
115     }
116 
117     /**
118      *
119      * @param element
120      * @param attributes
121      * @param augs
122      * @param event
123      * @return
124      * @throws XNIException
125      */
hasMatchingIdentifier(QName element, XMLAttributes attributes, Augmentations augs, int event)126     private boolean hasMatchingIdentifier(QName element,
127             XMLAttributes attributes, Augmentations augs, int event)
128     throws XNIException {
129         String normalizedValue = null;
130 
131         // The identifiers of an element are determined by the
132         // ShortHand Pointer as follows:
133 
134         if (attributes != null) {
135             for (int i = 0; i < attributes.getLength(); i++) {
136 
137                 // 1. If an element information item has an attribute information item
138                 // among its [attributes] that is a schema-determined ID, then it is
139                 // identified by the value of that attribute information item's
140                 // [schema normalized value] property;
141                 normalizedValue = getSchemaDeterminedID(attributes, i);
142                 if (normalizedValue != null) {
143                     break;
144                 }
145 
146                 // 2. If an element information item has an element information item among
147                 // its [children] that is a schema-determined ID, then it is identified by
148                 // the value of that element information item's [schema normalized value] property;
149                 // ???
150                 normalizedValue = getChildrenSchemaDeterminedID(attributes, i);
151                 if (normalizedValue != null) {
152                     break;
153                 }
154 
155                 // 3. If an element information item has an attribute information item among
156                 // its [attributes] that is a DTD-determined ID, then it is identified by the
157                 // value of that attribute information item's [normalized value] property.
158                 // An attribute information item is a DTD-determined ID if and only if it has
159                 // a [type definition] property whose value is equal to ID.
160                 normalizedValue = getDTDDeterminedID(attributes, i);
161                 if (normalizedValue != null) {
162                     break;
163                 }
164                 // 4. No externally determined ID's
165             }
166         }
167 
168         if (normalizedValue != null
169                 && normalizedValue.equals(fShortHandPointer)) {
170             return true;
171         }
172 
173         return false;
174     }
175 
176     /**
177      * Rerturns the DTD determine-ID
178      *
179      * @param attributes
180      * @param index
181      * @return String
182      * @throws XNIException
183      */
getDTDDeterminedID(XMLAttributes attributes, int index)184     public String getDTDDeterminedID(XMLAttributes attributes, int index)
185     throws XNIException {
186 
187         if (attributes.getType(index).equals("ID")) {
188             return attributes.getValue(index);
189         }
190         return null;
191     }
192 
193     /**
194      * Returns the schema-determined-ID.
195      *
196      *
197      * @param attributes
198      * @param index
199      * @return A String containing the schema-determined ID.
200      * @throws XNIException
201      */
getSchemaDeterminedID(XMLAttributes attributes, int index)202     public String getSchemaDeterminedID(XMLAttributes attributes, int index)
203     throws XNIException {
204         Augmentations augs = attributes.getAugmentations(index);
205         AttributePSVI attrPSVI = (AttributePSVI) augs
206         .getItem(Constants.ATTRIBUTE_PSVI);
207 
208         if (attrPSVI != null) {
209             // An element or attribute information item is a schema-determined
210             // ID if and only if one of the following is true:]
211 
212             // 1. It has a [member type definition] or [type definition] property
213             // whose value in turn has [name] equal to ID and [target namespace]
214             // equal to http://www.w3.org/2001/XMLSchema;
215 
216             // 2. It has a [base type definition] whose value has that [name] and [target namespace];
217 
218             // 3. It has a [base type definition] whose value has a [base type definition]
219             // whose value has that [name] and [target namespace], and so on following
220             // the [base type definition] property recursively;
221 
222             XSTypeDefinition typeDef = attrPSVI.getMemberTypeDefinition();
223             if (typeDef != null) {
224                 typeDef = attrPSVI.getTypeDefinition();
225             }
226 
227             //
228             if (typeDef != null && ((XSSimpleType) typeDef).isIDType()) {
229                 return attrPSVI.getSchemaValue().getNormalizedValue();
230             }
231 
232             // 4 & 5 NA
233         }
234 
235         return null;
236     }
237 
238     /**
239      * Not quite sure how this can be correctly implemented.
240      *
241      * @param attributes
242      * @param index
243      * @return String - We return null since we currenly do not supprt this.
244      * @throws XNIException
245      */
getChildrenSchemaDeterminedID(XMLAttributes attributes, int index)246     public String getChildrenSchemaDeterminedID(XMLAttributes attributes,
247             int index) throws XNIException {
248         return null;
249     }
250 
251     /**
252      *
253      * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#isFragmentResolved()
254      */
isFragmentResolved()255     public boolean isFragmentResolved() {
256         return fIsFragmentResolved;
257     }
258 
259     /**
260      *
261      * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#isChildFragmentResolved()
262      */
isChildFragmentResolved()263     public boolean isChildFragmentResolved() {
264         return fIsFragmentResolved && ( fMatchingChildCount >  0);
265     }
266 
267     /**
268      * Returns the name of the ShortHand pointer
269      *
270      * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#getSchemeName()
271      */
getSchemeName()272     public String getSchemeName() {
273         return fShortHandPointer;
274     }
275 
276     /**
277      * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#getSchemeData()
278      */
getSchemeData()279     public String getSchemeData() {
280         return null;
281     }
282 
283     /**
284      * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#setSchemeName(java.lang.String)
285      */
setSchemeName(String schemeName)286     public void setSchemeName(String schemeName) {
287         fShortHandPointer = schemeName;
288     }
289 
290     /**
291      * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#setSchemeData(java.lang.String)
292      */
setSchemeData(String schemeData)293     public void setSchemeData(String schemeData) {
294         // NA
295     }
296 }
297