Logo Search packages:      
Sourcecode: freeplane version File versions  Download package

StdXMLReader.java

/*
 * StdXMLReader.java NanoXML/Java $Revision: 1.4 $ $Date: 2002/01/04 21:03:28 $
 * $Name: RELEASE_2_2_1 $ This file is part of NanoXML 2 for Java. Copyright (C)
 * 2000-2002 Marc De Scheemaecker, All Rights Reserved. This software is
 * provided 'as-is', without any express or implied warranty. In no event will
 * the authors be held liable for any damages arising from the use of this
 * software. Permission is granted to anyone to use this software for any
 * purpose, including commercial applications, and to alter it and redistribute
 * it freely, subject to the following restrictions: 1. The origin of this
 * software must not be misrepresented; you must not claim that you wrote the
 * original software. If you use this software in a product, an acknowledgment
 * in the product documentation would be appreciated but is not required. 2.
 * Altered source versions must be plainly marked as such, and must not be
 * misrepresented as being the original software. 3. This notice may not be
 * removed or altered from any source distribution.
 */
package org.freeplane.n3.nanoxml;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.PushbackInputStream;
import java.io.PushbackReader;
import java.io.Reader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Stack;

/**
 * StdXMLReader reads the data to be parsed.
 * 
 * @author Marc De Scheemaecker
 * Modified by Dimitry Polivaev (2008)
 */
00040 public class StdXMLReader implements IXMLReader {
      /**
       * A stacked reader.
       * 
       * @author Marc De Scheemaecker
       * Modified by Dimitry Polivaev (2008)
       */
00047       private class StackedReader {
            LineNumberReader lineReader;
            Reader pbReader;
            String publicId;
            URL systemId;
      }

      /**
       * Creates a new reader using a file as input.
       * 
       * @param filename
       *            the name of the file containing the XML data
       * @throws java.io.FileNotFoundException
       *             if the file could not be found
       * @throws java.io.IOException
       *             if an I/O error occurred
       */
00064       public static IXMLReader fileReader(final String filename) throws FileNotFoundException, IOException {
            final StdXMLReader r = new StdXMLReader(new FileInputStream(filename));
            r.setSystemID(filename);
            for (int i = 0; i < r.readers.size(); i++) {
                  final StackedReader sr = (StackedReader) r.readers.elementAt(i);
                  sr.systemId = r.currentReader.systemId;
            }
            return r;
      }

      /**
       * Creates a new reader using a string as input.
       * 
       * @param str
       *            the string containing the XML data
       */
00080       public static IXMLReader stringReader(final String str) {
            return new StdXMLReader(new StringReader(str));
      }

      private char charReadTooMuch;
      /**
       * The current push-back reader.
       */
00088       private StackedReader currentReader;
      /**
       * The stack of readers.
       */
00092       final private Stack readers;

      /**
       * Initializes the XML reader.
       * 
       * @param stream
       *            the input for the XML data.
       * @throws java.io.IOException
       *             if an I/O error occurred
       */
00102       public StdXMLReader(final InputStream stream) throws IOException {
            new PushbackInputStream(stream);
            final StringBuilder charsRead = new StringBuilder();
            final Reader reader = this.stream2reader(stream, charsRead);
            currentReader = new StackedReader();
            readers = new Stack();
            currentReader.lineReader = new LineNumberReader(reader);
            currentReader.pbReader = currentReader.lineReader;
            currentReader.publicId = "";
            charReadTooMuch = '\0';
            try {
                  currentReader.systemId = new URL("file:.");
            }
            catch (final MalformedURLException e) {
            }
            this.startNewStream(new StringReader(charsRead.toString()));
      }

      /**
       * Initializes the XML reader.
       * 
       * @param reader
       *            the input for the XML data.
       */
00126       public StdXMLReader(final Reader reader) {
            currentReader = new StackedReader();
            readers = new Stack();
            currentReader.lineReader = new LineNumberReader(reader);
            currentReader.pbReader = currentReader.lineReader;
            currentReader.publicId = "";
            charReadTooMuch = '\0';
            try {
                  currentReader.systemId = new URL("file:.");
            }
            catch (final MalformedURLException e) {
            }
      }

      /**
       * Initializes the reader from a system and public ID.
       * 
       * @param publicID
       *            the public ID which may be null.
       * @param systemID
       *            the non-null system ID.
       * @throws MalformedURLException
       *             if the system ID does not contain a valid URL
       * @throws FileNotFoundException
       *             if the system ID refers to a local file which does not exist
       * @throws IOException
       *             if an error occurred opening the stream
       */
00154       public StdXMLReader(final String publicID, String systemID) throws MalformedURLException, FileNotFoundException,
              IOException {
            URL systemIDasURL = null;
            charReadTooMuch = '\0';
            try {
                  systemIDasURL = new URL(systemID);
            }
            catch (final MalformedURLException e) {
                  systemID = "file:" + systemID;
                  try {
                        systemIDasURL = new URL(systemID);
                  }
                  catch (final MalformedURLException e2) {
                        throw e;
                  }
            }
            currentReader = new StackedReader();
            readers = new Stack();
            final Reader reader = this.openStream(publicID, systemIDasURL.toString());
            currentReader.lineReader = new LineNumberReader(reader);
            currentReader.pbReader = currentReader.lineReader;
      }

      /**
       * Returns true if there are no more characters left to be read.
       * 
       * @throws java.io.IOException
       *             if an I/O error occurred
       */
00183       public boolean atEOF() throws IOException {
            int ch = readImpl();
            while (ch < 0) {
                  if (readers.empty()) {
                        return true;
                  }
                  currentReader.pbReader.close();
                  currentReader = (StackedReader) readers.pop();
                  ch = readImpl();
            }
            unread(ch);
            return false;
      }

      /**
       * Returns true if the current stream has no more characters left to be
       * read.
       * 
       * @throws java.io.IOException
       *             if an I/O error occurred
       */
00204       public boolean atEOFOfCurrentStream() throws IOException {
            final int ch = readImpl();
            if (ch < 0) {
                  return true;
            }
            else {
                  unread(ch);
                  return false;
            }
      }

      /**
       * Cleans up the object when it's destroyed.
       */
      @Override
00219       protected void finalize() throws Throwable {
            currentReader.lineReader = null;
            currentReader.pbReader = null;
            currentReader.systemId = null;
            currentReader.publicId = null;
            currentReader = null;
            readers.clear();
            super.finalize();
      }

      /**
       * Scans the encoding from an &lt;?xml...?&gt; tag.
       * 
       * @param str
       *            the first tag in the XML data.
       * @return the encoding, or null if no encoding has been specified.
       */
00236       protected String getEncoding(final String str) {
            if (!str.startsWith("<?xml")) {
                  return null;
            }
            int index = 5;
            while (index < str.length()) {
                  final StringBuilder key = new StringBuilder();
                  while ((index < str.length()) && (str.charAt(index) <= ' ')) {
                        index++;
                  }
                  while ((index < str.length()) && (str.charAt(index) >= 'a') && (str.charAt(index) <= 'z')) {
                        key.append(str.charAt(index));
                        index++;
                  }
                  while ((index < str.length()) && (str.charAt(index) <= ' ')) {
                        index++;
                  }
                  if ((index >= str.length()) || (str.charAt(index) != '=')) {
                        break;
                  }
                  while ((index < str.length()) && (str.charAt(index) != '\'') && (str.charAt(index) != '"')) {
                        index++;
                  }
                  if (index >= str.length()) {
                        break;
                  }
                  final char delimiter = str.charAt(index);
                  index++;
                  final int index2 = str.indexOf(delimiter, index);
                  if (index2 < 0) {
                        break;
                  }
                  if (key.toString().equals("encoding")) {
                        return str.substring(index, index2);
                  }
                  index = index2 + 1;
            }
            return null;
      }

      /**
       * Returns the line number of the data in the current stream.
       */
00279       public int getLineNr() {
            if (currentReader.lineReader == null) {
                  final StackedReader sr = (StackedReader) readers.peek();
                  if (sr.lineReader == null) {
                        return 0;
                  }
                  else {
                        return sr.lineReader.getLineNumber() + 1;
                  }
            }
            return currentReader.lineReader.getLineNumber() + 1;
      }

      /**
       * Returns the current public ID.
       */
00295       public String getPublicID() {
            return currentReader.publicId;
      }

      /**
       * Returns the current "level" of the stream on the stack of streams.
       */
00302       public int getStreamLevel() {
            return readers.size();
      }

      /**
       * Returns the current system ID.
       */
00309       public String getSystemID() {
            return currentReader.systemId.toString();
      }

      /**
       * Opens a stream from a public and system ID.
       * 
       * @param publicID
       *            the public ID, which may be null
       * @param systemID
       *            the system ID, which is never null
       * @throws java.net.MalformedURLException
       *             if the system ID does not contain a valid URL
       * @throws java.io.FileNotFoundException
       *             if the system ID refers to a local file which does not exist
       * @throws java.io.IOException
       *             if an error occurred opening the stream
       */
00327       public Reader openStream(final String publicID, final String systemID) throws MalformedURLException,
              FileNotFoundException, IOException {
            URL url = new URL(currentReader.systemId, systemID);
            if (url.getRef() != null) {
                  final String ref = url.getRef();
                  if (url.getFile().length() > 0) {
                        url = new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getFile());
                        url = new URL("jar:" + url + '!' + ref);
                  }
                  else {
                        url = StdXMLReader.class.getResource(ref);
                  }
            }
            currentReader.publicId = publicID;
            currentReader.systemId = url;
            final StringBuilder charsRead = new StringBuilder();
            final Reader reader = this.stream2reader(url.openStream(), charsRead);
            if (charsRead.length() == 0) {
                  return reader;
            }
            final String charsReadStr = charsRead.toString();
            final PushbackReader pbreader = new PushbackReader(reader, charsReadStr.length());
            for (int i = charsReadStr.length() - 1; i >= 0; i--) {
                  pbreader.unread(charsReadStr.charAt(i));
            }
            return pbreader;
      }

      /**
       * Reads a character.
       * 
       * @return the character
       * @throws java.io.IOException
       *             if no character could be read
       */
00362       public char read() throws IOException {
            int ch = readImpl();
            while (ch < 0) {
                  if (readers.empty()) {
                        throw new IOException("Unexpected EOF");
                  }
                  currentReader.pbReader.close();
                  currentReader = (StackedReader) readers.pop();
                  ch = readImpl();
            }
            return (char) ch;
      }

      private int readImpl() throws IOException {
            if (charReadTooMuch != '\0') {
                  final char ch = charReadTooMuch;
                  charReadTooMuch = '\0';
                  return ch;
            }
            final int ch = currentReader.pbReader.read();
            return ch;
      }

      /**
       * Sets the public ID of the current stream.
       * 
       * @param publicID
       *            the public ID
       */
00391       public void setPublicID(final String publicID) {
            currentReader.publicId = publicID;
      }

      /**
       * Sets the system ID of the current stream.
       * 
       * @param systemID
       *            the system ID
       * @throws java.net.MalformedURLException
       *             if the system ID does not contain a valid URL
       */
00403       public void setSystemID(final String systemID) throws MalformedURLException {
            currentReader.systemId = new URL(currentReader.systemId, systemID);
      }

      /**
       * Starts a new stream from a Java reader. The new stream is used temporary
       * to read data from. If that stream is exhausted, control returns to the
       * parent stream.
       * 
       * @param reader
       *            the non-null reader to read the new data from
       */
00415       public void startNewStream(final Reader reader) {
            this.startNewStream(reader, false);
      }

      /**
       * Starts a new stream from a Java reader. The new stream is used temporary
       * to read data from. If that stream is exhausted, control returns to the
       * parent stream.
       * 
       * @param reader
       *            the non-null reader to read the new data from
       * @param isInternalEntity
       *            true if the reader is produced by resolving an internal entity
       */
00429       public void startNewStream(final Reader reader, final boolean isInternalEntity) {
            final StackedReader oldReader = currentReader;
            readers.push(currentReader);
            currentReader = new StackedReader();
            if (isInternalEntity) {
                  currentReader.lineReader = null;
                  currentReader.pbReader = reader;
            }
            else {
                  currentReader.lineReader = new LineNumberReader(reader);
                  currentReader.pbReader = new PushbackReader(currentReader.lineReader, 2);
            }
            currentReader.systemId = oldReader.systemId;
            currentReader.publicId = oldReader.publicId;
      }

      /**
       * Converts a stream to a reader while detecting the encoding.
       * 
       * @param stream
       *            the input for the XML data.
       * @param charsRead
       *            buffer where to put characters that have been read
       * @throws java.io.IOException
       *             if an I/O error occurred
       */
00455       protected Reader stream2reader(final InputStream stream, final StringBuilder charsRead) throws IOException {
            final PushbackInputStream pbstream = new PushbackInputStream(stream);
            int b = pbstream.read();
            switch (b) {
                  case 0x00:
                  case 0xFE:
                  case 0xFF:
                        pbstream.unread(b);
                        return new InputStreamReader(pbstream, "UTF-16");
                  case 0xEF:
                        for (int i = 0; i < 2; i++) {
                              pbstream.read();
                        }
                        return new InputStreamReader(pbstream, "UTF-8");
                  case 0x3C:
                        b = pbstream.read();
                        charsRead.append('<');
                        while ((b > 0) && (b != 0x3E)) {
                              charsRead.append((char) b);
                              b = pbstream.read();
                        }
                        if (b > 0) {
                              charsRead.append((char) b);
                        }
                        final String encoding = this.getEncoding(charsRead.toString());
                        if (encoding == null) {
                              return new InputStreamReader(pbstream, "UTF-8");
                        }
                        charsRead.setLength(0);
                        try {
                              return new InputStreamReader(pbstream, encoding);
                        }
                        catch (final UnsupportedEncodingException e) {
                              return new InputStreamReader(pbstream, "UTF-8");
                        }
                  default:
                        charsRead.append((char) b);
                        return new InputStreamReader(pbstream, "UTF-8");
            }
      }

      public void unread(final char ch) throws IOException {
            charReadTooMuch = ch;
      }

      /**
       * Pushes the last character read back to the stream.
       * 
       * @param ch
       *            the character to push back.
       * @throws java.io.IOException
       *             if an I/O error occurred
       */
00508       public void unread(final int ch) throws IOException {
            unread((char) ch);
      }
}

Generated by  Doxygen 1.6.0   Back to index