blob: bad23010f11c02eeacc16bc6abe61f0d631c4049 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/*
6 * Copyright 1999-2004 The Apache Software Foundation.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * 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 */
21package com.sun.org.apache.xml.internal.security.c14n.implementations;
22
23import java.lang.reflect.Array;
24import java.util.AbstractList;
25import java.util.ArrayList;
26import java.util.Arrays;
27import java.util.Collection;
28import java.util.HashMap;
29import java.util.Iterator;
30import java.util.List;
31import java.util.Map;
32
33
34
35import org.w3c.dom.Attr;
36import org.w3c.dom.Node;
37
38
39
40/**
41 * A stack based Symble Table.
42 *<br>For speed reasons all the symbols are introduced in the same map,
43 * and at the same time in a list so it can be removed when the frame is pop back.
44 * @author Raul Benito
45 **/
46public class NameSpaceSymbTable {
47
48 /**The map betwen prefix-> entry table. */
49 SymbMap symb = new SymbMap();
50 /**The level of nameSpaces (for Inclusive visibility).*/
51 int nameSpaces=0;
52 /**The stacks for removing the definitions when doing pop.*/
53 List level = new ArrayList();
54 boolean cloned=true;
55 static final String XMLNS="xmlns";
56 /**
57 * Default constractor
58 **/
59 public NameSpaceSymbTable() {
60 //Insert the default binding for xmlns.
61 NameSpaceSymbEntry ne=new NameSpaceSymbEntry("",null,true);
62 ne.lastrendered="";
63 symb.put(XMLNS,ne);
64 }
65
66 /**
67 * Get all the unrendered nodes in the name space.
68 * For Inclusive rendering
69 * @param result the list where to fill the unrendered xmlns definitions.
70 **/
71 public void getUnrenderedNodes(Collection result) {
72 //List result=new ArrayList();
73 Iterator it=symb.entrySet().iterator();
74 while (it.hasNext()) {
75 NameSpaceSymbEntry n=(NameSpaceSymbEntry)(it.next());
76 //put them rendered?
77 if ((!n.rendered) && (n.n!=null)) {
78 result.add(n.n);
79 n.rendered=true;
80 }
81 }
82 }
83
84 /**
85 * Push a frame for visible namespace.
86 * For Inclusive rendering.
87 **/
88 public void outputNodePush() {
89 nameSpaces++;
90 push();
91 }
92
93 /**
94 * Pop a frame for visible namespace.
95 **/
96 public void outputNodePop() {
97 nameSpaces--;
98 pop();
99 }
100
101 /**
102 * Push a frame for a node.
103 * Inclusive or Exclusive.
104 **/
105 public void push() {
106 //Put the number of namespace definitions in the stack.
107 /**if (cloned) {
108 Object ob[]= {symb,cloned ? symb : null};
109 level.add(ob);
110 } **/
111 level.add(null);
112 cloned=false;
113 }
114
115 /**
116 * Pop a frame.
117 * Inclusive or Exclusive.
118 **/
119 public void pop() {
120 int size=level.size()-1;
121 Object ob= level.remove(size);
122 if (ob!=null) {
123 symb=(SymbMap)ob;
124 if (size==0) {
125 cloned=false;
126 } else
127 cloned=(level.get(size-1)!=symb);
128 } else {
129 cloned=false;
130 }
131
132
133 }
134
135 final void needsClone() {
136 if (!cloned) {
137 level.remove(level.size()-1);
138 level.add(symb);
139 symb=(SymbMap) symb.clone();
140 cloned=true;
141 }
142 }
143
144
145 /**
146 * Gets the attribute node that defines the binding for the prefix.
147 * @param prefix the prefix to obtain the attribute.
148 * @return null if there is no need to render the prefix. Otherwise the node of
149 * definition.
150 **/
151 public Attr getMapping(String prefix) {
152 NameSpaceSymbEntry entry=symb.get(prefix);
153 if (entry==null) {
154 //There is no definition for the prefix(a bug?).
155 return null;
156 }
157 if (entry.rendered) {
158 //No need to render an entry already rendered.
159 return null;
160 }
161 // Mark this entry as render.
162 entry=(NameSpaceSymbEntry) entry.clone();
163 needsClone();
164 symb.put(prefix,entry);
165 entry.rendered=true;
166 entry.level=nameSpaces;
167 entry.lastrendered=entry.uri;
168 // Return the node for outputing.
169 return entry.n;
170 }
171
172 /**
173 * Gets a definition without mark it as render.
174 * For render in exclusive c14n the namespaces in the include prefixes.
175 * @param prefix The prefix whose definition is neaded.
176 * @return the attr to render, null if there is no need to render
177 **/
178 public Attr getMappingWithoutRendered(String prefix) {
179 NameSpaceSymbEntry entry= symb.get(prefix);
180 if (entry==null) {
181 return null;
182 }
183 if (entry.rendered) {
184 return null;
185 }
186 return entry.n;
187 }
188
189 /**
190 * Adds the mapping for a prefix.
191 * @param prefix the prefix of definition
192 * @param uri the Uri of the definition
193 * @param n the attribute that have the definition
194 * @return true if there is already defined.
195 **/
196 public boolean addMapping(String prefix, String uri,Attr n) {
197 NameSpaceSymbEntry ob = symb.get(prefix);
198 if ((ob!=null) && uri.equals(ob.uri)) {
199 //If we have it previously defined. Don't keep working.
200 return false;
201 }
202 //Creates and entry in the table for this new definition.
203 NameSpaceSymbEntry ne=new NameSpaceSymbEntry(uri,n,false);
204 needsClone();
205 symb.put(prefix, ne);
206 if (ob != null) {
207 //We have a previous definition store it for the pop.
208 //Check if a previous definition(not the inmidiatly one) has been rendered.
209 ne.lastrendered=ob.lastrendered;
210 if ((ob.lastrendered!=null)&& (ob.lastrendered.equals(uri))) {
211 //Yes it is. Mark as rendered.
212 ne.rendered=true;
213 }
214 }
215 return true;
216 }
217
218 /**
219 * Adds a definition and mark it as render.
220 * For inclusive c14n.
221 * @param prefix the prefix of definition
222 * @param uri the Uri of the definition
223 * @param n the attribute that have the definition
224 * @return the attr to render, null if there is no need to render
225 **/
226 public Node addMappingAndRender(String prefix, String uri,Attr n) {
227 NameSpaceSymbEntry ob = symb.get(prefix);
228
229 if ((ob!=null) && uri.equals(ob.uri)) {
230 if (!ob.rendered) {
231 ob=(NameSpaceSymbEntry) ob.clone();
232 needsClone();
233 symb.put(prefix,ob);
234 ob.lastrendered=uri;
235 ob.rendered=true;
236 return ob.n;
237 }
238 return null;
239 }
240
241 NameSpaceSymbEntry ne=new NameSpaceSymbEntry(uri,n,true);
242 ne.lastrendered=uri;
243 needsClone();
244 symb.put(prefix, ne);
245 if (ob != null) {
246
247 if ((ob.lastrendered!=null)&& (ob.lastrendered.equals(uri))) {
248 ne.rendered=true;
249 return null;
250 }
251 }
252 return ne.n;
253 }
254 /**
255 * Adds & gets(if needed) the attribute node that defines the binding for the prefix.
256 * Take on account if the rules of rendering in the inclusive c14n.
257 * For inclusive c14n.
258 * @param prefix the prefix to obtain the attribute.
259 * @param outputNode the container element is an output element.
260 * @param uri the Uri of the definition
261 * @param n the attribute that have the definition
262 * @return null if there is no need to render the prefix. Otherwise the node of
263 * definition.
264 **/
265 public Node addMappingAndRenderXNodeSet(String prefix, String uri,Attr n,boolean outputNode) {
266 NameSpaceSymbEntry ob = symb.get(prefix);
267 int visibleNameSpaces=nameSpaces;
268 if ((ob!=null) && uri.equals(ob.uri)) {
269 if (!ob.rendered) {
270 ob=(NameSpaceSymbEntry)ob.clone();
271 needsClone();
272 symb.put(prefix,ob);
273 ob.rendered=true;
274 ob.level=visibleNameSpaces;
275 return ob.n;
276 }
277 ob=(NameSpaceSymbEntry)ob.clone();
278 needsClone();
279 symb.put(prefix,ob);
280 if (outputNode && (((visibleNameSpaces-ob.level)<2) || XMLNS.equals(prefix)) ) {
281 ob.level=visibleNameSpaces;
282 return null; //Already rendered, just return nulll
283 }
284 ob.level=visibleNameSpaces;
285 return ob.n;
286 }
287
288 NameSpaceSymbEntry ne=new NameSpaceSymbEntry(uri,n,true);
289 ne.level=nameSpaces;
290 ne.rendered=true;
291 needsClone();
292 symb.put(prefix, ne);
293 if (ob != null) {
294 ne.lastrendered=ob.lastrendered;
295
296 if ((ob.lastrendered!=null)&& (ob.lastrendered.equals(uri))) {
297 ne.rendered=true;
298 }
299 }
300 return ne.n;
301 }
302}
303
304/**
305 * The internal structure of NameSpaceSymbTable.
306 **/
307class NameSpaceSymbEntry implements Cloneable {
308 NameSpaceSymbEntry(String name,Attr n,boolean rendered) {
309 this.uri=name;
310 this.rendered=rendered;
311 this.n=n;
312 }
313 /** @inheritDoc */
314 public Object clone() {
315 try {
316 return super.clone();
317 } catch (CloneNotSupportedException e) {
318 return null;
319 }
320 }
321 /** The level where the definition was rendered(Only for inclusive) */
322 int level=0;
323 /**The URI that the prefix defines */
324 String uri;
325 /**The last output in the URI for this prefix (This for speed reason).*/
326 String lastrendered=null;
327 /**This prefix-URI has been already render or not.*/
328 boolean rendered=false;
329 /**The attribute to include.*/
330 Attr n;
331};
332
333class SymbMap implements Cloneable{
334 int free=23;
335 NameSpaceSymbEntry[] entries=new NameSpaceSymbEntry[free];
336 String[] keys=new String[free];
337
338 void put(String key, NameSpaceSymbEntry value) {
339 int index = index(key);
340 Object oldKey = keys[index];
341 keys[index] = key;
342 entries[index] = value;
343 if (oldKey==null || !oldKey.equals(key)) {
344 if (--free == 0) {
345 free=entries.length;
346 int newCapacity = free<<2;
347 rehash(newCapacity);
348 }
349 }
350 }
351
352 List entrySet() {
353 List a=new ArrayList();
354 for (int i=0;i<entries.length;i++) {
355 if ((entries[i]!=null) && !("".equals(entries[i]))) {
356 a.add(entries[i]);
357 }
358 }
359 return a;
360 }
361
362
363 protected int index(Object obj) {
364 Object[] set = keys;
365 int length = set.length;
366 //abs of index
367 int index = (obj.hashCode() & 0x7fffffff) % length;
368 Object cur = set[index];
369
370 if (cur == null || (cur.equals( obj))) {
371 return index;
372 }
373 do {
374 index=index==length? 0:++index;
375 cur = set[index];
376 } while (cur != null && (!cur.equals(obj)));
377 return index;
378 }
379 /**
380 * rehashes the map to the new capacity.
381 *
382 * @param newCapacity an <code>int</code> value
383 */
384 protected void rehash(int newCapacity) {
385 int oldCapacity = keys.length;
386 String oldKeys[] = keys;
387 NameSpaceSymbEntry oldVals[] = entries;
388
389 keys = new String[newCapacity];
390 entries = new NameSpaceSymbEntry[newCapacity];
391
392 for (int i = oldCapacity; i-- > 0;) {
393 if(oldKeys[i] != null) {
394 String o = oldKeys[i];
395 int index = index(o);
396 keys[index] = o;
397 entries[index] = oldVals[i];
398 }
399 }
400 }
401 NameSpaceSymbEntry get(String key) {
402 return entries[index(key)];
403 }
404 protected Object clone() {
405 // TODO Auto-generated method stub
406 try {
407 SymbMap copy=(SymbMap) super.clone();
408 copy.entries=new NameSpaceSymbEntry[entries.length];
409 System.arraycopy(entries,0,copy.entries,0,entries.length);
410 copy.keys=new String[keys.length];
411 System.arraycopy(keys,0,copy.keys,0,keys.length);
412
413 return copy;
414 } catch (CloneNotSupportedException e) {
415 // TODO Auto-generated catch block
416 e.printStackTrace();
417 }
418 return null;
419 }
420}