001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.components.sax;
018:
019: import org.apache.avalon.excalibur.pool.Recyclable;
020: import org.apache.avalon.framework.CascadingRuntimeException;
021: import org.xml.sax.Attributes;
022: import org.xml.sax.Locator;
023: import org.xml.sax.SAXException;
024:
025: import java.util.HashMap;
026:
027: /**
028: * This a simple xml compiler which outputs a byte array.
029: *
030: * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
031: * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
032: * @author <a href="mailto:tcurdt@apache.org">Torsten Curdt</a>
033: * @version CVS $Id: XMLByteStreamCompiler.java 433543 2006-08-22 06:22:54Z crossley $
034: */
035:
036: public final class XMLByteStreamCompiler implements XMLSerializer,
037: Recyclable {
038:
039: private HashMap map;
040: private int mapCount;
041:
042: /** The buffer for the compile xml byte stream. */
043: private byte buf[];
044:
045: /** The number of valid bytes in the buffer. */
046: private int bufCount;
047:
048: private int bufCountAverage;
049:
050: public XMLByteStreamCompiler() {
051: this .map = new HashMap();
052: this .bufCountAverage = 2000;
053: this .initOutput();
054: }
055:
056: private void initOutput() {
057: this .mapCount = 0;
058: this .map.clear();
059: this .buf = new byte[bufCountAverage];
060: this .buf[0] = (byte) 'C';
061: this .buf[1] = (byte) 'X';
062: this .buf[2] = (byte) 'M';
063: this .buf[3] = (byte) 'L';
064: this .buf[4] = (byte) 1;
065: this .buf[5] = (byte) 0;
066: this .bufCount = 6;
067: }
068:
069: public void recycle() {
070: bufCountAverage = (bufCountAverage + bufCount) / 2;
071: this .initOutput();
072: }
073:
074: private static final int START_DOCUMENT = 0;
075: private static final int END_DOCUMENT = 1;
076: private static final int START_PREFIX_MAPPING = 2;
077: private static final int END_PREFIX_MAPPING = 3;
078: private static final int START_ELEMENT = 4;
079: private static final int END_ELEMENT = 5;
080: private static final int CHARACTERS = 6;
081: private static final int IGNORABLE_WHITESPACE = 7;
082: private static final int PROCESSING_INSTRUCTION = 8;
083: private static final int COMMENT = 9;
084: private static final int LOCATOR = 10;
085: private static final int START_DTD = 11;
086: private static final int END_DTD = 12;
087: private static final int START_CDATA = 13;
088: private static final int END_CDATA = 14;
089: private static final int SKIPPED_ENTITY = 15;
090: private static final int START_ENTITY = 16;
091: private static final int END_ENTITY = 17;
092:
093: public Object getSAXFragment() {
094: if (this .bufCount == 6) { // no event arrived yet
095: return null;
096: }
097: byte newbuf[] = new byte[this .bufCount];
098: System.arraycopy(this .buf, 0, newbuf, 0, this .bufCount);
099: return newbuf;
100: }
101:
102: public void startDocument() throws SAXException {
103: this .writeEvent(START_DOCUMENT);
104: }
105:
106: public void endDocument() throws SAXException {
107: this .writeEvent(END_DOCUMENT);
108: }
109:
110: public void startPrefixMapping(java.lang.String prefix,
111: java.lang.String uri) throws SAXException {
112: this .writeEvent(START_PREFIX_MAPPING);
113: this .writeString(prefix);
114: this .writeString(uri);
115: }
116:
117: public void endPrefixMapping(String prefix) throws SAXException {
118: this .writeEvent(END_PREFIX_MAPPING);
119: this .writeString(prefix);
120: }
121:
122: public void startElement(String namespaceURI, String localName,
123: String qName, Attributes atts) throws SAXException {
124: int length = atts.getLength();
125: this .writeEvent(START_ELEMENT);
126: this .writeAttributes(length);
127: for (int i = 0; i < length; i++) {
128: this .writeString(atts.getURI(i));
129: this .writeString(atts.getLocalName(i));
130: this .writeString(atts.getQName(i));
131: this .writeString(atts.getType(i));
132: this .writeString(atts.getValue(i));
133: }
134: this .writeString((namespaceURI == null ? "" : namespaceURI));
135: this .writeString(localName);
136: this .writeString(qName);
137: }
138:
139: public void endElement(String namespaceURI, String localName,
140: String qName) throws SAXException {
141: this .writeEvent(END_ELEMENT);
142: this .writeString((namespaceURI == null ? "" : namespaceURI));
143: this .writeString(localName);
144: this .writeString(qName);
145: }
146:
147: public void characters(char[] ch, int start, int length)
148: throws SAXException {
149: this .writeEvent(CHARACTERS);
150: this .writeChars(ch, start, length);
151: }
152:
153: public void ignorableWhitespace(char[] ch, int start, int length)
154: throws SAXException {
155: this .writeEvent(IGNORABLE_WHITESPACE);
156: this .writeChars(ch, start, length);
157: }
158:
159: public void processingInstruction(String target, String data)
160: throws SAXException {
161: this .writeEvent(PROCESSING_INSTRUCTION);
162: this .writeString(target);
163: this .writeString(data);
164: }
165:
166: public void setDocumentLocator(Locator locator) {
167: try {
168: this .writeEvent(LOCATOR);
169: String publicId = locator.getPublicId();
170: String systemId = locator.getSystemId();
171: this .writeString(publicId != null ? publicId : "");
172: this .writeString(systemId != null ? systemId : "");
173: this .write(locator.getLineNumber());
174: this .write(locator.getColumnNumber());
175: } catch (Exception e) {
176: throw new CascadingRuntimeException(
177: "Error while handling locator", e);
178: }
179: }
180:
181: public void skippedEntity(java.lang.String name)
182: throws SAXException {
183: this .writeEvent(SKIPPED_ENTITY);
184: this .writeString(name);
185: }
186:
187: /**
188: * SAX Event Handling: LexicalHandler
189: */
190: public void startDTD(String name, String publicId, String systemId)
191: throws SAXException {
192: this .writeEvent(START_DTD);
193: this .writeString(name);
194: this .writeString(publicId != null ? publicId : "");
195: this .writeString(systemId != null ? systemId : "");
196: }
197:
198: /**
199: * SAX Event Handling: LexicalHandler
200: */
201: public void endDTD() throws SAXException {
202: this .writeEvent(END_DTD);
203: }
204:
205: /**
206: * SAX Event Handling: LexicalHandler
207: */
208: public void startEntity(String name) throws SAXException {
209: this .writeEvent(START_ENTITY);
210: this .writeString(name);
211: }
212:
213: /**
214: * SAX Event Handling: LexicalHandler
215: */
216: public void endEntity(String name) throws SAXException {
217: this .writeEvent(END_ENTITY);
218: this .writeString(name);
219: }
220:
221: /**
222: * SAX Event Handling: LexicalHandler
223: */
224: public void startCDATA() throws SAXException {
225: this .writeEvent(START_CDATA);
226: }
227:
228: /**
229: * SAX Event Handling: LexicalHandler
230: */
231: public void endCDATA() throws SAXException {
232: this .writeEvent(END_CDATA);
233: }
234:
235: /**
236: * SAX Event Handling: LexicalHandler
237: */
238: public void comment(char ary[], int start, int length)
239: throws SAXException {
240: try {
241: this .writeEvent(COMMENT);
242: this .writeChars(ary, start, length);
243: } catch (Exception e) {
244: throw new SAXException(e);
245: }
246: }
247:
248: public final void writeEvent(final int event) {
249: this .write(event);
250: }
251:
252: public final void writeAttributes(final int attributes)
253: throws SAXException {
254: if (attributes > 0xFFFF)
255: throw new SAXException("Too many attributes");
256: this .write((attributes >>> 8) & 0xFF);
257: this .write((attributes >>> 0) & 0xFF);
258: }
259:
260: public final void writeString(final String str) throws SAXException {
261: Integer index = (Integer) map.get(str);
262: if (index == null) {
263: map.put(str, new Integer(mapCount++));
264: int length = str.length();
265: this .writeChars(str.toCharArray(), 0, length);
266: } else {
267: int i = index.intValue();
268:
269: if (i > 0xFFFF)
270: throw new SAXException("Index too large");
271:
272: this .write(((i >>> 8) & 0xFF) | 0x80);
273: this .write((i >>> 0) & 0xFF);
274: }
275: }
276:
277: public final void writeChars(final char[] ch, final int start,
278: final int length) {
279: int utflen = 0;
280: int c;
281:
282: for (int i = 0; i < length; i++) {
283: c = ch[i + start];
284: if ((c >= 0x0001) && (c <= 0x007F)) {
285: utflen++;
286: } else if (c > 0x07FF) {
287: utflen += 3;
288: } else {
289: utflen += 2;
290: }
291: }
292:
293: if (utflen >= 0x00007FFF) {
294: assure(bufCount + utflen + 6);
295:
296: buf[bufCount++] = (byte) 0x7F;
297: buf[bufCount++] = (byte) 0xFF;
298:
299: buf[bufCount++] = (byte) ((utflen >>> 24) & 0xFF);
300: buf[bufCount++] = (byte) ((utflen >>> 16) & 0xFF);
301: buf[bufCount++] = (byte) ((utflen >>> 8) & 0xFF);
302: buf[bufCount++] = (byte) ((utflen >>> 0) & 0xFF);
303: } else {
304: assure(bufCount + utflen + 2);
305:
306: buf[bufCount++] = (byte) ((utflen >>> 8) & 0xFF);
307: buf[bufCount++] = (byte) ((utflen >>> 0) & 0xFF);
308: }
309:
310: for (int i = 0; i < length; i++) {
311: c = ch[i + start];
312: if ((c >= 0x0001) && (c <= 0x007F)) {
313: buf[bufCount++] = (byte) c;
314: } else if (c > 0x07FF) {
315: buf[bufCount++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
316: buf[bufCount++] = (byte) (0x80 | ((c >> 6) & 0x3F));
317: buf[bufCount++] = (byte) (0x80 | ((c >> 0) & 0x3F));
318: } else {
319: buf[bufCount++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
320: buf[bufCount++] = (byte) (0x80 | ((c >> 0) & 0x3F));
321: }
322: }
323:
324: /*
325: if (length == 0) return;
326:
327: assure( (int) (buf.length + length * utfRatioAverage) );
328:
329: int utflentotal = 0;
330:
331: bufCount += 2;
332: int bufStart = bufCount;
333:
334: for (int i = 0; i < length; i++) {
335: int c = ch[i + start];
336: int l = bufCount-bufStart;
337:
338: if (l+3 >= 0x7FFF) {
339: buf[bufStart-2] = (byte) ((l >>> 8) & 0xFF);
340: buf[bufStart-1] = (byte) ((l >>> 0) & 0xFF);
341: utflentotal += l;
342: bufCount += 2;
343: bufStart = bufCount;
344: }
345:
346: if ((c >= 0x0001) && (c <= 0x007F)) {
347: assure(bufCount+1);
348: buf[bufCount++] = (byte)c;
349: }
350: else if (c > 0x07FF) {
351: assure(bufCount+3);
352: buf[bufCount++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
353: buf[bufCount++] = (byte) (0x80 | ((c >> 6) & 0x3F));
354: buf[bufCount++] = (byte) (0x80 | ((c >> 0) & 0x3F));
355: }
356: else {
357: assure(bufCount+2);
358: buf[bufCount++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
359: buf[bufCount++] = (byte) (0x80 | ((c >> 0) & 0x3F));
360: }
361: }
362:
363: int l = bufCount-bufStart;
364: buf[bufStart-2] = (byte) ((l >>> 8) & 0xFF);
365: buf[bufStart-1] = (byte) ((l >>> 0) & 0xFF);
366: utflentotal += l;
367:
368: utfRatioAverage = (utfRatioAverage + (utflentotal / length) / 2);
369: */
370: }
371:
372: /* JH (2003-11-20): seems to be never used
373:
374: private void write( final byte[] b ) {
375: int newcount = this.bufCount + b.length;
376: assure(newcount);
377: System.arraycopy(b, 0, this.buf, this.bufCount, b.length);
378: this.bufCount = newcount;
379: }
380: */
381:
382: private void write(final int b) {
383: int newcount = this .bufCount + 1;
384: assure(newcount);
385: this .buf[this .bufCount] = (byte) b;
386: this .bufCount = newcount;
387: }
388:
389: private void assure(final int size) {
390: if (size > this .buf.length) {
391: byte newbuf[] = new byte[Math.max(this .buf.length << 1,
392: size)];
393: System.arraycopy(this .buf, 0, newbuf, 0, this.bufCount);
394: this.buf = newbuf;
395: }
396: }
397: }
|