image bugfixx - mir now depends on jai imagio
[mir.git] / source / mir / util / XMLReader.java
1 /*
2  * Copyright (C) 2001, 2002 The Mir-coders group
3  *
4  * This file is part of Mir.
5  *
6  * Mir is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Mir is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Mir; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * In addition, as a special exception, The Mir-coders gives permission to link
21  * the code of this program with  any library licensed under the Apache Software License,
22  * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23  * (or with modified versions of the above that use the same license as the above),
24  * and distribute linked combinations including the two.  You must obey the
25  * GNU General Public License in all respects for all of the code used other than
26  * the above mentioned libraries.  If you modify this file, you may extend this
27  * exception to your version of the file, but you are not obligated to do so.
28  * If you do not wish to do so, delete this exception statement from your version.
29  */
30 package mir.util;
31
32 import java.io.BufferedInputStream;
33 import java.io.FileInputStream;
34 import java.io.InputStream;
35 import java.io.StringReader;
36 import java.util.HashMap;
37 import java.util.Map;
38 import java.util.Stack;
39 import javax.xml.parsers.ParserConfigurationException;
40 import javax.xml.parsers.SAXParser;
41 import javax.xml.parsers.SAXParserFactory;
42
43 import org.ccil.cowan.tagsoup.Parser;
44 import org.xml.sax.Attributes;
45 import org.xml.sax.InputSource;
46 import org.xml.sax.Locator;
47 import org.xml.sax.SAXException;
48 import org.xml.sax.SAXParseException;
49 import org.xml.sax.helpers.DefaultHandler;
50 import multex.Exc;
51 import multex.Failure;
52
53 public class XMLReader {
54   private Locator locator;
55   private String filename;
56   private boolean namespaceAware;
57
58   public XMLReader() {
59     this(false);
60   }
61
62   public XMLReader(boolean aNameSpaceAware) {
63     namespaceAware = aNameSpaceAware;
64     filename="";
65   }
66
67   public void parseString(String aString, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
68     try {
69       parseInputSource(new InputSource(new StringReader(aString)), aRootHandler);
70     }
71     catch (Throwable t) {
72       throw new XMLReaderFailure(t);
73     }
74   }
75
76   public void parseString(boolean aTagSoup, String aString, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
77     try {
78       parseInputSource(aTagSoup, new InputSource(new StringReader(aString)), aRootHandler);
79     }
80     catch (Throwable t) {
81       throw new XMLReaderFailure(t);
82     }
83   }
84
85   public void parseFile(String aFileName, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
86     filename= aFileName;
87     try {
88       parseInputStream(new BufferedInputStream(new FileInputStream(aFileName),8192), aRootHandler);
89     }
90     catch (Throwable t) {
91       throw new XMLReaderFailure(t);
92     }
93   }
94
95   public void parseInputStream(InputStream anInputStream, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
96     parseInputSource(new InputSource(anInputStream), aRootHandler);
97   }
98
99   public void parseInputStream(boolean aTagSoup, InputStream anInputStream, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
100     parseInputSource(aTagSoup, new InputSource(anInputStream), aRootHandler);
101   }
102
103   public void parseInputSource(InputSource anInputSource, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
104     try {
105       parseInputSource(false, anInputSource, aRootHandler);
106     }
107     catch (Throwable e) {
108       Throwable t = ExceptionFunctions.traceCauseException(e);
109
110       if (t instanceof XMLReaderExc) {
111         throw (XMLReaderExc) t;
112       }
113
114       if (t instanceof XMLReaderFailure) {
115         throw (XMLReaderFailure) t;
116       }
117
118       throw new XMLReaderFailure(t);
119     }
120   }
121
122   public void parseInputSource(boolean aTagSoup, InputSource anInputSource, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
123     try {
124       XMLReaderHandler handler = new XMLReaderHandler(aRootHandler);
125
126       if (aTagSoup) {
127         org.ccil.cowan.tagsoup.Parser parser = new Parser();
128         parser.setContentHandler(handler);
129         parser.setDTDHandler(handler);
130         parser.parse(anInputSource);
131       }
132       else {
133         SAXParserFactory parserFactory = SAXParserFactory.newInstance();
134
135         parserFactory.setNamespaceAware(true);
136         parserFactory.setValidating(true);
137         SAXParser parser = parserFactory.newSAXParser();
138
139         parser.parse(anInputSource, handler);
140       }
141     }
142     catch (Throwable e) {
143       Throwable t = ExceptionFunctions.traceCauseException(e);
144
145       if (t instanceof XMLReaderExc) {
146         throw (XMLReaderExc) t;
147       }
148
149       if (t instanceof XMLReaderFailure) {
150         throw (XMLReaderFailure) t;
151       }
152
153       if (t instanceof XMLReaderExc) {
154         if (locator!=null && filename!=null)
155           ((XMLReaderExc) t).setLocation(filename, locator.getLineNumber(), locator.getColumnNumber());
156         throw (XMLReaderExc) t;
157       }
158
159       if (t instanceof SAXParseException) {
160         XMLReaderExc r = new XMLReaderExc(t.getMessage());
161
162         if (locator!=null && filename!=null)
163           r.setLocation(filename, locator.getLineNumber(), locator.getColumnNumber());
164
165         throw r;
166       }
167
168       if (t instanceof XMLReaderFailure) {
169         throw (XMLReaderFailure) t;
170       }
171
172       if (t instanceof ParserConfigurationException) {
173         throw new XMLReaderFailure("Internal exception: "+t.toString(), t);
174       }
175
176       throw new XMLReaderFailure(t);
177     }
178   }
179   private class XMLReaderHandler extends DefaultHandler {
180     private SectionsManager manager;
181
182     public XMLReaderHandler(SectionHandler aRootHandler) {
183       super();
184
185       manager = new SectionsManager();
186       manager.pushHandler(aRootHandler);
187    }
188
189     public void setDocumentLocator(Locator aLocator) {
190       locator=aLocator;
191     }
192
193     public void startElement(String aUri, String aLocalName, String aQualifiedName, Attributes anAttributes) throws SAXException {
194       Map attributesMap;
195       int i;
196
197       try {
198         attributesMap = new HashMap();
199
200         if (namespaceAware)
201           for (i=0; i<anAttributes.getLength(); i++)
202             attributesMap.put(new XMLName(anAttributes.getURI(i), XMLReaderTool.getNameSpaceFromQualifiedName(anAttributes.getQName(i)), anAttributes.getLocalName(i)), anAttributes.getValue(i));
203         else
204           for (i=0; i<anAttributes.getLength(); i++)
205             attributesMap.put(anAttributes.getLocalName(i), anAttributes.getValue(i));
206
207         SectionHandler handler = manager.currentHandler().startElement(new XMLName(aUri, XMLReaderTool.getNameSpaceFromQualifiedName(aQualifiedName), aLocalName), attributesMap);
208
209         manager.pushHandler( handler );
210       }
211       catch (XMLReaderExc e) {
212         throw new SAXParseException(e.getMessage(), null, e);
213       }
214       catch (Exception e) {
215         throw new SAXException(e);
216       }
217     }
218
219     public void endElement(String aUri, String aLocalName, String aQualifiedName) throws SAXException {
220       try
221       {
222         SectionHandler handler = manager.popHandler();
223
224         handler.finishSection();
225
226         if (!manager.isEmpty()) {
227           manager.currentHandler().endElement(handler);
228         }
229       }
230       catch (XMLReaderExc e) {
231         throw new SAXParseException(e.getMessage(), null, e);
232       }
233       catch (Exception e) {
234         throw new SAXException(e);
235       }
236     }
237
238     public void endDocument() throws SAXException {
239       try
240       {
241         SectionHandler handler = manager.popHandler();
242
243         handler.finishSection();
244       }
245       catch (XMLReaderExc e) {
246         throw new SAXParseException(e.getMessage(), null, e);
247       }
248       catch (Exception e) {
249         throw new SAXException(e);
250       }
251     }
252
253     public void characters(char[] aBuffer, int aStart, int anEnd) throws SAXException {
254       try {
255         String text = new String(aBuffer, aStart, anEnd);
256
257         manager.currentHandler().characters(text);
258       }
259       catch (XMLReaderExc e) {
260         throw new SAXParseException(e.getMessage(), null, e);
261       }
262       catch (Exception e) {
263         throw new SAXException(e);
264       }
265     }
266   }
267
268   private class SectionsManager {
269     Stack handlerStack;
270
271     public SectionsManager() {
272       handlerStack = new Stack();
273     }
274
275     public void pushHandler(SectionHandler aSectionHandler) {
276       handlerStack.push(aSectionHandler);
277     }
278
279     public SectionHandler popHandler() {
280       return (SectionHandler) handlerStack.pop();
281     }
282
283     public SectionHandler currentHandler() {
284       return (SectionHandler) handlerStack.peek();
285     }
286
287     public boolean isEmpty() {
288       return handlerStack.isEmpty();
289     }
290   }
291
292   public static interface SectionHandler {
293     public abstract SectionHandler startElement(XMLName aTag, Map anAttributes) throws XMLReaderExc;
294
295     public abstract void endElement(SectionHandler aHandler) throws XMLReaderExc;
296
297     public void characters(String aCharacters) throws XMLReaderExc;
298
299     public void finishSection() throws XMLReaderExc;
300   }
301
302   public static abstract class AbstractSectionHandler implements SectionHandler {
303     public SectionHandler startElement(XMLName aTag, Map anAttributes) throws XMLReaderExc {
304       return startElement(aTag.getLocalName(), anAttributes);
305     };
306
307     public SectionHandler startElement(String aLocalName, Map anAttributes) throws XMLReaderExc {
308       return null;
309     };
310
311     public void endElement(SectionHandler aHandler) throws XMLReaderExc {
312     };
313
314     public void finishSection() throws XMLReaderExc {
315     }
316
317     public void characters(String aCharacters) throws XMLReaderExc {
318       if ( aCharacters.trim().length() > 0) {
319         throw new XMLReaderExc("Text not allowed");
320       }
321     }
322   }
323
324   public static class XMLReaderExc extends Exc {
325     private boolean hasLocation;
326     private String filename;
327     private int lineNr;
328     private int columnNr;
329
330     public XMLReaderExc(String aMessage) {
331       super(aMessage);
332       hasLocation = false;
333     }
334
335     protected void setLocation(String aFilename, int aLineNr, int aColumnNr) {
336       filename = aFilename;
337       lineNr = aLineNr;
338       columnNr = aColumnNr;
339       hasLocation = true;
340     }
341
342     public boolean getHasLocation() {
343       return hasLocation;
344     }
345
346     public int getLineNr() {
347       return lineNr;
348     }
349
350     public int getColumnNr() {
351       return columnNr;
352     }
353
354     public String getFilename() {
355       return filename;
356     }
357   }
358
359   public static class XMLReaderFailure extends Failure {
360     public XMLReaderFailure(String aMessage, Throwable aCause) {
361       super(aMessage, aCause);
362     }
363
364     public XMLReaderFailure(Throwable aCause) {
365       super(aCause.getMessage(), aCause);
366     }
367   }
368
369   public static class XMLName {
370     private String namespaceURI;
371     private String localName;
372     private String prefix;
373
374     public XMLName(String aLocalName) {
375       this(null, null, aLocalName);
376     }
377
378     public XMLName(String aNamespaceURI, String aPrefix, String aLocalName) {
379       localName="";
380       prefix="";
381       namespaceURI="";
382
383       if (aLocalName!=null)
384         localName = aLocalName;
385       if (aPrefix!=null)
386         prefix = aPrefix;
387       if (aNamespaceURI!=null)
388         namespaceURI = aNamespaceURI;
389     }
390
391     public XMLName(String aNamespaceURI, String aLocalName) {
392       this (aNamespaceURI, null, aLocalName);
393     }
394
395     public String getNamespaceURI() {
396       return namespaceURI;
397     }
398
399     public String getLocalName() {
400       return localName;
401     }
402
403     public String getPrefix() {
404       return prefix;
405     }
406
407     public int hashCode() {
408       if (namespaceURI == null)
409         return localName.hashCode() + 3*prefix.hashCode();
410       else
411         return localName.hashCode() + 3*namespaceURI.hashCode();
412     }
413
414     public String toString() {
415       return ((namespaceURI.length()>0)? "["+namespaceURI+"]":"")+((prefix.length()>0)?prefix+":":"")+localName;
416     }
417
418     public boolean equals(Object anObject) {
419       if (anObject instanceof XMLName) {
420         if (namespaceURI==null)
421           return (((XMLName) anObject).namespaceURI == null) &&
422                  prefix.equals(((XMLName) anObject).prefix) &&
423                  localName.equals(((XMLName) anObject).localName);
424         else
425           return namespaceURI.equals(((XMLName) anObject).namespaceURI) &&
426                  localName.equals(((XMLName) anObject).localName);
427       }
428       else
429         return false;
430     }
431   }
432
433 }