001: /*
002: * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
003: * Copyright (C) 2006 - Javolution (http://javolution.org/)
004: * All rights reserved.
005: *
006: * Permission to use, copy, modify, and distribute this software is
007: * freely granted, provided that this notice is preserved.
008: */
009: package javolution.xml.stream;
010:
011: import j2mex.realtime.MemoryArea;
012: import javolution.lang.Reusable;
013: import javolution.text.CharArray;
014: import javolution.util.FastList;
015: import j2me.lang.CharSequence;
016: import j2me.util.Iterator;
017:
018: /**
019: * This class represents the namespaces stack while parsing.
020: *
021: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
022: * @version 3.2, April 2, 2005
023: */
024: final class NamespacesImpl implements Reusable, NamespaceContext {
025:
026: /**
027: * Holds the number of predefined namespaces.
028: */
029: static final int NBR_PREDEFINED_NAMESPACES = 3;
030:
031: /**
032: * Holds useful CharArray instances (non-static to avoid potential
033: * inter-thread corruption).
034: */
035: final CharArray _nullNsURI = new CharArray(""); // No namespace URI.
036:
037: final CharArray _defaultNsPrefix = new CharArray("");
038:
039: final CharArray _xml = new CharArray("xml");
040:
041: final CharArray _xmlURI = new CharArray(
042: "http://www.w3.org/XML/1998/namespace");
043:
044: final CharArray _xmlns = new CharArray("xmlns");
045:
046: final CharArray _xmlnsURI = new CharArray(
047: "http://www.w3.org/2000/xmlns/");
048:
049: /**
050: * Holds the current nesting level.
051: */
052: private int _nesting = 0;
053:
054: /**
055: * Holds the currently mapped prefixes.
056: */
057: CharArray[] _prefixes = new CharArray[16];
058:
059: /**
060: * Holds the currently mapped namespaces.
061: */
062: CharArray[] _namespaces = new CharArray[_prefixes.length];
063:
064: /**
065: * Indicates if the prefix has to been written (when writing).
066: */
067: boolean[] _prefixesWritten = new boolean[_prefixes.length];
068:
069: /**
070: * Holds the number of prefix/namespace association per nesting level.
071: */
072: int[] _namespacesCount = new int[16];
073:
074: /**
075: * Holds the default namespace.
076: */
077: CharArray _defaultNamespace = _nullNsURI;
078:
079: /**
080: * Holds the default namespace index.
081: */
082: int _defaultNamespaceIndex;
083:
084: /**
085: * Default constructor.
086: */
087: public NamespacesImpl() {
088: _prefixes[0] = _defaultNsPrefix;
089: _namespaces[0] = _nullNsURI;
090: _prefixes[1] = _xml;
091: _namespaces[1] = _xmlURI;
092: _prefixes[2] = _xmlns;
093: _namespaces[2] = _xmlnsURI;
094: _namespacesCount[0] = NBR_PREDEFINED_NAMESPACES;
095: }
096:
097: // Implements NamespaceContext
098: public CharArray getNamespaceURI(CharSequence prefix) {
099: if (prefix == null)
100: throw new IllegalArgumentException(
101: "null prefix not allowed");
102: return getNamespaceURINullAllowed(prefix);
103: }
104:
105: CharArray getNamespaceURINullAllowed(CharSequence prefix) {
106: if ((prefix == null) || (prefix.length() == 0))
107: return _defaultNamespace;
108: final int count = _namespacesCount[_nesting];
109: for (int i = count; --i >= 0;) {
110: if (_prefixes[i].equals(prefix))
111: return _namespaces[i];
112: }
113: return null; // Not bound.
114: }
115:
116: // Implements NamespaceContext
117: public CharArray getPrefix(CharSequence uri) {
118: if (uri == null)
119: throw new IllegalArgumentException(
120: "null namespace URI not allowed");
121: return _defaultNamespace.equals(uri) ? _defaultNsPrefix
122: : getPrefix(uri, _namespacesCount[_nesting]);
123: }
124:
125: CharArray getPrefix(CharSequence uri, int count) {
126: for (int i = count; --i >= 0;) {
127: CharArray prefix = _prefixes[i];
128: CharArray namespace = _namespaces[i];
129: if (namespace.equals(uri)) { // Find matching uri.
130: // Checks that the prefix has not been overwriten after being set.
131: boolean isPrefixOverwritten = false;
132: for (int j = i + 1; j < count; j++) {
133: if (prefix.equals(_prefixes[j])) {
134: isPrefixOverwritten = true;
135: break;
136: }
137: }
138: if (!isPrefixOverwritten)
139: return prefix;
140: }
141: }
142: return null; // Not bound.
143: }
144:
145: // Implements NamespaceContext
146: public Iterator getPrefixes(CharSequence namespaceURI) {
147: FastList prefixes = new FastList();
148: for (int i = _namespacesCount[_nesting]; --i >= 0;) {
149: if (_namespaces[i].equals(namespaceURI)) {
150: prefixes.add(_prefixes[i]);
151: }
152: }
153: return prefixes.iterator();
154: }
155:
156: // Null values are not allowed.
157: void setPrefix(CharArray prefix, CharArray uri) {
158: int index = _namespacesCount[_nesting];
159: _prefixes[index] = prefix;
160: _namespaces[index] = uri;
161: if (prefix.length() == 0) { // The default namespace is set.
162: _defaultNamespaceIndex = index;
163: _defaultNamespace = uri;
164: }
165: if (++_namespacesCount[_nesting] >= _prefixes.length)
166: resizePrefixStack();
167: }
168:
169: // Used only by XMLStreamWriter (converts CharSequence to CharArray).
170: // Null values are not allowed.
171: void setPrefix(final CharSequence prefix, CharSequence uri,
172: boolean isWritten) {
173: final int index = _namespacesCount[_nesting];
174: _prefixesWritten[index] = isWritten;
175: final int prefixLength = prefix.length();
176: CharArray prefixTmp = _prefixesTmp[index];
177: if ((prefixTmp == null)
178: || (prefixTmp.array().length < prefixLength)) {
179: MemoryArea.getMemoryArea(this ).executeInArea(
180: new Runnable() {
181: public void run() {
182: _prefixesTmp[index] = new CharArray()
183: .setArray(
184: new char[prefixLength + 32],
185: 0, 0);
186: }
187: });
188: prefixTmp = _prefixesTmp[index];
189: }
190: for (int i = 0; i < prefixLength; i++) {
191: prefixTmp.array()[i] = prefix.charAt(i);
192: }
193: prefixTmp.setArray(prefixTmp.array(), 0, prefixLength);
194:
195: final int uriLength = uri.length();
196: CharArray namespaceTmp = _namespacesTmp[index];
197: if ((namespaceTmp == null)
198: || (namespaceTmp.array().length < uriLength)) {
199: MemoryArea.getMemoryArea(this ).executeInArea(
200: new Runnable() {
201: public void run() {
202: _namespacesTmp[index] = new CharArray()
203: .setArray(new char[uriLength + 32],
204: 0, 0);
205: }
206: });
207: namespaceTmp = _namespacesTmp[index];
208: }
209: for (int i = 0; i < uriLength; i++) {
210: namespaceTmp.array()[i] = uri.charAt(i);
211: }
212: namespaceTmp.setArray(namespaceTmp.array(), 0, uriLength);
213:
214: // Sets the prefix using CharArray instances.
215: setPrefix(prefixTmp, namespaceTmp);
216: }
217:
218: private CharArray[] _prefixesTmp = new CharArray[_prefixes.length];
219:
220: private CharArray[] _namespacesTmp = new CharArray[_prefixes.length];
221:
222: void pop() {
223: if (_namespacesCount[--_nesting] <= _defaultNamespaceIndex) {
224: searchDefaultNamespace();
225: }
226: }
227:
228: private void searchDefaultNamespace() {
229: int count = _namespacesCount[_nesting];
230: for (int i = count; --i >= 0;) {
231: if (_prefixes[i].length() == 0) {
232: _defaultNamespaceIndex = i;
233: return;
234: }
235: }
236: throw new Error("Cannot find default namespace");
237: }
238:
239: void push() {
240: _nesting++;
241: if (_nesting >= _namespacesCount.length) {
242: resizeNamespacesCount();
243: }
244: _namespacesCount[_nesting] = _namespacesCount[_nesting - 1];
245: }
246:
247: public void reset() {
248: _defaultNamespace = _nullNsURI;
249: _defaultNamespaceIndex = 0;
250: _namespacesCount[0] = NBR_PREDEFINED_NAMESPACES;
251: _nesting = 0;
252: }
253:
254: private void resizeNamespacesCount() {
255: MemoryArea.getMemoryArea(this ).executeInArea(new Runnable() {
256: public void run() {
257: final int oldLength = _namespacesCount.length;
258: final int newLength = oldLength * 2;
259:
260: // Resizes namespaces counts.
261: int[] tmp = new int[newLength];
262: System
263: .arraycopy(_namespacesCount, 0, tmp, 0,
264: oldLength);
265: _namespacesCount = tmp;
266: }
267: });
268: }
269:
270: // Resizes prefix mapping stack.
271: private void resizePrefixStack() {
272: MemoryArea.getMemoryArea(this ).executeInArea(new Runnable() {
273: public void run() {
274: final int oldLength = _prefixes.length;
275: final int newLength = oldLength * 2;
276:
277: // Resizes prefixes.
278: CharArray[] tmp0 = new CharArray[newLength];
279: System.arraycopy(_prefixes, 0, tmp0, 0, oldLength);
280: _prefixes = tmp0;
281:
282: // Resizes namespaces uri.
283: CharArray[] tmp1 = new CharArray[newLength];
284: System.arraycopy(_namespaces, 0, tmp1, 0, oldLength);
285: _namespaces = tmp1;
286:
287: // Resizes prefix sets.
288: boolean[] tmp2 = new boolean[newLength];
289: System.arraycopy(_prefixesWritten, 0, tmp2, 0,
290: oldLength);
291: _prefixesWritten = tmp2;
292:
293: // Resizes temporary prefix (CharSequence to CharArray conversion).
294: CharArray[] tmp3 = new CharArray[newLength];
295: System.arraycopy(_prefixesTmp, 0, tmp3, 0, oldLength);
296: _prefixesTmp = tmp3;
297:
298: // Resizes temporary namespaces (CharSequence to CharArray conversion).
299: CharArray[] tmp4 = new CharArray[newLength];
300: System.arraycopy(_namespacesTmp, 0, tmp4, 0, oldLength);
301: _namespacesTmp = tmp4;
302:
303: }
304: });
305: }
306:
307: }
|