001: /*
002: * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
003: * Copyright (C) 2005 - 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 j2me.lang.CharSequence;
012: import j2me.util.Collection;
013: import j2me.util.Iterator;
014: import j2me.util.Map;
015: import javolution.lang.Reusable;
016: import javolution.text.CharArray;
017: import javolution.util.FastCollection;
018: import javolution.util.FastCollection.Record;
019:
020: /**
021: * This class holds defined entities while parsing.
022: *
023: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
024: * @version 4.0, June 16, 2006
025: */
026: final class EntitiesImpl implements Reusable {
027:
028: /**
029: * Holds maximum length.
030: */
031: private int _maxLength = 1;
032:
033: /**
034: * Holds the user defined entities mapping.
035: */
036: private Map _entitiesMapping;
037:
038: /**
039: * Default constructor.
040: */
041: EntitiesImpl() {
042: }
043:
044: /**
045: * Returns the length of the largest entity.
046: *
047: * @return the length largest entity.
048: */
049: public int getMaxLength() {
050: return _maxLength;
051: }
052:
053: /**
054: * Replaces the entity at the specified position.
055: * The five predefined XML entities "&lt;", "&gt;", "&apos;",
056: * "&quot;", "&amp;" as well as character refererences
057: * (decimal or hexadecimal) are always recognized.
058: *
059: * @param buffer the data buffer.
060: * @param start the index of entity first character (index of '&')
061: * @return the length of the replacement entity (including ';')
062: * @throws XMLStreamException if the entity is not recognized.
063: */
064: public int replaceEntity(char[] buffer, int start, int length)
065: throws XMLStreamException {
066:
067: // Checks for character references.
068: if (buffer[start + 1] == '#') {
069: char c = buffer[start + 2];
070: int base = (c == 'x') ? 16 : 10;
071: int i = (c == 'x') ? 3 : 2;
072: int charValue = 0;
073: for (; i < length - 1; i++) {
074: c = buffer[start + i];
075: charValue *= base;
076: charValue += (c <= '9') ? (c - '0')
077: : (c <= 'Z') ? c - 'A' : c - 'a';
078: }
079: buffer[start] = (char) charValue;
080: return 1;
081: }
082:
083: if ((buffer[start + 1] == 'l') && (buffer[start + 2] == 't')
084: && (buffer[start + 3] == ';')) {
085: buffer[start] = '<';
086: return 1;
087: }
088:
089: if ((buffer[start + 1] == 'g') && (buffer[start + 2] == 't')
090: && (buffer[start + 3] == ';')) {
091: buffer[start] = '>';
092: return 1;
093: }
094:
095: if ((buffer[start + 1] == 'a') && (buffer[start + 2] == 'p')
096: && (buffer[start + 3] == 'o')
097: && (buffer[start + 4] == 's')
098: && (buffer[start + 5] == ';')) {
099: buffer[start] = '\'';
100: return 1;
101: }
102:
103: if ((buffer[start + 1] == 'q') && (buffer[start + 2] == 'u')
104: && (buffer[start + 3] == 'o')
105: && (buffer[start + 4] == 't')
106: && (buffer[start + 5] == ';')) {
107: buffer[start] = '"';
108: return 1;
109: }
110:
111: if ((buffer[start + 1] == 'a') && (buffer[start + 2] == 'm')
112: && (buffer[start + 3] == 'p')
113: && (buffer[start + 4] == ';')) {
114: buffer[start] = '&';
115: return 1;
116: }
117:
118: // Searches user defined entities.
119: _tmp.setArray(buffer, start + 1, length - 2);
120: CharSequence replacementText = (_entitiesMapping != null) ? (CharSequence) _entitiesMapping
121: .get(_tmp)
122: : null;
123: if (replacementText == null)
124: throw new XMLStreamException("Entity " + _tmp
125: + " not recognized");
126: int replacementTextLength = replacementText.length();
127: for (int i = 0; i < replacementTextLength; i++) {
128: buffer[start + i] = replacementText.charAt(i);
129: }
130: return replacementTextLength;
131: }
132:
133: private CharArray _tmp = new CharArray();
134:
135: /**
136: * Defines a custom entity mapping.
137: *
138: * @param entityToReplacementText the entity (e.g. "copy") to replacement
139: * text (e.g. "©") mapping (both CharSequence).
140: */
141: public void setEntitiesMapping(Map entityToReplacementText) {
142: // Sets the maximum length for replacement text.
143: Collection values = entityToReplacementText.values();
144: if (values instanceof FastCollection) { // Avoids allocating iterators.
145: FastCollection fc = (FastCollection) values;
146: for (Record r = fc.head(), t = fc.tail(); (r = r.getNext()) != t;) {
147: CharSequence value = (CharSequence) fc.valueOf(r);
148: if (_maxLength < value.length()) {
149: _maxLength = value.length();
150: }
151: }
152: } else {
153: for (Iterator i = values.iterator(); i.hasNext();) {
154: CharSequence value = (CharSequence) i.next();
155: if (_maxLength < value.length()) {
156: _maxLength = value.length();
157: }
158: }
159: }
160: _entitiesMapping = entityToReplacementText;
161: }
162:
163: /**
164: * Returns the custom entity mapping.
165: *
166: * @return the entity (e.g. "copy") to replacement text (e.g. "©") mapping
167: * (both CharSequence).
168: */
169: public Map getEntitiesMapping() {
170: return _entitiesMapping;
171: }
172:
173: // Implements Reusable.
174: public void reset() {
175: _maxLength = 1;
176: _entitiesMapping = null;
177: }
178:
179: }
|