blob: af90b743367b982d9d04a733629ae0f1f5863caa [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.html.core.internal.contentmodel.chtml;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import org.eclipse.wst.xml.core.internal.contentmodel.CMNamedNodeMap;
import org.eclipse.wst.xml.core.internal.contentmodel.CMNode;
/**
*/
abstract class DeclCollection implements CMNamedNodeMap {
protected class DualMap {
public DualMap() {
super();
}
public DualMap(Object[] objects) {
super();
initialize(objects);
}
public int size() {
return table.length;
}
public Object getValue(int key) {
if (!isValidIndex(key))
return null;
return table[key];
}
public int getKey(Object value) {
Integer keyObj = (Integer) map.get(value);
if (keyObj == null)
return ID_UNKNOWN;
return keyObj.intValue();
}
protected void initialize(Object[] objects) {
if (objects == null)
return;
table = objects;
map = new HashMap();
for (int key = 0; key < objects.length; key++) {
Object value = table[key];
map.put(value, new Integer(key));
}
}
private Object[] table = null;
private HashMap map = null;
private boolean isValidIndex(int index) {
return index >= 0 && index < table.length;
}
}
protected class TolerantStringDualMap extends DualMap {
public TolerantStringDualMap(String[] names) {
super();
Object[] objects = new Object[names.length];
for (int i = 0; i < names.length; i++) {
objects[i] = makeCanonicalForm(names[i]);
}
initialize(objects);
}
public int getKey(Object value) {
try {
String name = (String) value;
return super.getKey(makeCanonicalForm(name));
}
catch (ClassCastException e) {
return ID_UNKNOWN;
}
}
private String makeCanonicalForm(String raw) {
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=100152
// we are able to "cheat" here a little and use US Locale
// to get a good cononical form, since we are using this only
// for HTML and JSP standard tags.
// Long term, for similar needs with XML 1.1 (for example)
// we should use a class such as com.ibm.icu.text.Normalizer
return raw.toUpperCase(Locale.US);
}
}
private class DeclIterator implements Iterator {
public DeclIterator() {
maxid = fDecls.length - 1;
}
public boolean hasNext() {
return id < maxid;
}
public Object next() {
if (!hasNext())
return null;
return item(++id);
}
public void remove() { /* nothing should be done. */
}
private int id = -1;
private int maxid = -1;
}
CMNode[] fDecls = null;
protected final static boolean STRICT_CASE = false;
protected final static boolean TOLERANT_CASE = true;
protected final static int ID_UNKNOWN = -1;
private DualMap fMap = null;
/**
*/
public DeclCollection(String[] names, boolean tolerant) {
super();
fDecls = new CMNode[names.length];
if (tolerant) {
fMap = new TolerantStringDualMap(names);
}
else {
fMap = new DualMap(names);
}
}
/**
* @return org.eclipse.wst.xml.core.internal.contentmodel.CMNode
* @param id
* int
*/
protected abstract CMNode create(String name);
/**
*/
public CMNamedNodeMap getDeclarations(String[] names) {
CMNamedNodeMapImpl map = new CMNamedNodeMapImpl();
for (int i = 0; i < names.length; i++) {
String name = names[i];
CMNode node = getNamedItem(name);
if (node == null)
continue;
map.putNamedItem(name, node);
}
return map;
}
public void getDeclarations(CMGroupImpl group, Iterator names) {
while (names.hasNext()) {
String entityName = (String) names.next();
CMNode dec = getNamedItem(entityName);
if (dec != null)
group.appendChild(dec);
}
}
/**
* Map name to id.
*
* @return int
* @param name
* java.lang.String
*/
protected int getID(String name) {
return fMap.getKey(name);
}
/**
* getLength method
*
* @return int
*/
public int getLength() {
return fDecls.length;
}
/**
* @return java.lang.String
* @param id
* int
*/
protected String getName(int id) {
return (String) fMap.getValue(id);
}
/**
* getNamedItem method
*
* @return CMNode
* @param name
* java.lang.String
*/
public CMNode getNamedItem(String name) {
int id = getID(name);
if (!isValidID(id))
return null;
return item(id);
}
/**
* @return boolean
* @param id
* int
*/
private boolean isValidID(int id) {
return id >= 0 && id < fDecls.length;
}
/**
* item method
*
* @return CMNode
* @param index
* int
*/
public CMNode item(int index) {
if (!isValidID(index))
return null;
CMNode decl = fDecls[index];
if (decl != null)
return decl; // already exist.
decl = create(getName(index));
fDecls[index] = decl;
return decl;
}
/**
*/
public Iterator iterator() {
return new DeclIterator();
}
}