/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.cocoon.components.sax; import java.util.HashMap; import org.apache.cocoon.xml.XMLConsumer; import org.xml.sax.Attributes; import org.xml.sax.Locator; import org.xml.sax.SAXException; /** * This a simple xml compiler which outputs a byte array. * If you want to reuse this instance, make sure to call {@link #recycle()} * inbetween two compilation tasks. * * @version $Id: AbstractXMLByteStreamCompiler.java 587751 2007-10-24 02:41:36Z vgritsenko $ */ public abstract class AbstractXMLByteStreamCompiler implements XMLConsumer, XMLByteStreamConstants { private HashMap map; private int mapCount; private boolean hasProlog = false; protected AbstractXMLByteStreamCompiler() { this.map = new HashMap(); this.initOutput(); } private void initOutput() { this.mapCount = 0; this.map.clear(); this.hasProlog = false; } public void recycle() { this.initOutput(); } public void startDocument() throws SAXException { if(!hasProlog) writeProlog(); this.writeEvent(START_DOCUMENT); } public void endDocument() throws SAXException { this.writeEvent(END_DOCUMENT); } public void startPrefixMapping(java.lang.String prefix, java.lang.String uri) throws SAXException { if(!hasProlog) writeProlog(); this.writeEvent(START_PREFIX_MAPPING); this.writeString(prefix); this.writeString(uri); } public void endPrefixMapping(String prefix) throws SAXException { this.writeEvent(END_PREFIX_MAPPING); this.writeString(prefix); } public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { int length = atts.getLength(); this.writeEvent(START_ELEMENT); this.writeAttributes(length); for (int i = 0; i < length; i++) { this.writeString(atts.getURI(i)); this.writeString(atts.getLocalName(i)); this.writeString(atts.getQName(i)); this.writeString(atts.getType(i)); this.writeString(atts.getValue(i)); } this.writeString((namespaceURI == null ? "" : namespaceURI)); this.writeString(localName); this.writeString(qName); } public void endElement(String namespaceURI, String localName, String qName) throws SAXException { this.writeEvent(END_ELEMENT); this.writeString((namespaceURI == null ? "" : namespaceURI)); this.writeString(localName); this.writeString(qName); } public void characters(char[] ch, int start, int length) throws SAXException { this.writeEvent(CHARACTERS); this.writeChars(ch, start, length); } public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { if(!hasProlog) writeProlog(); this.writeEvent(IGNORABLE_WHITESPACE); this.writeChars(ch, start, length); } public void processingInstruction(String target, String data) throws SAXException { this.writeEvent(PROCESSING_INSTRUCTION); this.writeString(target); this.writeString(data); } public void setDocumentLocator(Locator locator) { try { if(!hasProlog) writeProlog(); this.writeEvent(LOCATOR); String publicId = locator.getPublicId(); String systemId = locator.getSystemId(); this.writeString(publicId!=null?publicId:""); this.writeString(systemId!=null?systemId:""); this.write(locator.getLineNumber()); this.write(locator.getColumnNumber()); } catch (Exception e) { throw new DocumentLocatorException("Error while handling locator", e); } } public void skippedEntity(java.lang.String name) throws SAXException { this.writeEvent(SKIPPED_ENTITY); this.writeString(name); } /** * SAX Event Handling: LexicalHandler */ public void startDTD(String name, String publicId, String systemId) throws SAXException { this.writeEvent(START_DTD); this.writeString(name); this.writeString(publicId!=null?publicId:""); this.writeString(systemId!=null?systemId:""); } /** * SAX Event Handling: LexicalHandler */ public void endDTD() throws SAXException { this.writeEvent(END_DTD); } /** * SAX Event Handling: LexicalHandler */ public void startEntity(String name) throws SAXException { this.writeEvent(START_ENTITY); this.writeString(name); } /** * SAX Event Handling: LexicalHandler */ public void endEntity(String name) throws SAXException { this.writeEvent(END_ENTITY); this.writeString(name); } /** * SAX Event Handling: LexicalHandler */ public void startCDATA() throws SAXException { this.writeEvent(START_CDATA); } /** * SAX Event Handling: LexicalHandler */ public void endCDATA() throws SAXException { this.writeEvent(END_CDATA); } /** * SAX Event Handling: LexicalHandler */ public void comment(char ary[], int start, int length) throws SAXException { try { this.writeEvent(COMMENT); this.writeChars(ary, start, length); } catch (Exception e) { throw new SAXException(e); } } public final void writeEvent( final int event) throws SAXException { this.write(event); } public final void writeAttributes( final int attributes) throws SAXException { if (attributes > 0xFFFF) throw new SAXException("Too many attributes"); this.write((attributes >>> 8) & 0xFF); this.write((attributes >>> 0) & 0xFF); } public final void writeString( final String str) throws SAXException { Integer index = (Integer) map.get(str); if (index == null) { map.put(str, new Integer(mapCount++)); int length = str.length(); this.writeChars(str.toCharArray(), 0, length); } else { int i = index.intValue(); if (i <= 0x7FFF) { // write index value in 16-bits this.write(((i >>> 8) & 0xFF) | 0x80); this.write((i >>> 0) & 0xFF); } else { // write escape code (Short.MAX_VALUE) to write a full 32-bit value write((byte)0x7F); write((byte)0xFF); // write index value in 32-bit write((byte) ((i >>> 24) & 0xFF) | 0x80); write((byte) ((i >>> 16) & 0xFF)); write((byte) ((i >>> 8) & 0xFF)); write((byte) ((i >>> 0) & 0xFF)); } } } public final void writeChars( final char[] ch, final int start, final int length) throws SAXException { int utflen = 0; int c; for (int i = 0; i < length; i++) { c = ch[i + start]; if ((c >= 0x0001) && (c <= 0x007F)) { utflen++; } else if (c > 0x07FF) { utflen += 3; } else { utflen += 2; } } if (utflen >= 0x00007FFF) { write((byte)0x7F); write((byte)0xFF); write((byte) ((utflen >>> 24) & 0xFF)); write((byte) ((utflen >>> 16) & 0xFF)); write((byte) ((utflen >>> 8) & 0xFF)); write((byte) ((utflen >>> 0) & 0xFF)); } else { write((byte) ((utflen >>> 8) & 0xFF)); write((byte) ((utflen >>> 0) & 0xFF)); } for (int i = 0; i < length; i++) { c = ch[i + start]; if ((c >= 0x0001) && (c <= 0x007F)) { write((byte) c); } else if (c > 0x07FF) { write((byte) (0xE0 | ((c >> 12) & 0x0F))); write((byte) (0x80 | ((c >> 6) & 0x3F))); write((byte) (0x80 | ((c >> 0) & 0x3F))); } else { write((byte) (0xC0 | ((c >> 6) & 0x1F))); write((byte) (0x80 | ((c >> 0) & 0x3F))); } } } abstract protected void write( final int b ) throws SAXException; private void writeProlog() throws SAXException { write((byte)'C'); write((byte)'X'); write((byte)'M'); write((byte)'L'); write((byte)1); write((byte)0); hasProlog = true; } }