Logo
Distributed Genetic Programming Framework
print print

File org.sfc.xml.sax.SAXWriter.java

Here you can find all the information about the file org.sfc.xml.sax.SAXWriter.java. You may explore it here or download it onto your local disk.
/*
 * Copyright (c) 2005 Thomas Weise
 *
 * E-Mail           : tweise@gmx.de
 * Creation Date    : 2005-08-12 11:43:04
 * Original Filename: org.sfc.xml.sax.SAXWriter.java
 * Version          : 3.0.0
 * Last modification: 2006-04-10
 *                by: Thomas Weise
 *
 * License          : GNU LESSER GENERAL PUBLIC LICENSE
 *                    Version 2.1, February 1999
 *                    You should have received a copy of this license along
 *                    with this library; if not, write to the Free Software
 *                    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *                    MA 02111-1307, USA or download the license under
 *                    http://www.gnu.org/copyleft/lesser.html.
 *
 * Warranty         : This software is provided "as is" without any
 *                    warranty; without even the implied warranty of
 *                    merchantability or fitness for a particular purpose.
 *                    See the Gnu Lesser General Public License for more
 *                    details.
 */


package org.sfc.xml.sax;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.util.Map;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;

import org.sfc.collections.Collections;
import org.sfc.io.IO;
import org.sfc.io.ReferenceCountedWriter;
import org.sfc.text.Text;
import org.sfc.xml.XML;

/**
 * The class <code>SAXWriter</code> allows you to serialize xml data in
 * a light-weight manner.
 * This version does not support dtd's or other exorbitant xml stuff, just
 * plain xml-documents with namespaces and such and such.
 * This simple architecture comes with increased speed and decreased memory
 * consumption compared to the dom-serialization-approach.
 * @author Thomas Weise
 */

public class SAXWriter extends    SAXImplementor
  {
/**
 * We've currently nothing to do.
 */

  private static final int  STATE_NOTHING       = 0;
/**
 * Currently we're prefix-mapping.
 */

  private static final int  STATE_MAPPING       = (STATE_NOTHING+1);
/**
 * Currently we're inside a fresh element.
 */

  private static final int  STATE_NEW_ELEMENT   = (STATE_MAPPING+1);
/**
 * Currently we're inside dtd.
 */

  private static final int  STATE_DTD           = (STATE_NEW_ELEMENT+1);
/**
 * Currently we're inside dtd.
 */

  private static final int  STATE_INTERNAL_DTD  = (STATE_DTD+1);
/**
 * Currently we're inside dtd.
 */

  private static final int  STATE_CDATA         = (STATE_INTERNAL_DTD+1);

/**
 * The data-output.
 */

  private   ReferenceCountedWriter    m_writer  ;

/**
 * The internal character buffer.
 */

  private   char[]                    m_buffer  ;
/**
 * The current buffer length.
 */

  private   int                       m_count   ;

/**
 * The element stack.
 */

  private   Element                   m_stack   ;

/**
 * The current state.
 */

            int                       m_state   ;
/**
 * The internal namespace-counter.
 */

            int                       m_nsct    ;
/**
 * The state stack.
 */

  private   int[]                     m_states  ;
/**
 * The state stack depth.
 */

  private   int                       m_state_cnt ;
/**
 * The encoding of the sax stream.
 */

  private final String                    m_endcoding ;
/**
 * special format if this value <= 0.
 */

  private       int                       m_format  ;

/**
 * Create a new sax writer.
 * @param p_dest  Any given source object that can be converted to a
 *                <code>Writer</code> by the <code>IO</code> class.
 * @throws SAXException  If the destination object cannot be open.
 */

  public  SAXWriter (final Object p_dest) throws SAXException
    {
    super();

    String  l_s;
    Charset l_cs;

//    if(p_dest instanceof IReferenceCounted)
//      {
//      ((IReferenceCounted)p_dest).add_ref();
//      }
    this.m_writer = IO.get_writer(p_dest, XML.PREFERED_ENCODING);
    if(this.m_writer == null)
      {
      throw new SAXException("Cannot open destination.");
      }

    this.m_buffer    = new char[256];
    this.m_state     = STATE_NOTHING;
    this.m_states    = new int[2];
    this.m_state_cnt = 0;

    l_s = this.m_writer.get_encoding();
    if(l_s != null)
      {
      try
        {
        l_cs = Charset.forName(l_s);
        }
      catch(UnsupportedCharsetException l_ucse)
        {
        l_cs = null;
        }

      this.m_endcoding = ((l_cs != null) ? l_cs.name() : l_s);
      }
    else  this.m_endcoding = null;
    }

/**
 * Push a state to the internal state stack.
 */

  private final void  push_state  ()
    {
    int   l_c;
    int[] l_s;

    l_s = this.m_states;
    l_c = this.m_count;

    if(l_c >= l_s.length)
      {
      l_s           = new int[l_c << 1];
      System.arraycopy(this.m_states, 0, l_s, 0, l_c);
      this.m_states = l_s;
      }

    l_s[l_c]          = this.m_state;
    this.m_state_cnt  = (l_c + 1);
    }

/**
 * Pop a state from the internal stack.
 * @throws  SAXException  If no state was yet pushed.
 */

  private final void  pop_state ()  throws SAXException
    {
    int l_c;

    l_c = this.m_state_cnt;
    if(l_c <= 0) throw new SAXException();

    this.m_state     = this.m_states[--l_c];
    this.m_state_cnt = l_c;
    }

/**
 * Write a portion of an array of characters to the internal buffer.
 *
 * @param  p_cbuf  Buffer of characters to be written
 * @param  p_off   Offset from which to start reading characters
 * @param  p_len   Number of characters to be written
 */

  final  void buffer(final char  p_cbuf[],
                     final int   p_off,
                     final int   p_len)
    {
    int     l_c, l_d;
    char[]  l_b;

    l_c = this.m_count;
    l_b = this.m_buffer;
    l_d = l_c + p_len;

    if(l_d >= l_b.length)
      {
      l_b = new char[l_d << 1];
      System.arraycopy(this.m_buffer, 0, l_b, 0, l_c);
      this.m_buffer = l_b;
      }

    System.arraycopy(p_cbuf, p_off, l_b, l_c, p_len);
    this.m_count = l_d;
    }

/**
 * Prepare some charater data to be written.
 * @param p_ch  The charater to be written.
 */

  final void  buffer  (final char p_ch)
    {
    int     l_c;
    char[]  l_b;

    l_c = this.m_count;
    l_b = this.m_buffer;

    if(l_c >= l_b.length)
      {
      l_b = new char[l_c << 1];
      System.arraycopy(this.m_buffer, 0, l_b, 0, l_c);
      this.m_buffer = l_b;
      }

    l_b[l_c] = p_ch;
    this.m_count = l_c+1;
    }



/**
 * Commit the storage buffer to the output device. This also ensures proper
 * xml linebreaking.
 * @throws  SAXException  When io fails.
 */

  final void  commit  ()  throws SAXException
    {
    int     l_c;
    char[]  l_b;

    l_c = this.m_count;
    if(l_c > 0)
      {

      l_b = this.m_buffer;
      if(this.m_format <= 0)
        {
        l_c = Text.xml_spaces(l_b, l_c);
        }

      this.m_count  = 0;
      try
        {
        this.m_writer.write(l_b, 0, l_c);
        }
      catch(IOException l_ioe)
        {
        throw new SAXException(l_ioe);
        }
      }
    }


/**
 * The internal method to preprocess the buffer.
 */

  private final void  unicode_escape  ()
    {
    char    l_n, l_o, l_ch;
    int     l_i, l_c, l_j, l_k;
    char[]  l_t;
    String  l_s;

    l_c = this.m_count;
    l_t = this.m_buffer;
    l_n = XML.LINE_BREAK;
    l_o = ((Text.LINE_BREAK_CHARS[0] == l_n) ? Text.LINE_BREAK_CHARS[1] :
                                               Text.LINE_BREAK_CHARS[0]);

    for(l_i = (l_c-1); l_i >= 0; l_i--)
      {
      l_ch = l_t[l_i];

      if(l_ch == l_o)
        {
        if((l_i <= 0) || (l_t[l_i-1] != l_n))
          {
          l_t[l_i] = l_n;
          }
        else
          {
          l_c--;
          System.arraycopy(l_t, l_i+1, l_t, l_i, l_c - l_i);
          }
        }
      else
        {
        if((l_ch != ' ') && (l_ch != '\t') && (l_ch != l_n))
          {
          if(l_ch < ' ')
            {
            l_c--;
            System.arraycopy(l_t, l_i+1, l_t, l_i, l_c - l_i);
            }
          else
            {
            if( (l_ch > 127) || (l_ch < 0) || (l_ch == '<') ||
                (l_ch == '>'/*|| (l_ch == '&') || (l_ch == '#')*/ ||
                (l_ch == '/') || (l_ch == '"') || (l_ch == '\''))
              {
              l_s = Integer.toString(l_ch);
              l_k = l_s.length();
              l_j = l_k + l_c + 2;

              if(l_j >= l_t.length)
                {
                l_t           = new char[l_j << 1];
                System.arraycopy(this.m_buffer, 0, l_t, 0, l_i);
                this.m_buffer = l_t;
                }
              System.arraycopy(l_t, l_i + 1, l_t, l_i + 3 + l_k,
                               l_c - l_i - 1);
              l_t[l_i]           = '&';
              l_t[l_i + 1]       = '#';
              l_s.getChars(0, l_k, l_t, l_i + 2);
              l_t[l_i + 2 + l_k] = ';';
              l_c = l_j;
              }
            }
          }
        }
      }

    this.m_count  = l_c;
    this.m_buffer = l_t;
    }

/**
 * Write a string to the internal buffer.
 *
 * @param  p_str  String to be written
 */

  final  void buffer(final  String  p_str)
    {
    int     l_c, l_d, l_l;
    char[]  l_b;

    l_c = this.m_count;
    l_b = this.m_buffer;
    l_l = p_str.length();
    l_d = l_c + l_l;

    if(l_d >= l_b.length)
      {
      l_b = new char[l_d << 1];
      System.arraycopy(this.m_buffer, 0, l_b, 0, l_c);
      this.m_buffer = l_b;
      }

    p_str.getChars(0, l_l, l_b, l_c);
    this.m_count = l_d;
    }

/**
 * Receive notification of the beginning of a document.
 *
 * <p>The SAX parser will invoke this method only once, before any
 * other event callbacks.</p>
 *
 * @throws org.xml.sax.SAXException any SAX exception, possibly
 *            wrapping another exception
 * @see #endDocument
 */

  @Override
  public void startDocument ()  throws SAXException
    {
    this.buffer("<?xml version=\"");
    this.buffer(this.getXMLVersion());

    if(this.m_endcoding != null)
      {
      this.buffer("\" encoding=\"");
      this.buffer(this.m_endcoding);
      }

    this.buffer("\"?>");
    this.commit();
    }

/**
 * Returns the version of XML used for the entity.  This will
 * normally be the identifier from the current entity's
 * <em>&lt;?xml&nbsp;version='...'&nbsp;...?&gt;</em> declaration,
 * or be defaulted by the parser.
 *
 * @return Identifier for the XML version being used to interpret
 * the entity's text, or null if that information is not yet
 * available in the current parsing state.
 */

  @Override
  public final  String getXMLVersion ()
    {
    return "1.0";
    }

/**
 * Returns the name of the character encoding for the entity.
 * If the encoding was declared externally (for example, in a MIME
 * Content-Type header), that will be the name returned.  Else if there
 * was an <em>&lt;?xml&nbsp;...encoding='...'?&gt;</em> declaration at
 * the start of the document, that encoding name will be returned.
 * Otherwise the encoding will been inferred (normally to be UTF-8, or
 * some UTF-16 variant), and that inferred name will be returned.
 *
 * @return Name of the character encoding being used to interpret
 * the entity's text, or null if this was not provided for a
 * character stream passed through an InputSource or is otherwise
 * not yet available in the current parsing state.
 */

  @Override
  public final  String getEncoding ()
    {
    return this.m_endcoding;
    }

/**
 * Receive notification of the end of a document.
 *
 * <p><strong>There is an apparent contradiction between the
 * documentation for this method and the documentation for {@link
 * org.xml.sax.ErrorHandler#fatalError}.  Until this ambiguity is
 * resolved in a future major release, clients should make no
 * assumptions about whether endDocument() will or will not be
 * invoked when the parser has reported a fatalError() or thrown
 * an exception.</strong></p>
 *
 * <p>The SAX parser will invoke this method only once, and it will
 * be the last method invoked during the parse.  The parser shall
 * not invoke this method until it has either abandoned parsing
 * (because of an unrecoverable error) or reached the end of
 * input.</p>
 *
 * @throws org.xml.sax.SAXException any SAX exception, possibly
 *            wrapping another exception
 * @see #startDocument
 */

  @Override
  public final  void endDocument() throws SAXException
    {

    while(this.m_state_cnt > 0)
      {
      pop_state();
      switch(this.m_state)
        {
        case  STATE_CDATA:
          {
          this.endCDATA();
          break;
          }

        case  STATE_INTERNAL_DTD:
        case  STATE_DTD:
          {
          this.endDTD();
          break;
          }
        }
      }

    while(this.m_stack != null) this.m_stack = this.m_stack.close();

    try
      {
      this.m_writer.close();
      }
    catch(Exception l_t)
      {
      throw new SAXException(l_t);
      }
    finally
      {
      this.m_writer = null;
      }
    }

///
/// LexicalHandler
///
/**
 * Report the start of DTD declarations, if any.
 *
 * <p>This method is intended to report the beginning of the
 * DOCTYPE declaration; if the document has no DOCTYPE declaration,
 * this method will not be invoked.</p>
 *
 *
 * <p>Note that the start/endDTD events will appear within
 * the start/endDocument events from ContentHandler and
 * before the first
 * {@link org.xml.sax.ContentHandler#startElement startElement}
 * event.</p>
 *
 * @param p_name The document type name.
 * @param p_public_id The declared public identifier for the
 *        external DTD subset, or null if none was declared.
 * @param p_system_id The declared system identifier for the
 *        external DTD subset, or null if none was declared.
 *        (Note that this is not resolved against the document
 *        base URI.)
 * @exception SAXException The application may raise an
 *            exception.
 * @see #endDTD
 */

  @Override
  public final  void startDTD (String    p_name,
                               String    p_public_id,
                               String    p_system_id)
        throws SAXException
    {
    boolean l_b;

    if(((p_name = Text.preprocess(p_name)) == null) ||
       (this.m_stack != null))
      {
      throw new SAXException();
      }

    switch(this.m_state)
      {
      case  STATE_NOTHING:
      case  STATE_MAPPING:
        {
        push_state();
        break;
        }

      default:  throw new SAXException();
      }

    this.m_state = STATE_DTD;

    this.buffer("<!DOCTYPE");
    if(p_name != null)
      {
      this.buffer(' ');
      this.buffer(p_name);
      }

    if((p_public_id = Text.preprocess(p_public_id)) != null)
      {
      this.buffer(" PUBLIC ");
      l_b = (p_public_id.charAt(0) != '"');
      if(l_b) this.buffer('"');
      this.buffer(p_public_id);
      if(l_b) this.buffer('"');
      }

    if((p_system_id = Text.preprocess(p_system_id)) != null)
      {
      if(p_public_id == null) this.buffer(" SYSTEM ");
      else                    this.buffer(' ');
      l_b = (p_system_id.charAt(0) != '"');
      if(l_b) this.buffer('"');
      this.buffer(p_system_id);
      if(l_b) this.buffer('"');
      }

    this.commit();
    }


/**
 * Report the end of DTD declarations.
 *
 * <p>This method is intended to report the end of the
 * DOCTYPE declaration; if the document has no DOCTYPE declaration,
 * this method will not be invoked.</p>
 *
 * @exception SAXException The application may raise an exception.
 * @see #startDTD
 */

  @Override
  public final  void endDTD () throws SAXException
    {
    if(this.m_state != STATE_DTD)
      {
      if(this.m_state == STATE_INTERNAL_DTD)
        {
        this.buffer(']');
        }
      else
        {
        throw new SAXException();
        }
      }
    this.pop_state();
    this.buffer('>');
    this.commit();
    }

/**
 * The begin of any dtd item.
 * @throws  SAXException  If we're not in an appropriate state.
 */

  private final void  dtd_item  ()  throws SAXException
    {
    if(this.m_state != STATE_INTERNAL_DTD)
      {
      if(this.m_state == STATE_DTD)
        {
        this.buffer(" [");
        this.m_state = STATE_INTERNAL_DTD;
        }
      else
        {
        throw new SAXException();
        }
      }
    }

/**
 * Report an element type declaration.
 *
 * <p>The content model will consist of the string "EMPTY", the
 * string "ANY", or a parenthesised group, optionally followed
 * by an occurrence indicator.  The model will be normalized so
 * that all parameter entities are fully resolved and all whitespace
 * is removed,and will include the enclosing parentheses.  Other
 * normalization (such as removing redundant parentheses or
 * simplifying occurrence indicators) is at the discretion of the
 * parser.</p>
 *
 * @param p_name The element type name.
 * @param p_model The content model as a normalized string.
 * @exception SAXException The application may raise an exception.
 */

  @Override
  public final  void elementDecl (String  p_name,
                                  String  p_model)
                                throws SAXException
    {
    if(((p_name  = Text.preprocess(p_name)) == null) ||
       ((p_model = Text.preprocess(p_model)) == null))
      {
      throw new SAXException();
      }

    this.dtd_item();

    this.buffer("<!ELEMENT ");

    this.buffer(p_name);
    this.buffer(' ');
    this.buffer(p_model.trim());

    this.buffer('>');
    this.commit();
    }


/**
 * Report an attribute type declaration.
 *
 * <p>Only the effective (first) declaration for an attribute will
 * be reported.  The type will be one of the strings "CDATA",
 * "ID", "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY",
 * "ENTITIES", a parenthesized token group with
 * the separator "|" and all whitespace removed, or the word
 * "NOTATION" followed by a space followed by a parenthesized
 * token group with all whitespace removed.</p>
 *
 * <p>The value will be the value as reported to applications,
 * appropriately normalized and with entity and character
 * references expanded.  </p>
 *
 * @param p_e_name The name of the associated element.
 * @param p_a_name The name of the attribute.
 * @param p_type A string representing the attribute type.
 * @param p_mode A string representing the attribute defaulting mode
 *        ("#IMPLIED", "#REQUIRED", or "#FIXED") or null if
 *        none of these applies.
 * @param p_value A string representing the attribute's default value,
 *        or null if there is none.
 * @exception SAXException The application may raise an exception.
 */

  @Override
  public final  void attributeDecl (String   p_e_name,
                                    String   p_a_name,
                                    String   p_type,
                                    String   p_mode,
                                    String   p_value)
                                                    throws SAXException
    {
    if(((p_e_name = Text.preprocess(p_e_name)) == null) ||
       ((p_a_name = Text.preprocess(p_a_name)) == null) ||
       ((p_type   = Text.preprocess(p_type))   == null) )
      {
      throw new SAXException();
      }

    this.dtd_item();

    this.buffer("<!ATTLIST ");
    this.buffer(p_e_name);
    this.buffer(' ');
    this.buffer(p_a_name);
    this.buffer(' ');
    this.buffer(p_type);

    if((p_mode = Text.preprocess(p_mode)) != null)
      {
      this.buffer(' ');
      this.buffer(p_mode);
      }

    if((p_value = Text.preprocess(p_value)) != null)
      {
      this.buffer(' ');
      this.buffer(p_value);
      }

    this.buffer('>');
    this.commit();
    }


/**
 * Report an internal entity declaration.
 *
 * <p>Only the effective (first) declaration for each entity
 * will be reported.  All parameter entities in the value
 * will be expanded, but general entities will not.</p>
 *
 * @param p_name The name of the entity.  If it is a parameter
 *        entity, the name will begin with '%'.
 * @param p_value The replacement text of the entity.
 * @exception SAXException The application may raise an exception.
 * @see #externalEntityDecl
 * @see org.xml.sax.DTDHandler#unparsedEntityDecl
 */

  @Override
  public  final  void internalEntityDecl (String  p_name,
                                          String  p_value)
                                                  throws SAXException
    {
    boolean l_b;

    if( ((p_name  = Text.preprocess(p_name))  == null) ||
        ((p_value = Text.preprocess(p_value)) == null) )
      {
      throw new SAXException();
      }

    this.dtd_item();

    this.buffer("<!ENTITY ");
    this.buffer(p_name);
    this.buffer(' ');
    l_b = (p_value.charAt(0) != '"');
    if(l_b) this.buffer('"');
    this.buffer(p_value);
    if(l_b) this.buffer('"');
    this.buffer('>');

    this.commit();
    }


/**
 * Report a parsed external entity declaration.
 *
 * <p>Only the effective (first) declaration for each entity
 * will be reported.</p>
 *
 * <p>If the system identifier is a URL, the parser must resolve it
 * fully before passing it to the application.</p>
 *
 * @param p_name The name of the entity.  If it is a parameter
 *        entity, the name will begin with '%'.
 * @param p_public_id The entity's public identifier, or null if none
 *        was given.
 * @param p_system_id The entity's system identifier.
 * @exception SAXException The application may raise an exception.
 * @see #internalEntityDecl
 * @see org.xml.sax.DTDHandler#unparsedEntityDecl
 */

  @Override
  public final  void externalEntityDecl (String    p_name,
                                         String    p_public_id,
                                         String    p_system_id)
                                              throws SAXException
    {
    boolean l_b;

    if( ((p_name       = Text.preprocess(p_name)) == null) ||
        (((p_public_id = Text.preprocess(p_public_id)) == null) &&
         ((p_system_id = Text.preprocess(p_system_id)) == null)) )
      {
      throw new SAXException();
      }

    this.dtd_item();

    this.buffer("<!ENTITY ");

    if(p_name != null)
      {
      this.buffer(' ');
      this.buffer(p_name);
      }

    if(p_public_id != null)
      {
      this.buffer(" PUBLIC ");
      l_b = (p_public_id.charAt(0) != '"');
      if(l_b) this.buffer('"');
      this.buffer(p_public_id);
      if(l_b) this.buffer('"');
      }

    if(p_system_id != null)
      {
      if(p_public_id == null) this.buffer(" SYSTEM ");
      else                    this.buffer(' ');
      l_b = (p_system_id.charAt(0) != '"');
      if(l_b) this.buffer('"');
      this.buffer(p_system_id);
      if(l_b) this.buffer('"');
      }

    this.commit();
    }

/**
 * Begin the scope of a prefix-URI Namespace mapping.
 *
 * <p>The information from this event is not necessary for
 * normal Namespace processing: the SAX XML reader will
 * automatically replace prefixes for element and attribute
 * names when the <code>http://xml.org/sax/features/namespaces</code>
 * feature is <var>true</var> (the default).</p>
 *
 * <p>There are cases, however, when applications need to
 * use prefixes in character data or in attribute values,
 * where they cannot safely be expanded automatically; the
 * start/endPrefixMapping event supplies the information
 * to the application to expand prefixes in those contexts
 * itself, if necessary.</p>
 *
 * <p>There should never be start/endPrefixMapping events for the
 * "xml" prefix, since it is predeclared and immutable.</p>
 *
 * @param p_prefix the Namespace prefix being declared.
 *  An empty string is used for the default element namespace,
 *  which has no prefix.
 * @param p_uri the Namespace URI the prefix is mapped to
 * @throws org.xml.sax.SAXException the client may throw
 *            an exception during processing
 * @see #startElement
 */

  @Override
  public final  void startPrefixMapping (final  String p_prefix,
                                         final  String p_uri)
                                throws SAXException
    {
    Element l_e;

    switch(this.m_state)
      {
      case  STATE_NOTHING:
        {
        this.m_stack = l_e = new Element(this.m_stack);
        this.m_state = STATE_MAPPING;
        break;
        }

      case  STATE_MAPPING:
      case  STATE_NEW_ELEMENT:
        {
        l_e = this.m_stack;
        break;
        }

      defaultthrow new SAXException();
      }

    l_e.map_prefix(p_prefix, p_uri);
    }


/**
 * The simple method to start a new element.
 * @param p_namespace_uri The namespace-uri of the element.
 *                        This might be <code>null</code>.
 * @param p_name          The (qualified or unqualified) name of the new
 *                        element.
 * @throws  SAXException  If something's gone wrong.
 * @see #startElement(String, String, String, Attributes)
 * @see #start_element(String)
 */

  public  final void  start_element (final String p_namespace_uri,
                               final String p_name)
                                          throws SAXException
    {
    this.startElement(p_namespace_uri, null, p_name, null);
    }

/**
 * The simple method to start a new element.
 * @param p_name          The (qualified or unqualified) name of the new
 *                        element.
 * @throws  SAXException  If something's gone wrong.
 * @see #startElement(String, String, String, Attributes)
 * @see #start_element(String, String)
 */

  public  final void  start_element (final String p_name)
                                          throws SAXException
    {
    this.startElement(null, null, p_name, null);
    }


/**
 * The simple method to put attributes.
 * @param p_name          The (qualified or unqualified) name of the new
 *                        element.
 * @param p_value         The value of the attribute.
 * @throws  SAXException  If something's gone wrong.
 * @see #startElement(String, String, String, Attributes)
 * @see #attribute(String, String, String)
 */

  public  final void  attribute (final String p_name,
                                 final String p_value)
                                          throws SAXException
    {
    this.attribute(null, p_name, p_value);
    }

/**
 * The simple method to put attributes.
 * @param p_namespace_uri The namespace-uri of the element.
 *                        This might be <code>null</code>.
 * @param p_name          The (qualified or unqualified) name of the new
 *                        element.
 * @param p_value         The value of the attribute.
 * @throws  SAXException  If something's gone wrong.
 * @see #startElement(String, String, String, Attributes)
 * @see #attribute(String, String)
 */

  public  final void  attribute (final String p_namespace_uri,
                                 final String p_name,
                                 final String p_value)
                                          throws SAXException
    {
    Element l_e;

    switch(this.m_state)
      {
      case  STATE_NOTHING:
        {
        this.m_stack = l_e = new Element(this.m_stack);
        this.m_state = STATE_MAPPING;
        break;
        }

      case  STATE_MAPPING:
      case  STATE_NEW_ELEMENT:
        {
        l_e = this.m_stack;
        break;
        }

      defaultthrow new SAXException();
      }

    l_e.attribute(p_namespace_uri, null, p_name, p_value);
    }

/**
 * Receive notification of the beginning of an element.
 *
 * <p>The Parser will invoke this method at the beginning of every
 * element in the XML document; there will be a corresponding
 * {@link #endElement endElement} event for every startElement event
 * (even when the element is empty). All of the element's content will be
 * reported, in order, before the corresponding endElement
 * event.</p>
 *
 * <p>This event allows up to three name components for each
 * element:</p>
 *
 * <ol>
 * <li>the Namespace URI;</li>
 * <li>the local name; and</li>
 * <li>the qualified (prefixed) name.</li>
 * </ol>
 *
 * <p>Any or all of these may be provided, depending on the
 * values of the <var>http://xml.org/sax/features/namespaces</var>
 * and the <var>http://xml.org/sax/features/namespace-prefixes</var>
 * properties:</p>
 *
 * <ul>
 * <li>the Namespace URI and local name are required when
 * the namespaces property is <var>true</var> (the default), and are
 * optional when the namespaces property is <var>false</var> (if one is
 * specified, both must be);</li>
 * <li>the qualified name is required when the namespace-prefixes property
 * is <var>true</var>, and is optional when the namespace-prefixes property
 * is <var>false</var> (the default).</li>
 * </ul>
 *
 * <p>Note that the attribute list provided will contain only
 * attributes with explicit values (specified or defaulted):
 * #IMPLIED attributes will be omitted.  The attribute list
 * will contain attributes used for Namespace declarations
 * (xmlns* attributes) only if the
 * <code>http://xml.org/sax/features/namespace-prefixes</code>
 * property is true (it is false by default, and support for a
 * true value is optional).</p>
 *
 * @param p_uri the Namespace URI, or the empty string if the
 *        element has no Namespace URI or if Namespace
 *        processing is not being performed
 * @param p_local_name the local name (without prefix), or the
 *        empty string if Namespace processing is not being
 *        performed
 * @param p_q_name the qualified name (with prefix), or the
 *        empty string if qualified names are not available
 * @param p_atts the attributes attached to the element.  If
 *        there are no attributes, it shall be an empty
 *        Attributes object.  The value of this object after
 *        startElement returns is undefined
 * @throws org.xml.sax.SAXException any SAX exception, possibly
 *            wrapping another exception
 * @see #endElement
 * @see org.xml.sax.Attributes
 * @see #start_element(String, String)
 * @see #start_element(String)
 */

  @Override
  public final  void startElement (final  String      p_uri,
                                   final  String      p_local_name,
                                   final  String      p_q_name,
                                   final  Attributes  p_atts)
                                throws SAXException
    {
    Element l_e;
    int     l_i;

    switch(this.m_state)
      {
      case  STATE_NEW_ELEMENT:
        {
        this.m_state = STATE_MAPPING;
        this.buffer('>');
        this.m_stack = l_e = new Element(this.m_stack);
        break;
        }

      case  STATE_NOTHING:
        {
        this.m_state = STATE_MAPPING;
        this.m_stack = l_e = new Element(this.m_stack);
        break;
        }

      case STATE_MAPPING:
        {
        l_e = this.m_stack;
        break;
        }

      defaultthrow new SAXException();
      }

    if((p_atts != null) && ((l_i = p_atts.getLength()) > 0))
      {
      this.m_state = STATE_MAPPING;

      for(--l_i; l_i >= 0; l_i--)
        {
        l_e.attribute(p_atts.getURI(l_i), p_atts.getLocalName(l_i),
                      p_atts.getQName(l_i), p_atts.getValue(l_i));
        }
      }

    l_e.start(p_uri, p_local_name, p_q_name);
    this.m_state = STATE_NEW_ELEMENT;
    }


/**
 * Receive notification of the end of an element.
 *
 * <p>The SAX parser will invoke this method at the end of every
 * element in the XML document; there will be a corresponding
 * {@link #startElement startElement} event for every endElement
 * event (even when the element is empty).</p>
 *
 * <p>For information on the names, see startElement.</p>
 *
 * @param p_uri the Namespace URI, or the empty string if the
 *        element has no Namespace URI or if Namespace
 *        processing is not being performed
 * @param p_local_name the local name (without prefix), or the
 *        empty string if Namespace processing is not being
 *        performed
 * @param p_q_name the qualified XML name (with prefix), or the
 *        empty string if qualified names are not available
 * @throws org.xml.sax.SAXException any SAX exception, possibly
 *            wrapping another exception
 * @see #end_element()
 */

  @Override
  public final  void endElement (final  String  p_uri,
                                 final  String  p_local_name,
                                 final  String  p_q_name)
                                throws SAXException
    {
    this.end_element();
    }

/**
 * The more convenient method to end an element.
 * @throws  SAXException  If something went wrong.
 * @see #endElement(String, String, String)
 */

  public  final void  end_element ()  throws SAXException
    {
    if(this.m_stack != null)  this.m_stack = this.m_stack.close();
    }

/**
 * Demark somthing that's inside an element.
 */

  private final void  element_item  ()
    {
    if(this.m_state == STATE_NEW_ELEMENT)
      {
      this.buffer('>');
      this.m_state = STATE_NOTHING;
      }
    }

/**
 * Receive notification of character data.
 *
 * <p>The Parser will call this method to report each chunk of
 * character data.  SAX parsers may return all contiguous character
 * data in a single chunk, or they may split it into several
 * chunks; however, all of the characters in any single event
 * must come from the same external entity so that the Locator
 * provides useful information.</p>
 *
 * <p>The application must not attempt to read from the array
 * outside of the specified range.</p>
 *
 * <p>Individual characters may consist of more than one Java
 * <code>char</code> value.  There are two important cases where this
 * happens, because characters can't be represented in just sixteen bits.
 * In one case, characters are represented in a <em>Surrogate Pair</em>,
 * using two special Unicode values. Such characters are in the so-called
 * "Astral Planes", with a code point above U+FFFF.  A second case involves
 * composite characters, such as a base character combining with one or
 * more accent characters. </p>
 *
 * <p> Your code should not assume that algorithms using
 * <code>char</code>-at-a-time idioms will be working in character
 * units; in some cases they will split characters.  This is relevant
 * wherever XML permits arbitrary characters, such as attribute values,
 * processing instruction data, and comments as well as in data reported
 * from this method.  It's also generally relevant whenever Java code
 * manipulates internationalized text; the issue isn't unique to XML.</p>
 *
 * @param p_ch the characters from the XML document
 * @param p_start the start position in the array
 * @param p_length the number of characters to read from the array
 * @throws org.xml.sax.SAXException any SAX exception, possibly
 *            wrapping another exception
 * @see org.xml.sax.Locator
 * @see #text(String)
 */

  @Override
  public final  void characters (final  char  p_ch[],
                                 final  int   p_start,
                                 final  int   p_length) throws SAXException
    {
    this.element_item();
    if(this.m_count > 0) this.commit();
    this.buffer(p_ch, p_start, p_length);
    this.m_format++;
    try
      {
      this.unicode_escape();
      this.commit();
      }
    finally
      {
      this.m_format--;
      }
    }

/**
 * The simple method to write a character to an xml-document.
 * @param p_char    The character to be written.
 * @throws SAXException any SAX exception, possibly
 *            wrapping another exception, probably io went wrong.
 * @see #characters(char[], int, int)
 */

  public  final void  text  (final char p_char) throws SAXException
    {
    this.element_item();
    if(this.m_count > 0) this.commit();
    this.buffer(p_char);
    this.m_format++;
    try
      {
      this.unicode_escape();
      this.commit();
      }
    finally
      {
      this.m_format--;
      }
    }

/**
 * The simple method to write some text to an xml-document.
 * @param p_string  The text to be written.
 * @throws SAXException any SAX exception, possibly
 *            wrapping another exception, probably io went wrong.
 * @see #characters(char[], int, int)
 */

  public  final void  text  (final String p_string) throws SAXException
    {
    this.element_item();
    if(this.m_count > 0) this.commit();
    this.buffer(p_string);
    this.m_format++;
    try
      {
      this.unicode_escape();
      this.commit();
      }
    finally
      {
      this.m_format--;
      }
    }


/**
 * Report an XML comment anywhere in the document.
 *
 * <p>This callback will be used for comments inside or outside the
 * document element, including comments in the external DTD
 * subset (if read).  Comments in the DTD must be properly
 * nested inside start/endDTD and start/endEntity events (if
 * used).</p>
 *
 * @param p_ch An array holding the characters in the comment.
 * @param p_start The starting position in the array.
 * @param p_length The number of characters to use from the array.
 * @exception SAXException The application may raise an exception.
 */

  @Override
  public final  void comment (final  char   p_ch[],
                              final  int    p_start,
                              final  int    p_length) throws SAXException
    {
    this.element_item();
    this.buffer("<!--");
    this.buffer(p_ch, p_start, p_length);
    this.buffer("-->");
    this.commit();
    }

/**
 * Receive notification of a processing instruction.
 *
 * <p>The Parser will invoke this method once for each processing
 * instruction found: note that processing instructions may occur
 * before or after the main document element.</p>
 *
 * <p>A SAX parser must never report an XML declaration (XML 1.0,
 * section 2.8) or a text declaration (XML 1.0, section 4.3.1)
 * using this method.</p>
 *
 * <p>Like {@link #characters characters()}, processing instruction
 * data may have characters that need more than one <code>char</code>
 * value. </p>
 *
 * @param p_target the processing instruction target
 * @param p_data the processing instruction data, or null if
 *        none was supplied.  The data does not include any
 *        whitespace separating it from the target
 * @throws org.xml.sax.SAXException any SAX exception, possibly
 *            wrapping another exception
 */

  @Override
  public final  void processingInstruction (String   p_target,
                                            String   p_data)
        throws SAXException
    {
    if((p_target = Text.preprocess(p_target)) == null)
      {
      throw new SAXException();
      }

    this.element_item();

    this.buffer("<?");
    this.buffer(p_target);
    if((p_data = Text.preprocess(p_data)) != null)
      {
      this.buffer(' ');
      this.buffer(p_data);
      }
    this.buffer("?>");
    this.commit();
    }

/**
 * Report the start of a CDATA section.
 *
 * <p>The contents of the CDATA section will be reported through
 * the regular {@link org.xml.sax.ContentHandler#characters
 * characters} event; this event is intended only to report
 * the boundary.</p>
 *
 * @exception SAXException The application may raise an exception.
 * @see #endCDATA
 */

  @Override
  public final  void startCDATA () throws SAXException
    {
    switch(this.m_state)
      {
      case  STATE_DTD:
      case  STATE_INTERNAL_DTD:
      case  STATE_MAPPING:
      case  STATE_NOTHING:
        {
        this.push_state();
        break;
        }
      case  STATE_NEW_ELEMENT:
        {
        this.element_item();
        this.push_state();
        break;
        }

      default:  throw new SAXException();
      }

    this.buffer("<![CDATA[<");
    this.commit();
    this.m_state = STATE_CDATA;
    this.m_format++;
    }


/**
 * Report the end of a CDATA section.
 *
 * @exception SAXException The application may raise an exception.
 * @see #startCDATA
 */

  @Override
  public final  void endCDATA () throws SAXException
    {
    if(this.m_state != STATE_CDATA) throw new SAXException();

    this.buffer("]]>");
    this.commit();
    this.m_format--;
    this.pop_state();
    }

/**
 * Finalize the sax-writer.
 * @throws  Throwable sometimes.
 */

  @Override
  protected void  finalize  ()  throws Throwable
    {
    try
      {
      if(this.m_writer != null)
        {
        endDocument();
        }
      }
    finally
      {
      super.finalize();
      }
    }

///**
// * Called when an element starts.
// * @param p_namespace_uri the Namespace URI, or the empty string if the
// *        element has no Namespace URI or if Namespace
// *        processing is not being performed
// * @param p_local_name the local name (without prefix), or the
// *        empty string if Namespace processing is not being
// *        performed
// * @throws SAXException When something goes wrong.
// */

//  protected void  on_start_element(final  String  p_namespace_uri,
//                                   final  String  p_local_name)
//                          throws SAXException
//    {
//    //
//    }
//
///**
// * Called when an element ends.
// * @param p_namespace_uri the Namespace URI, or the empty string if the
// *        element has no Namespace URI or if Namespace
// *        processing is not being performed
// * @param p_local_name the local name (without prefix), or the
// *        empty string if Namespace processing is not being
// *        performed
// * @throws SAXException When something goes wrong.
// */

//  protected void  on_end_element(final  String  p_namespace_uri,
//                                 final  String  p_local_name)
//      throws SAXException
//    {
//    //
//    }

/**
 * This class represents the internal element stack.
 *
 * @author Thomas Weise
 */

  private final class Element
    {
/**
 * The element that contains this one.
 */

    private final Element             m_owner       ;

/**
 * The namespaces managed by this element.
 */

    private       Map<String, String> m_namespaces  ;

/**
 * The string builder with initial attributes.
 */

    private       StringBuilder       m_attrs       ;

/**
 * The base-namespace.
 */

    private       String              m_base_namespace  ;
///**
// * The short name of the tag.
// */

//    private       String              m_local_name    ;
/**
 * The qualified name of the tag.
 */

    private       String              m_q_name    ;
///**
// * The namespace-uri of this element.
// */

//    private       String              m_namespace_uri ;

/**
 * Create a new element.
 * @param p_owner The element that owns this one.
 */

    Element (final Element p_owner)
      {
      super();
      this.m_owner = p_owner;
      }

/**
 * Begin a prefix-mapping.
 * @param p_prefix  The prefix.
 * @param p_uri     The uri to be mapped to it.
 * @throws  SAXException  If something went wrong.
 */

    final void  map_prefix  (String p_prefix,
                             String p_uri) throws SAXException
      {
      Map<String, String> l_m;
      StringBuilder       l_sb;
      Element             l_e;

      if((p_uri = Text.preprocess(p_uri)) == null) return ;

      if( (p_prefix = Text.preprocess(p_prefix)) == null )
        {
        for(l_e = this; l_e != null; l_e = l_e.m_owner)
          {
          if(l_e.m_base_namespace != null)
            {
            if(l_e.m_base_namespace.equals(p_uri))
              {
              this.m_base_namespace = p_uri;
              return ;
              }
            break;
            }
          }

        this.m_base_namespace = p_uri;
        }
      else
        {
        for(l_e = this; l_e != null; l_e = l_e.m_owner)
          {
          if((l_e.m_namespaces != null) &&
             (p_uri.equals(l_e.m_namespaces.get(p_prefix))))
            {
            return;
            }
          }

        l_m = this.m_namespaces;
        if(l_m == null)
          {
          this.m_namespaces = l_m = Collections.create_map(-1);
          }

        l_m.put(p_prefix, p_uri);
        l_m.put(p_uri, p_prefix);
        }

      switch(SAXWriter.this.m_state)
        {
        case STATE_MAPPING:
          {
          l_sb = this.m_attrs;
          if(l_sb == null)
            {
            this.m_attrs = l_sb = new StringBuilder();
            }

          l_sb.append(' ');

          if(p_prefix != null)
            {
            l_sb.append(XML.XMLNSQ);
            l_sb.append(p_prefix);
            }
          else l_sb.append(XML.XMLNS);

          l_sb.append("=\"");
          l_sb.append(p_uri);
          l_sb.append('"');
          break;
          }

        case  STATE_NEW_ELEMENT:
          {
          SAXWriter.this.buffer(' ');

          if(p_prefix != null)
            {
            SAXWriter.this.buffer(XML.XMLNSQ);
            SAXWriter.this.buffer(p_prefix);
            }
          else SAXWriter.this.buffer(XML.XMLNS);

          SAXWriter.this.buffer("=\"");
          SAXWriter.this.buffer(p_uri);
          SAXWriter.this.buffer('"');
          SAXWriter.this.commit();
          break;
          }

        defaultthrow new SAXException();
        }
      }

/**
 * Get the name of a new thing.
 * @param p_uri the Namespace URI, or the empty string if the
 *        element has no Namespace URI or if Namespace
 *        processing is not being performed
 * @param p_local_name the local name (without prefix), or the
 *        empty string if Namespace processing is not being
 *        performed
 * @param p_q_name the qualified name (with prefix), or the
 *        empty string if qualified names are not available
// * @param p_is_tag  If this is the tag name.
 * @return The name of a new thing.
 * @throws  SAXException  If something went wrong.
 */

    final  String name  (       String      p_uri,
                                String      p_local_name,
                                String      p_q_name/*,
                         final  boolean     p_is_tag*/
throws SAXException
      {
      Element l_e;
      String  l_pfx;
      int     l_i;
      boolean l_map;

      p_local_name = Text.preprocess(p_local_name);
      l_pfx        = null;

      if((p_q_name = Text.preprocess(p_q_name)) != null)
        {
        l_i = p_q_name.indexOf(XML.NAMESPACE_SEPARATOR);
        if(l_i > 0)
          {
          l_pfx    = p_q_name.substring(0, l_i);

          if(p_local_name == null)
            {
            p_local_name = p_q_name.substring(l_i+1);
            }
          }
        else
          {
          if(p_local_name == null)
            {
            p_local_name = p_q_name;
            }
          }
        }


      if( (p_uri = Text.preprocess(p_uri)) == null )
        {
//        if(p_is_tag)
//          {
//          for(l_e = this; l_e != null; l_e = l_e.m_owner)
//            {
//            if(l_e.m_base_namespace != null)
//              {
//              this.m_namespace_uri = l_e.m_base_namespace;
//              break;
//              }
//            }
//
//          this.m_local_name = p_local_name;
//          }
        return p_local_name;
        }

      for(l_e = this; l_e != null; l_e = l_e.m_owner)
        {
        p_q_name = l_e.m_base_namespace;
        if(p_q_name != null)
          {
          if(p_q_name.equals(p_uri))
            {
//            if(p_is_tag)
//              {
//              this.m_namespace_uri  = l_e.m_base_namespace;
//              this.m_local_name     = p_local_name;
//              }
            return p_local_name;
            }
          break;
          }
        }

      l_map = true;

      if((l_pfx == null) && (this.m_base_namespace != null))
        {
        for(l_e = this; l_e != null; l_e = l_e.m_owner)
          {
          if(l_e.m_namespaces != null)
            {
            l_pfx = l_e.m_namespaces.get(p_uri);
            if(l_pfx != null)
              {
              l_map = false;
              break;
              }
            }
          }

loopy:
        for(;;)
          {
          l_pfx = "ns" + (SAXWriter.this.m_nsct++);
          for(l_e = this; l_e != null; l_e = l_e.m_owner)
            {
            if(l_e.m_namespaces != null)
              {
              if(l_e.m_namespaces.get(l_pfx) != null)
                {
                continue loopy;
                }
              }
            }

          break;
          }
        }

      if(l_map) this.map_prefix(l_pfx, p_uri);


//      if(p_is_tag)
//        {
//        this.m_namespace_uri = p_uri;
//        this.m_local_name    = p_local_name;
//        }

      if(l_pfx != null)
        {
        return (l_pfx + XML.NAMESPACE_SEPARATOR + p_local_name);
        }

      return p_local_name;
      }

/**
 * Insert an attribute.
 * @param p_uri the Namespace URI, or the empty string if the
 *        element has no Namespace URI or if Namespace
 *        processing is not being performed
 * @param p_local_name the local name (without prefix), or the
 *        empty string if Namespace processing is not being
 *        performed
 * @param p_q_name the qualified name (with prefix), or the
 *        empty string if qualified names are not available
 * @param p_value The value of the attribute.
 * @throws  SAXException  The sax-exception is thrown when something goes
 *                        wrong.
 */

    final void  attribute (       String  p_uri,
                           final  String  p_local_name,
                           final  String  p_q_name,
                           final  String  p_value) throws SAXException
      {
      StringBuilder l_sb;

      p_uri = this.name(p_uri, p_local_name, p_q_name/*, false*/);

      switch(SAXWriter.this.m_state)
        {
        case STATE_MAPPING:
          {
          l_sb = this.m_attrs;
          if(l_sb == null)
            {
            this.m_attrs = l_sb = new StringBuilder();
            }

          l_sb.append(' ');
          l_sb.append(p_uri);
          if(p_value != null)
            {
            l_sb.append("=\"");
            l_sb.append(p_value);
            l_sb.append('"');
            }

          break;
          }

        case STATE_NEW_ELEMENT:
          {
          SAXWriter.this.buffer(' ');
          SAXWriter.this.buffer(p_uri);
          if(p_value != null)
            {
            SAXWriter.this.buffer("=\"");
            SAXWriter.this.buffer(p_value);
            SAXWriter.this.buffer('"');
            }

          SAXWriter.this.commit();
          break;
          }

        defaultthrow new SAXException();
        }
      }

/**
 * Start a new fucking element.
 * @param p_uri the Namespace URI, or the empty string if the
 *        element has no Namespace URI or if Namespace
 *        processing is not being performed
 * @param p_local_name the local name (without prefix), or the
 *        empty string if Namespace processing is not being
 *        performed
 * @param p_q_name the qualified name (with prefix), or the
 *        empty string if qualified names are not available
 * @throws SAXException any SAX exception, possibly
 *            wrapping another exception
 * @see org.xml.sax.Attributes
 */

    final  void start (final  String      p_uri,
                       final  String      p_local_name,
                       final  String      p_q_name)
            throws SAXException
      {
      StringBuilder l_sb;

      SAXWriter.this.buffer('<');
      SAXWriter.this.buffer(
          this.m_q_name = this.name(p_uri, p_local_name, p_q_name
                                      /*, true*/));

      l_sb = this.m_attrs;
      if(l_sb != null)
        {
        SAXWriter.this.buffer(l_sb.toString());
        this.m_attrs = null;
        }

      SAXWriter.this.commit();
//      SAXWriter.this.on_start_element(this.m_namespace_uri,
//                                      this.m_local_name);
      }

/**
 * Close this stack element.
 * @return  The owning stack element.
 * @throws  SAXException when io fails.
 */

    final Element close () throws SAXException
      {
      switch(SAXWriter.this.m_state)
        {
        case  STATE_NOTHING:
          {
          SAXWriter.this.buffer("</" + this.m_q_name + ">");
          break;
          }
        case  STATE_NEW_ELEMENT:
          {
          SAXWriter.this.buffer("/>");
          break;
          }

        defaultthrow new SAXException();
        }

      SAXWriter.this.commit();
      SAXWriter.this.m_state = STATE_NOTHING;

//      SAXWriter.this.on_end_element(this.m_namespace_uri,
//                                    this.m_local_name);

      return this.m_owner;
      }
    }
  }

File Information:

file name:SAXWriter.java
package:org.sfc.xml.sax
qualified name:org.sfc.xml.sax.SAXWriter.java
file type:Java Source File
download location:download http://dgpf.sourceforge.net/source/org/sfc/xml/sax/SAXWriter.java
size:53.244 KB (54522 B)
uploaded: 2018-01-07 12:03:36 GMT+0000
last update: 2006-04-10 10:13:08 GMT+0000
last access: 2018-04-27 02:42:49 GMT+0000

statistics online since 2006-01-02.   RSS Feed
Contact us by sending an email to tweise@gmx.de to receive further information, to report errors, or to join our project.
All content on this site (http://dgpf.sourceforge.net/) is LGPL-licensed.
http://dgpf.sourceforge.net/scripts/source/source.php last modified at 2018-01-07 12:03:34 GMT+0000 served at 2018-04-27 02:42:49 GMT+0000.
Valid CSS Valid XHTML 1.1
Valid RSS SourceForge.net Logo