1 /* 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 */ 21 package com.sun.org.apache.xml.internal.security.c14n.implementations; 22 23 import java.util.ArrayList; 24 import java.util.Collection; 25 import java.util.Iterator; 26 import java.util.List; 27 28 29 import org.w3c.dom.Attr; 30 import org.w3c.dom.Node; 31 32 33 34 /** 35 * A stack based Symble Table. 36 *<br>For speed reasons all the symbols are introduced in the same map, 37 * and at the same time in a list so it can be removed when the frame is pop back. 38 * @author Raul Benito 39 **/ 40 public class NameSpaceSymbTable { 41 42 /**The map betwen prefix-> entry table. */ 43 SymbMap symb; 44 /**The level of nameSpaces (for Inclusive visibility).*/ 45 int nameSpaces=0; 46 /**The stacks for removing the definitions when doing pop.*/ 47 List<SymbMap> level; 48 boolean cloned=true; 49 static final String XMLNS="xmlns"; 50 final static SymbMap initialMap=new SymbMap(); 51 static { 52 NameSpaceSymbEntry ne=new NameSpaceSymbEntry("",null,true,XMLNS); 53 ne.lastrendered=""; 54 initialMap.put(XMLNS,ne); 55 } 56 /** 57 * Default constractor 58 **/ 59 public NameSpaceSymbTable() { 60 level = new ArrayList<SymbMap>(10); 61 //Insert the default binding for xmlns. 62 symb=(SymbMap) initialMap.clone(); 63 } 64 65 /** 66 * Get all the unrendered nodes in the name space. 67 * For Inclusive rendering 68 * @param result the list where to fill the unrendered xmlns definitions. 69 **/ 70 public void getUnrenderedNodes(Collection<Attr> result) { 71 //List result=new ArrayList(); 72 Iterator<NameSpaceSymbEntry> it=symb.entrySet().iterator(); 73 while (it.hasNext()) { 74 NameSpaceSymbEntry n= it.next(); 75 //put them rendered? 76 if ((!n.rendered) && (n.n!=null)) { 77 n=(NameSpaceSymbEntry) n.clone(); 78 needsClone(); 79 symb.put(n.prefix,n); 80 n.lastrendered=n.uri; 81 n.rendered=true; 82 83 result.add(n.n); 84 85 } 86 } 87 } 88 89 /** 90 * Push a frame for visible namespace. 91 * For Inclusive rendering. 92 **/ 93 public void outputNodePush() { 94 nameSpaces++; 95 push(); 96 } 97 98 /** 99 * Pop a frame for visible namespace. 100 **/ 101 public void outputNodePop() { 102 nameSpaces--; 103 pop(); 104 } 105 106 /** 107 * Push a frame for a node. 108 * Inclusive or Exclusive. 109 **/ 110 public void push() { 111 //Put the number of namespace definitions in the stack. 112 level.add(null); 113 cloned=false; 114 } 115 116 /** 117 * Pop a frame. 118 * Inclusive or Exclusive. 119 **/ 120 public void pop() { 121 int size=level.size()-1; 122 Object ob= level.remove(size); 123 if (ob!=null) { 124 symb=(SymbMap)ob; 125 if (size==0) { 126 cloned=false; 127 } else 128 cloned=(level.get(size-1)!=symb); 129 } else { 130 cloned=false; 131 } 132 133 134 } 135 136 final void needsClone() { 137 if (!cloned) { 138 level.set(level.size()-1,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,prefix); 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,prefix); 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 public int getLevel() { 256 // TODO Auto-generated method stub 257 return level.size(); 258 } 259 260 public void removeMapping(String prefix) { 261 NameSpaceSymbEntry ob = symb.get(prefix); 262 263 if (ob!=null) { 264 needsClone(); 265 symb.put(prefix,null); 266 } 267 } 268 269 public void removeMappingIfNotRender(String prefix) { 270 NameSpaceSymbEntry ob = symb.get(prefix); 271 272 if (ob!=null && !ob.rendered) { 273 needsClone(); 274 symb.put(prefix,null); 275 } 276 } 277 278 public boolean removeMappingIfRender(String prefix) { 279 NameSpaceSymbEntry ob = symb.get(prefix); 280 281 if (ob!=null && ob.rendered) { 282 needsClone(); 283 symb.put(prefix,null); 284 } 285 return false; 286 } 287 } 288 289 /** 290 * The internal structure of NameSpaceSymbTable. 291 **/ 292 class NameSpaceSymbEntry implements Cloneable { 293 NameSpaceSymbEntry(String name,Attr n,boolean rendered,String prefix) { 294 this.uri=name; 295 this.rendered=rendered; 296 this.n=n; 297 this.prefix=prefix; 298 } 299 /** @inheritDoc */ 300 public Object clone() { 301 try { 302 return super.clone(); 303 } catch (CloneNotSupportedException e) { 304 return null; 305 } 306 } 307 /** The level where the definition was rendered(Only for inclusive) */ 308 int level=0; 309 String prefix; 310 /**The URI that the prefix defines */ 311 String uri; 312 /**The last output in the URI for this prefix (This for speed reason).*/ 313 String lastrendered=null; 314 /**This prefix-URI has been already render or not.*/ 315 boolean rendered=false; 316 /**The attribute to include.*/ 317 Attr n; 318 }; 319 320 class SymbMap implements Cloneable { 321 int free=23; 322 NameSpaceSymbEntry[] entries; 323 String[] keys; 324 SymbMap() { 325 entries=new NameSpaceSymbEntry[free]; 326 keys=new String[free]; 327 } 328 void put(String key, NameSpaceSymbEntry value) { 329 int index = index(key); 330 Object oldKey = keys[index]; 331 keys[index] = key; 332 entries[index] = value; 333 if (oldKey==null || !oldKey.equals(key)) { 334 if (--free == 0) { 335 free=entries.length; 336 int newCapacity = free<<2; 337 rehash(newCapacity); 338 } 339 } 340 } 341 342 List<NameSpaceSymbEntry> entrySet() { 343 List<NameSpaceSymbEntry> a=new ArrayList<NameSpaceSymbEntry>(); 344 for (int i=0;i<entries.length;i++) { 345 if ((entries[i]!=null) && !("".equals(entries[i].uri))) { 346 a.add(entries[i]); 347 } 348 } 349 return a; 350 } 351 352 protected int index(Object obj) { 353 Object[] set = keys; 354 int length = set.length; 355 //abs of index 356 int index = (obj.hashCode() & 0x7fffffff) % length; 357 Object cur = set[index]; 358 359 if (cur == null || (cur.equals( obj))) { 360 return index; 361 } 362 length=length-1; 363 do { 364 index=index==length? 0:++index; 365 cur = set[index]; 366 } while (cur != null && (!cur.equals(obj))); 367 return index; 368 } 369 370 /** 371 * rehashes the map to the new capacity. 372 * 373 * @param newCapacity an <code>int</code> value 374 */ 375 protected void rehash(int newCapacity) { 376 int oldCapacity = keys.length; 377 String oldKeys[] = keys; 378 NameSpaceSymbEntry oldVals[] = entries; 379 380 keys = new String[newCapacity]; 381 entries = new NameSpaceSymbEntry[newCapacity]; 382 383 for (int i = oldCapacity; i-- > 0;) { 384 if(oldKeys[i] != null) { 385 String o = oldKeys[i]; 386 int index = index(o); 387 keys[index] = o; 388 entries[index] = oldVals[i]; 389 } 390 } 391 } 392 393 NameSpaceSymbEntry get(String key) { 394 return entries[index(key)]; 395 } 396 397 protected Object clone() { 398 try { 399 SymbMap copy=(SymbMap) super.clone(); 400 copy.entries=new NameSpaceSymbEntry[entries.length]; 401 System.arraycopy(entries,0,copy.entries,0,entries.length); 402 copy.keys=new String[keys.length]; 403 System.arraycopy(keys,0,copy.keys,0,keys.length); 404 405 return copy; 406 } catch (CloneNotSupportedException e) { 407 // TODO Auto-generated catch block 408 e.printStackTrace(); 409 } 410 return null; 411 } 412 }