Package org.freeplane.n3.nanoxml

Source Code of org.freeplane.n3.nanoxml.StdXMLReader$StackedReader

/*
* 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)
*/
public class StdXMLReader implements IXMLReader {
  /**
   * A stacked reader.
   *
   * @author Marc De Scheemaecker
   * Modified by Dimitry Polivaev (2008)
   */
  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
   */
  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
   */
  public static IXMLReader stringReader(final String str) {
    return new StdXMLReader(new StringReader(str));
  }

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

  /**
   * Initializes the XML reader.
   *
   * @param stream
   *            the input for the XML data.
   * @throws java.io.IOException
   *             if an I/O error occurred
   */
  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<StackedReader>();
    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.
   */
  public StdXMLReader(final Reader reader) {
    currentReader = new StackedReader();
    readers = new Stack<StackedReader>();
    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
   */
  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<StackedReader>();
    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
   */
  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
   */
  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
  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.
   */
  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.
   */
  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.
   */
  public String getPublicID() {
    return currentReader.publicId;
  }

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

  /**
   * Returns the current system ID.
   */
  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
   */
  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
   */
  public char read() throws IOException {
    int ch = readImpl();
    while (ch < 0) {
      if (readers.empty()) {
        throw new IOException("Unexpected EOF at line " + getLineNr());
      }
      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
   */
  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
   */
  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
   */
  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
   */
  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
   */
  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
   */
  public void unread(final int ch) throws IOException {
    unread((char) ch);
  }
}
TOP

Related Classes of org.freeplane.n3.nanoxml.StdXMLReader$StackedReader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.