<commit_before>/* -*- Mode: vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/* ParserStream.vala
 *
 * Copyright (C) 2019  <NAME> <<EMAIL>>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but 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.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 *
 * Authors:
 *      <NAME> <<EMAIL>>
 */
using Gee;

public errordomain GXml.StreamReaderError {
  INVALID_DOCUMENT_ERROR
}

/**
 * Parser using a on the fly-post-parsing technique
 *
 * This parser takes or creates a {@link Document}, search
 * and adds the root XML element as a {@link Element};
 * then search and add all children {@link Element}.
 *
 * The root element is added without any attribute and
 * without any content or children; the same hapends with all
 * children.
 *
 * After call {@link read} or {@link read_document},
 * Root's and its children's content and its attributes
 * are stored as a string in a {@link GLib.MemoryOutputStream}
 * object at {@link GXml.Element.read_buffer}.
 *
 * If you want all attributes and children's children,
 * you should call {@link GXml.Element.parse_buffer},
 * which execute children's {@link GXml.Element.parse_buffer}
 * all asyncronically.
 */
public class GXml.StreamReader : GLib.Object {
  uint8[] buf = new uint8[2];
  Gee.HashMap<string,GXml.Collection> root_collections = new Gee.HashMap<string,GXml.Collection> ();
  DataInputStream _stream = null;
  DomDocument _document = null;
  /**
   * The stream where data is read from
   * to parse and fill {@link GXml.Element.read_buffer}
   */
  public DataInputStream stream { get { return _stream; } }
  /**
   * Use it to cancel the parse and fill process
   */
  public Cancellable? cancellable { get; set; }
  /**
   * Current {@link DomDocument} used to read to.
   */
  public DomDocument document { get { return _document; } }
  /**
   * Create a new {@link StreamReader} object.
   */
  public StreamReader (InputStream istream) {
    _stream = new DataInputStream (istream);
    buf[0] = '\0';
    buf[1] = '\0';
  }
  private inline uint8 read_byte () throws GLib.Error {
    buf[0] = stream.read_byte (cancellable);
    return buf[0];
  }
  private inline string read_upto (string str) throws GLib.Error {
    string bstr = stream.read_upto (str, -1, null, cancellable);
    return bstr;
  }
  private inline char cur_char () {
    return (char) buf[0];
  }
  private inline uint8 cur_byte () {
    return buf[0];
  }
  /**
   * Creates a new {@link DomDocument} and parse the stream to.
   */
  public DomDocument read () throws GLib.Error {
    _document = new Document ();
    internal_read ();
    return document;
  }
  /**
   * Use a {@link DomElement} to initialize {@link document}
   */
  public void read_document (DomDocument doc) throws GLib.Error {
    _document = doc;
    internal_read ();
  }
  private void internal_read () throws GLib.Error {
    read_byte ();
    if (cur_char () != '<') {
      throw new StreamReaderError.INVALID_DOCUMENT_ERROR (_("Invalid document: should start with '<'"));
    }
    read_byte ();
    if (is_space (cur_char ())) {
      throw new StreamReaderError.INVALID_DOCUMENT_ERROR (_("Invalid document: unexpected character before node's name"));
    }
    if (cur_char () == '?') {
      read_xml_dec ();
      if (cur_char () != '<') {
        throw new StreamReaderError.INVALID_DOCUMENT_ERROR (_("Invalid document: unexpected character '%c'"), cur_char ());
      }
      read_byte ();
      if (is_space (cur_char ())) {
        throw new StreamReaderError.INVALID_DOCUMENT_ERROR (_("Invalid document: unexpected character before node's name"));
      }
    }
    read_root_element ();
  }
  private GXml.Element read_root_element () throws GLib.Error {
    return read_element (true);
  }
  private GXml.Element read_element (bool children, GXml.Element? parent = null) throws GLib.Error {
    if (parent != null) {
      if (!(parent is GXml.Object)) {
        throw new DomError.INVALID_NODE_TYPE_ERROR
                      (_("Parent '%s' is not implemeting GXml.Object interface"), parent.get_type ().name ());
      }
    }
    GXml.Element e = null;
    var buf = new MemoryOutputStream.resizable ();
    var dbuf = new DataOutputStream (buf);
    var oname_buf = new MemoryOutputStream (new uint8[1024]);
    var name_buf = new DataOutputStream (oname_buf);

    dbuf.put_byte ('<');
    dbuf.put_byte (cur_byte ());

    name_buf.put_byte (cur_byte ());
    dbuf.put_byte (read_byte ());
    bool is_empty = false;
    while (cur_char () != '>') {
      if (is_space (cur_char ())) {
        break;
      }<commit_msg>Fix typo in StreamReader.vala, fixing https://gitlab.gnome.org/GNOME/gxml/issues/42<commit_after>/* -*- Mode: vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/* ParserStream.vala
 *
 * Copyright (C) 2019  <NAME> <<EMAIL>>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but 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.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 *
 * Authors:
 *      <NAME> <<EMAIL>>
 */
using Gee;

public errordomain GXml.StreamReaderError {
  INVALID_DOCUMENT_ERROR
}

/**
 * Parser using a on the fly-post-parsing technique
 *
 * This parser takes or creates a {@link Document}, search
 * and adds the root XML element as a {@link Element};
 * then search and add all children {@link Element}.
 *
 * The root element is added without any attribute and
 * without any content or children; the same hapends with all
 * children.
 *
 * After call {@link read} or {@link read_document},
 * Root's and its children's content and its attributes
 * are stored as a string in a {@link GLib.MemoryOutputStream}
 * object at {@link GXml.Element.read_buffer}.
 *
 * If you want all attributes and children's children,
 * you should call {@link GXml.Element.parse_buffer},
 * which execute children's {@link GXml.Element.parse_buffer}
 * all asyncronically.
 */
public class GXml.StreamReader : GLib.Object {
  uint8[] buf = new uint8[2];
  Gee.HashMap<string,GXml.Collection> root_collections = new Gee.HashMap<string,GXml.Collection> ();
  DataInputStream _stream = null;
  DomDocument _document = null;
  /**
   * The stream where data is read from
   * to parse and fill {@link GXml.Element.read_buffer}
   */
  public DataInputStream stream { get { return _stream; } }
  /**
   * Use it to cancel the parse and fill process
   */
  public Cancellable? cancellable { get; set; }
  /**
   * Current {@link DomDocument} used to read to.
   */
  public DomDocument document { get { return _document; } }
  /**
   * Create a new {@link StreamReader} object.
   */
  public StreamReader (InputStream istream) {
    _stream = new DataInputStream (istream);
    buf[0] = '\0';
    buf[1] = '\0';
  }
  private inline uint8 read_byte () throws GLib.Error {
    buf[0] = stream.read_byte (cancellable);
    return buf[0];
  }
  private inline string read_upto (string str) throws GLib.Error {
    string bstr = stream.read_upto (str, -1, null, cancellable);
    return bstr;
  }
  private inline char cur_char () {
    return (char) buf[0];
  }
  private inline uint8 cur_byte () {
    return buf[0];
  }
  /**
   * Creates a new {@link DomDocument} and parse the stream to.
   */
  public DomDocument read () throws GLib.Error {
    _document = new Document ();
    internal_read ();
    return document;
  }
  /**
   * Use a {@link DomElement} to initialize {@link document}
   */
  public void read_document (DomDocument doc) throws GLib.Error {
    _document = doc;
    internal_read ();
  }
  private void internal_read () throws GLib.Error {
    read_byte ();
    if (cur_char () != '<') {
      throw new StreamReaderError.INVALID_DOCUMENT_ERROR (_("Invalid document: should start with '<'"));
    }
    read_byte ();
    if (is_space (cur_char ())) {
      throw new StreamReaderError.INVALID_DOCUMENT_ERROR (_("Invalid document: unexpected character before node's name"));
    }
    if (cur_char () == '?') {
      read_xml_dec ();
      if (cur_char () != '<') {
        throw new StreamReaderError.INVALID_DOCUMENT_ERROR (_("Invalid document: unexpected character '%c'"), cur_char ());
      }
      read_byte ();
      if (is_space (cur_char ())) {
        throw new StreamReaderError.INVALID_DOCUMENT_ERROR (_("Invalid document: unexpected character before node's name"));
      }
    }
    read_root_element ();
  }
  private GXml.Element read_root_element () throws GLib.Error {
    return read_element (true);
  }
  private GXml.Element read_element (bool children, GXml.Element? parent = null) throws GLib.Error {
    if (parent != null) {
      if (!(parent is GXml.Object)) {
        throw new DomError.INVALID_NODE_TYPE_ERROR
                      (_("Parent '%s' is not implementing GXml.Object interface"), parent.get_type ().name ());
      }
    }
    GXml.Element e = null;
    var buf = new MemoryOutputStream.resizable ();
    var dbuf = new DataOutputStream (buf);
    var oname_buf = new MemoryOutputStream (new uint8[1024]);
    var name_buf = new DataOutputStream (oname_buf);

    dbuf.put_byte ('<');
    dbuf.put_byte (cur_byte ());

    name_buf.put_byte (cur_byte ());
    dbuf.put_byte (read_byte ());
    bool is_empty = false;
    while (cur_char () != '>') {
      if (is_space (cur_char ())) {
        break;
      }
{'fraction_non_alphanumeric': 0.11578947368421053, 'fraction_numerical': 0.005408015451472718, 'mean_word_length': 3.2252141982864138, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 23, 'https://': 1, 'lorem ipsum': 0, 'www.': 2, 'xml': 3}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5487020', 'n_tokens_mistral': 3119, 'n_tokens_neox': 3064, 'n_words': 1055}