blob: 84ccd54233ea551439407b6bc54f854819913c0e [file] [log] [blame]
/*
* Copyright (c) 2004, 2011, 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;
}
};
}
}