| /* |
| * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| * THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC. |
| */ |
| |
| package com.sun.xml.internal.fastinfoset.util; |
| |
| import com.sun.xml.internal.fastinfoset.EncodingConstants; |
| import com.sun.xml.internal.fastinfoset.CommonResourceBundle; |
| import java.util.Iterator; |
| import java.util.NoSuchElementException; |
| import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetException; |
| |
| public class PrefixArray extends ValueArray { |
| public static final int PREFIX_MAP_SIZE = 64; |
| |
| private int _initialCapacity; |
| |
| public String[] _array; |
| |
| private PrefixArray _readOnlyArray; |
| |
| private static class PrefixEntry { |
| private PrefixEntry next; |
| private int prefixId; |
| } |
| |
| private PrefixEntry[] _prefixMap = new PrefixEntry[PREFIX_MAP_SIZE]; |
| |
| private PrefixEntry _prefixPool; |
| |
| private static class NamespaceEntry { |
| private NamespaceEntry next; |
| private int declarationId; |
| private int namespaceIndex; |
| |
| private String prefix; |
| private String namespaceName; |
| private int prefixEntryIndex; |
| } |
| |
| private NamespaceEntry _namespacePool; |
| |
| private NamespaceEntry[] _inScopeNamespaces; |
| |
| public int[] _currentInScope; |
| |
| public int _declarationId; |
| |
| public PrefixArray(int initialCapacity, int maximumCapacity) { |
| _initialCapacity = initialCapacity; |
| _maximumCapacity = maximumCapacity; |
| |
| _array = new String[initialCapacity]; |
| // Sizes of _inScopeNamespaces and _currentInScope need to be two |
| // greater than _array because 0 represents the empty string and |
| // 1 represents the xml prefix |
| _inScopeNamespaces = new NamespaceEntry[initialCapacity + 2]; |
| _currentInScope = new int[initialCapacity + 2]; |
| |
| increaseNamespacePool(initialCapacity); |
| increasePrefixPool(initialCapacity); |
| |
| initializeEntries(); |
| } |
| |
| public PrefixArray() { |
| this(DEFAULT_CAPACITY, MAXIMUM_CAPACITY); |
| } |
| |
| private final void initializeEntries() { |
| _inScopeNamespaces[0] = _namespacePool; |
| _namespacePool = _namespacePool.next; |
| _inScopeNamespaces[0].next = null; |
| _inScopeNamespaces[0].prefix = ""; |
| _inScopeNamespaces[0].namespaceName = ""; |
| _inScopeNamespaces[0].namespaceIndex = _currentInScope[0] = 0; |
| |
| int index = KeyIntMap.indexFor(KeyIntMap.hashHash(_inScopeNamespaces[0].prefix.hashCode()), _prefixMap.length); |
| _prefixMap[index] = _prefixPool; |
| _prefixPool = _prefixPool.next; |
| _prefixMap[index].next = null; |
| _prefixMap[index].prefixId = 0; |
| |
| |
| _inScopeNamespaces[1] = _namespacePool; |
| _namespacePool = _namespacePool.next; |
| _inScopeNamespaces[1].next = null; |
| _inScopeNamespaces[1].prefix = EncodingConstants.XML_NAMESPACE_PREFIX; |
| _inScopeNamespaces[1].namespaceName = EncodingConstants.XML_NAMESPACE_NAME; |
| _inScopeNamespaces[1].namespaceIndex = _currentInScope[1] = 1; |
| |
| index = KeyIntMap.indexFor(KeyIntMap.hashHash(_inScopeNamespaces[1].prefix.hashCode()), _prefixMap.length); |
| if (_prefixMap[index] == null) { |
| _prefixMap[index] = _prefixPool; |
| _prefixPool = _prefixPool.next; |
| _prefixMap[index].next = null; |
| } else { |
| final PrefixEntry e = _prefixMap[index]; |
| _prefixMap[index] = _prefixPool; |
| _prefixPool = _prefixPool.next; |
| _prefixMap[index].next = e; |
| } |
| _prefixMap[index].prefixId = 1; |
| } |
| |
| private final void increaseNamespacePool(int capacity) { |
| if (_namespacePool == null) { |
| _namespacePool = new NamespaceEntry(); |
| } |
| |
| for (int i = 0; i < capacity; i++) { |
| NamespaceEntry ne = new NamespaceEntry(); |
| ne.next = _namespacePool; |
| _namespacePool = ne; |
| } |
| } |
| |
| private final void increasePrefixPool(int capacity) { |
| if (_prefixPool == null) { |
| _prefixPool = new PrefixEntry(); |
| } |
| |
| for (int i = 0; i < capacity; i++) { |
| PrefixEntry pe = new PrefixEntry(); |
| pe.next = _prefixPool; |
| _prefixPool = pe; |
| } |
| } |
| |
| public int countNamespacePool() { |
| int i = 0; |
| NamespaceEntry e = _namespacePool; |
| while (e != null) { |
| i++; |
| e = e.next; |
| } |
| return i; |
| } |
| |
| public int countPrefixPool() { |
| int i = 0; |
| PrefixEntry e = _prefixPool; |
| while (e != null) { |
| i++; |
| e = e.next; |
| } |
| return i; |
| } |
| |
| public final void clear() { |
| for (int i = _readOnlyArraySize; i < _size; i++) { |
| _array[i] = null; |
| } |
| _size = _readOnlyArraySize; |
| } |
| |
| public final void clearCompletely() { |
| _prefixPool = null; |
| _namespacePool = null; |
| |
| for (int i = 0; i < _size + 2; i++) { |
| _currentInScope[i] = 0; |
| _inScopeNamespaces[i] = null; |
| } |
| |
| for (int i = 0; i < _prefixMap.length; i++) { |
| _prefixMap[i] = null; |
| } |
| |
| increaseNamespacePool(_initialCapacity); |
| increasePrefixPool(_initialCapacity); |
| |
| initializeEntries(); |
| |
| _declarationId = 0; |
| |
| clear(); |
| } |
| |
| /** |
| * Returns cloned version of internal String[]. |
| * @return cloned version of internal String[]. |
| */ |
| public final String[] getArray() { |
| if (_array == null) return null; |
| |
| final String[] clonedArray = new String[_array.length]; |
| System.arraycopy(_array, 0, clonedArray, 0, _array.length); |
| return clonedArray; |
| } |
| |
| public final void setReadOnlyArray(ValueArray readOnlyArray, boolean clear) { |
| if (!(readOnlyArray instanceof PrefixArray)) { |
| throw new IllegalArgumentException(CommonResourceBundle.getInstance(). |
| getString("message.illegalClass", new Object[]{readOnlyArray})); |
| } |
| |
| setReadOnlyArray((PrefixArray)readOnlyArray, clear); |
| } |
| |
| public final void setReadOnlyArray(PrefixArray readOnlyArray, boolean clear) { |
| if (readOnlyArray != null) { |
| _readOnlyArray = readOnlyArray; |
| _readOnlyArraySize = readOnlyArray.getSize(); |
| |
| clearCompletely(); |
| |
| // Resize according to size of read only arrays |
| _inScopeNamespaces = new NamespaceEntry[_readOnlyArraySize + _inScopeNamespaces.length]; |
| _currentInScope = new int[_readOnlyArraySize + _currentInScope.length]; |
| // Intialize first two entries |
| initializeEntries(); |
| |
| if (clear) { |
| clear(); |
| } |
| |
| _array = getCompleteArray(); |
| _size = _readOnlyArraySize; |
| } |
| } |
| |
| public final String[] getCompleteArray() { |
| if (_readOnlyArray == null) { |
| // Return cloned version of internal _array |
| return getArray(); |
| // return _array; |
| } else { |
| final String[] ra = _readOnlyArray.getCompleteArray(); |
| final String[] a = new String[_readOnlyArraySize + _array.length]; |
| System.arraycopy(ra, 0, a, 0, _readOnlyArraySize); |
| return a; |
| } |
| } |
| |
| public final String get(int i) { |
| return _array[i]; |
| } |
| |
| public final int add(String s) { |
| if (_size == _array.length) { |
| resize(); |
| } |
| |
| _array[_size++] = s; |
| return _size; |
| } |
| |
| protected final void resize() { |
| if (_size == _maximumCapacity) { |
| throw new ValueArrayResourceException(CommonResourceBundle.getInstance().getString("message.arrayMaxCapacity")); |
| } |
| |
| int newSize = _size * 3 / 2 + 1; |
| if (newSize > _maximumCapacity) { |
| newSize = _maximumCapacity; |
| } |
| |
| final String[] newArray = new String[newSize]; |
| System.arraycopy(_array, 0, newArray, 0, _size); |
| _array = newArray; |
| |
| newSize += 2; |
| final NamespaceEntry[] newInScopeNamespaces = new NamespaceEntry[newSize]; |
| System.arraycopy(_inScopeNamespaces, 0, newInScopeNamespaces, 0, _inScopeNamespaces.length); |
| _inScopeNamespaces = newInScopeNamespaces; |
| |
| final int[] newCurrentInScope = new int[newSize]; |
| System.arraycopy(_currentInScope, 0, newCurrentInScope, 0, _currentInScope.length); |
| _currentInScope = newCurrentInScope; |
| } |
| |
| public final void clearDeclarationIds() { |
| for (int i = 0; i < _size; i++) { |
| final NamespaceEntry e = _inScopeNamespaces[i]; |
| if (e != null) { |
| e.declarationId = 0; |
| } |
| } |
| |
| _declarationId = 1; |
| } |
| |
| public final void pushScope(int prefixIndex, int namespaceIndex) throws FastInfosetException { |
| if (_namespacePool == null) { |
| increaseNamespacePool(16); |
| } |
| |
| final NamespaceEntry e = _namespacePool; |
| _namespacePool = e.next; |
| |
| final NamespaceEntry current = _inScopeNamespaces[++prefixIndex]; |
| if (current == null) { |
| e.declarationId = _declarationId; |
| e.namespaceIndex = _currentInScope[prefixIndex] = ++namespaceIndex; |
| e.next = null; |
| |
| _inScopeNamespaces[prefixIndex] = e; |
| } else if (current.declarationId < _declarationId) { |
| e.declarationId = _declarationId; |
| e.namespaceIndex = _currentInScope[prefixIndex] = ++namespaceIndex; |
| e.next = current; |
| |
| current.declarationId = 0; |
| _inScopeNamespaces[prefixIndex] = e; |
| } else { |
| throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.duplicateNamespaceAttribute")); |
| } |
| } |
| |
| public final void pushScopeWithPrefixEntry(String prefix, String namespaceName, |
| int prefixIndex, int namespaceIndex) throws FastInfosetException { |
| if (_namespacePool == null) { |
| increaseNamespacePool(16); |
| } |
| if (_prefixPool == null) { |
| increasePrefixPool(16); |
| } |
| |
| final NamespaceEntry e = _namespacePool; |
| _namespacePool = e.next; |
| |
| final NamespaceEntry current = _inScopeNamespaces[++prefixIndex]; |
| if (current == null) { |
| e.declarationId = _declarationId; |
| e.namespaceIndex = _currentInScope[prefixIndex] = ++namespaceIndex; |
| e.next = null; |
| |
| _inScopeNamespaces[prefixIndex] = e; |
| } else if (current.declarationId < _declarationId) { |
| e.declarationId = _declarationId; |
| e.namespaceIndex = _currentInScope[prefixIndex] = ++namespaceIndex; |
| e.next = current; |
| |
| current.declarationId = 0; |
| _inScopeNamespaces[prefixIndex] = e; |
| } else { |
| throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.duplicateNamespaceAttribute")); |
| } |
| |
| final PrefixEntry p = _prefixPool; |
| _prefixPool = _prefixPool.next; |
| p.prefixId = prefixIndex; |
| |
| e.prefix = prefix; |
| e.namespaceName = namespaceName; |
| e.prefixEntryIndex = KeyIntMap.indexFor(KeyIntMap.hashHash(prefix.hashCode()), _prefixMap.length); |
| |
| final PrefixEntry pCurrent = _prefixMap[e.prefixEntryIndex]; |
| p.next = pCurrent; |
| _prefixMap[e.prefixEntryIndex] = p; |
| } |
| |
| public final void popScope(int prefixIndex) { |
| final NamespaceEntry e = _inScopeNamespaces[++prefixIndex]; |
| _inScopeNamespaces[prefixIndex] = e.next; |
| _currentInScope[prefixIndex] = (e.next != null) ? e.next.namespaceIndex : 0; |
| |
| e.next = _namespacePool; |
| _namespacePool = e; |
| } |
| |
| public final void popScopeWithPrefixEntry(int prefixIndex) { |
| final NamespaceEntry e = _inScopeNamespaces[++prefixIndex]; |
| |
| _inScopeNamespaces[prefixIndex] = e.next; |
| _currentInScope[prefixIndex] = (e.next != null) ? e.next.namespaceIndex : 0; |
| |
| e.prefix = e.namespaceName = null; |
| e.next = _namespacePool; |
| _namespacePool = e; |
| |
| PrefixEntry current = _prefixMap[e.prefixEntryIndex]; |
| if (current.prefixId == prefixIndex) { |
| _prefixMap[e.prefixEntryIndex] = current.next; |
| current.next = _prefixPool; |
| _prefixPool = current; |
| } else { |
| PrefixEntry prev = current; |
| current = current.next; |
| while (current != null) { |
| if (current.prefixId == prefixIndex) { |
| prev.next = current.next; |
| current.next = _prefixPool; |
| _prefixPool = current; |
| break; |
| } |
| prev = current; |
| current = current.next; |
| } |
| } |
| } |
| |
| public final String getNamespaceFromPrefix(String prefix) { |
| final int index = KeyIntMap.indexFor(KeyIntMap.hashHash(prefix.hashCode()), _prefixMap.length); |
| PrefixEntry pe = _prefixMap[index]; |
| while (pe != null) { |
| final NamespaceEntry ne = _inScopeNamespaces[pe.prefixId]; |
| if (prefix == ne.prefix || prefix.equals(ne.prefix)) { |
| return ne.namespaceName; |
| } |
| pe = pe.next; |
| } |
| |
| return null; |
| } |
| |
| public final String getPrefixFromNamespace(String namespaceName) { |
| int position = 0; |
| while (++position < _size + 2) { |
| final NamespaceEntry ne = _inScopeNamespaces[position]; |
| if (ne != null && namespaceName.equals(ne.namespaceName)) { |
| return ne.prefix; |
| } |
| } |
| |
| return null; |
| } |
| |
| public final Iterator getPrefixes() { |
| return new Iterator() { |
| int _position = 1; |
| NamespaceEntry _ne = _inScopeNamespaces[_position]; |
| |
| public boolean hasNext() { |
| return _ne != null; |
| } |
| |
| public Object next() { |
| if (_position == _size + 2) { |
| throw new NoSuchElementException(); |
| } |
| |
| final String prefix = _ne.prefix; |
| moveToNext(); |
| return prefix; |
| } |
| |
| public void remove() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| private final void moveToNext() { |
| while (++_position < _size + 2) { |
| _ne = _inScopeNamespaces[_position]; |
| if (_ne != null) { |
| return; |
| } |
| } |
| _ne = null; |
| } |
| |
| }; |
| } |
| |
| public final Iterator getPrefixesFromNamespace(final String namespaceName) { |
| return new Iterator() { |
| String _namespaceName = namespaceName; |
| int _position = 0; |
| NamespaceEntry _ne; |
| |
| { |
| moveToNext(); |
| } |
| |
| public boolean hasNext() { |
| return _ne != null; |
| } |
| |
| public Object next() { |
| if (_position == _size + 2) { |
| throw new NoSuchElementException(); |
| } |
| |
| final String prefix = _ne.prefix; |
| moveToNext(); |
| return prefix; |
| } |
| |
| public void remove() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| private final void moveToNext() { |
| while (++_position < _size + 2) { |
| _ne = _inScopeNamespaces[_position]; |
| if (_ne != null && _namespaceName.equals(_ne.namespaceName)) { |
| return; |
| } |
| } |
| _ne = null; |
| } |
| }; |
| } |
| } |