Clone in a terminal:
XmlData.vala
/*
    Copyright (C) 2015 Johan Mattsson

    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 3 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.
*/

namespace B {

public class XmlData : XmlString {
	int* start_tags;
	int tags_capacity;
	int tags_size;
	
	internal bool error = false;
	
	public XmlData (char* data, int length) {
		base (data, length);

		start_tags = null;
		tags_capacity = 0;
		tags_size = 0;
		
		index_start_tags ();
	}
	
	~XmlData () {
		if (start_tags != null) {
			delete start_tags;
			start_tags =  null;
		}
	}
	
	public int get_index (XmlString start) {
		int offset = (int) ((size_t) start.data - (size_t) data);
		return offset;
	}
	
	public int find_next_tag_token (int index) {
		int new_index;
				
		if (index >= length) {
			return -1;
		}
		
		for (int i = 0; i < tags_size; i++) {
			new_index = start_tags[i];
			if (new_index >= index) {
				
				if (new_index == 0 && i > 0) { //FIXME:DELETE
					return -1;
				}
				
				return new_index;
			}
		}
		
		return -1;
	}

	void index_start_tags () {
		const char first_bit = 1 << 7;
		int i = 0;
		char* d = data;
 		
 		while (d[i] != '\0') {
			if ((int) (d[i] & first_bit) == 0) {
				if (d[i] == '<') {
					add_tag (i);
				}
			}
			i++;
		}
	}
	
	void add_tag (int index) {
		if (unlikely (tags_size == tags_capacity)) {
			if (!increase_capacity ()) {
				return;
			}
		}
		
		start_tags[tags_size] = index;
		tags_size++;
	}

	bool increase_capacity () {
		int* tags;
		
		tags_capacity += 512;
		tags = (int*) try_malloc (tags_capacity * sizeof (int));
		
		if (tags == null) {
			tags_capacity = 0;
			
			if (start_tags != null) {
				delete start_tags;
				start_tags = null;
				tags_size = 0;
				error = true;
			}
			
			warning ("Can not allocate xml data buffer.");
			return false;
		}
		
		if (tags_size > 0) {
			Posix.memcpy (tags, start_tags, tags_size * sizeof (int));
		}
		
		if (start_tags != null) {
			delete start_tags;
		}
		
		start_tags = tags;
		
		return true;
	}
	
	public void print_all () {
		XmlString s;
		int i = -1;
		string e;
		
		print("All tags:\n");
		
		for (int j = 0; j < tags_size; j++) {
			i = find_next_tag_token (i + 1);
			
			if (i > -1) {
				s = substring (i);
				s = s.substring (0, s.index_of (">"));
				s = s.substring (0, s.index_of (" "));
			} else {
				e = "error";
				s = new XmlString (e, e.length); 
			}
			
			int o = start_tags[j];
			print (s.to_string () + " : " + ((string) (data + o)).ndup (4) + @"  $o $j   i: $i\n");
		}
	}
}

}

Contact

Email: johan.mattsson.m@gmail.com
Mastodon: typo.social/@birdfont
GitHub: johanmattssonm
LinkedIn: johan-mattsson-2ab324112