From 47758d16ff0acd9edbd8ff6eb3922e59fb14f8bb Mon Sep 17 00:00:00 2001
From: Federico Mena Quintero <federico@gnome.org>
Date: Thu, 21 Nov 2019 14:24:02 -0600
Subject: [PATCH] Include the libcroco sources directly under src/st/croco

This is all of the original libcroco, minus these two which we don't use:

  - cr-sel-eng - the CSS selection engine for xmlNode.
  - cr-style.

Part of https://gitlab.gnome.org/GNOME/gnome-shell/issues/1934
---
 meson.build                        |    2 -
 src/st/croco/cr-additional-sel.c   |  500 +++
 src/st/croco/cr-additional-sel.h   |   98 +
 src/st/croco/cr-attr-sel.c         |  235 ++
 src/st/croco/cr-attr-sel.h         |   74 +
 src/st/croco/cr-cascade.c          |  215 ++
 src/st/croco/cr-cascade.h          |   74 +
 src/st/croco/cr-declaration.c      |  801 +++++
 src/st/croco/cr-declaration.h      |  136 +
 src/st/croco/cr-doc-handler.c      |  276 ++
 src/st/croco/cr-doc-handler.h      |  298 ++
 src/st/croco/cr-enc-handler.c      |  184 ++
 src/st/croco/cr-enc-handler.h      |   94 +
 src/st/croco/cr-fonts.c            |  949 ++++++
 src/st/croco/cr-fonts.h            |  315 ++
 src/st/croco/cr-input.c            | 1191 ++++++++
 src/st/croco/cr-input.h            |  174 ++
 src/st/croco/cr-num.c              |  313 ++
 src/st/croco/cr-num.h              |  127 +
 src/st/croco/cr-om-parser.c        | 1142 +++++++
 src/st/croco/cr-om-parser.h        |   98 +
 src/st/croco/cr-parser.c           | 4525 ++++++++++++++++++++++++++++
 src/st/croco/cr-parser.h           |  128 +
 src/st/croco/cr-parsing-location.c |  172 ++
 src/st/croco/cr-parsing-location.h |   70 +
 src/st/croco/cr-prop-list.c        |  404 +++
 src/st/croco/cr-prop-list.h        |   80 +
 src/st/croco/cr-pseudo.c           |  167 +
 src/st/croco/cr-pseudo.h           |   64 +
 src/st/croco/cr-rgb.c              |  687 +++++
 src/st/croco/cr-rgb.h              |   94 +
 src/st/croco/cr-selector.c         |  306 ++
 src/st/croco/cr-selector.h         |   95 +
 src/st/croco/cr-simple-sel.c       |  325 ++
 src/st/croco/cr-simple-sel.h       |  130 +
 src/st/croco/cr-statement.c        | 2794 +++++++++++++++++
 src/st/croco/cr-statement.h        |  440 +++
 src/st/croco/cr-string.c           |  168 ++
 src/st/croco/cr-string.h           |   76 +
 src/st/croco/cr-stylesheet.c       |  178 ++
 src/st/croco/cr-stylesheet.h       |  102 +
 src/st/croco/cr-term.c             |  790 +++++
 src/st/croco/cr-term.h             |  190 ++
 src/st/croco/cr-tknzr.c            | 2762 +++++++++++++++++
 src/st/croco/cr-tknzr.h            |  115 +
 src/st/croco/cr-token.c            |  636 ++++
 src/st/croco/cr-token.h            |  212 ++
 src/st/croco/cr-utils.c            | 1330 ++++++++
 src/st/croco/cr-utils.h            |  246 ++
 src/st/croco/libcroco-config.h     |   13 +
 src/st/croco/libcroco.h            |   42 +
 src/st/meson.build                 |   62 +-
 src/st/st-theme-node-private.h     |    2 +-
 src/st/st-theme-private.h          |    2 +-
 54 files changed, 24696 insertions(+), 7 deletions(-)
 create mode 100644 src/st/croco/cr-additional-sel.c
 create mode 100644 src/st/croco/cr-additional-sel.h
 create mode 100644 src/st/croco/cr-attr-sel.c
 create mode 100644 src/st/croco/cr-attr-sel.h
 create mode 100644 src/st/croco/cr-cascade.c
 create mode 100644 src/st/croco/cr-cascade.h
 create mode 100644 src/st/croco/cr-declaration.c
 create mode 100644 src/st/croco/cr-declaration.h
 create mode 100644 src/st/croco/cr-doc-handler.c
 create mode 100644 src/st/croco/cr-doc-handler.h
 create mode 100644 src/st/croco/cr-enc-handler.c
 create mode 100644 src/st/croco/cr-enc-handler.h
 create mode 100644 src/st/croco/cr-fonts.c
 create mode 100644 src/st/croco/cr-fonts.h
 create mode 100644 src/st/croco/cr-input.c
 create mode 100644 src/st/croco/cr-input.h
 create mode 100644 src/st/croco/cr-num.c
 create mode 100644 src/st/croco/cr-num.h
 create mode 100644 src/st/croco/cr-om-parser.c
 create mode 100644 src/st/croco/cr-om-parser.h
 create mode 100644 src/st/croco/cr-parser.c
 create mode 100644 src/st/croco/cr-parser.h
 create mode 100644 src/st/croco/cr-parsing-location.c
 create mode 100644 src/st/croco/cr-parsing-location.h
 create mode 100644 src/st/croco/cr-prop-list.c
 create mode 100644 src/st/croco/cr-prop-list.h
 create mode 100644 src/st/croco/cr-pseudo.c
 create mode 100644 src/st/croco/cr-pseudo.h
 create mode 100644 src/st/croco/cr-rgb.c
 create mode 100644 src/st/croco/cr-rgb.h
 create mode 100644 src/st/croco/cr-selector.c
 create mode 100644 src/st/croco/cr-selector.h
 create mode 100644 src/st/croco/cr-simple-sel.c
 create mode 100644 src/st/croco/cr-simple-sel.h
 create mode 100644 src/st/croco/cr-statement.c
 create mode 100644 src/st/croco/cr-statement.h
 create mode 100644 src/st/croco/cr-string.c
 create mode 100644 src/st/croco/cr-string.h
 create mode 100644 src/st/croco/cr-stylesheet.c
 create mode 100644 src/st/croco/cr-stylesheet.h
 create mode 100644 src/st/croco/cr-term.c
 create mode 100644 src/st/croco/cr-term.h
 create mode 100644 src/st/croco/cr-tknzr.c
 create mode 100644 src/st/croco/cr-tknzr.h
 create mode 100644 src/st/croco/cr-token.c
 create mode 100644 src/st/croco/cr-token.h
 create mode 100644 src/st/croco/cr-utils.c
 create mode 100644 src/st/croco/cr-utils.h
 create mode 100644 src/st/croco/libcroco-config.h
 create mode 100644 src/st/croco/libcroco.h

diff --git a/meson.build b/meson.build
index bfe4ee8a6..9c6d5b946 100644
--- a/meson.build
+++ b/meson.build
@@ -13,7 +13,6 @@ cogl_pc = 'mutter-cogl-' + mutter_api_version
 cogl_pango_pc = 'mutter-cogl-pango-' + mutter_api_version
 libmutter_pc = 'libmutter-' + mutter_api_version
 
-croco_req = '>= 0.6.8'
 ecal_req = '>= 3.5.3'
 eds_req = '>= 3.17.2'
 gcr_req = '>= 3.7.5'
@@ -89,7 +88,6 @@ gio_unix_dep = dependency('gio-unix-2.0', version: gio_req)
 gjs_dep = dependency('gjs-1.0', version: gjs_req)
 gtk_dep = dependency('gtk+-3.0', version: gtk_req)
 libxml_dep = dependency('libxml-2.0')
-croco_dep = dependency('libcroco-0.6', version: croco_req)
 clutter_dep = dependency(clutter_pc, version: mutter_req)
 cogl_dep = dependency(cogl_pc, version: mutter_req)
 cogl_pango_dep = dependency(cogl_pango_pc, version: mutter_req)
diff --git a/src/st/croco/cr-additional-sel.c b/src/st/croco/cr-additional-sel.c
new file mode 100644
index 000000000..c34b8d243
--- /dev/null
+++ b/src/st/croco/cr-additional-sel.c
@@ -0,0 +1,500 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ *
+ */
+
+#include "cr-additional-sel.h"
+#include "string.h"
+
+/**
+ * CRAdditionalSel:
+ *
+ * #CRAdditionalSel abstracts an additionnal selector.
+ * An additional selector is the selector part
+ * that comes after the combination of type selectors.
+ * It can be either "a class selector (the .class part),
+ * a pseudo class selector, an attribute selector 
+ * or an id selector.
+ */
+
+/**
+ * cr_additional_sel_new:
+ *
+ * Default constructor of #CRAdditionalSel.
+ * Returns the newly build instance of #CRAdditionalSel.
+ */
+CRAdditionalSel *
+cr_additional_sel_new (void)
+{
+        CRAdditionalSel *result = NULL;
+
+        result = g_try_malloc (sizeof (CRAdditionalSel));
+
+        if (result == NULL) {
+                cr_utils_trace_debug ("Out of memory");
+                return NULL;
+        }
+
+        memset (result, 0, sizeof (CRAdditionalSel));
+
+        return result;
+}
+
+/**
+ * cr_additional_sel_new_with_type:
+ * @a_sel_type: the type of the newly built instance 
+ * of #CRAdditionalSel.
+ *
+ * Constructor of #CRAdditionalSel.
+ * Returns the newly built instance of #CRAdditionalSel.
+ */
+CRAdditionalSel *
+cr_additional_sel_new_with_type (enum AddSelectorType a_sel_type)
+{
+        CRAdditionalSel *result = NULL;
+
+        result = cr_additional_sel_new ();
+
+        g_return_val_if_fail (result, NULL);
+
+        result->type = a_sel_type;
+
+        return result;
+}
+
+/**
+ * cr_additional_sel_set_class_name:
+ * @a_this: the "this pointer" of the current instance
+ * of #CRAdditionalSel .
+ * @a_class_name: the new class name to set.
+ *
+ * Sets a new class name to a
+ * CLASS additional selector.
+ */
+void
+cr_additional_sel_set_class_name (CRAdditionalSel * a_this,
+                                  CRString * a_class_name)
+{
+        g_return_if_fail (a_this && a_this->type == CLASS_ADD_SELECTOR);
+
+        if (a_this->content.class_name) {
+                cr_string_destroy (a_this->content.class_name);
+        }
+
+        a_this->content.class_name = a_class_name;
+}
+
+/**
+ * cr_additional_sel_set_id_name:
+ * @a_this: the "this pointer" of the current instance
+ * of #CRAdditionalSel .
+ * @a_id: the new id to set.
+ *
+ * Sets a new id name to an
+ * ID additional selector.
+ */
+void
+cr_additional_sel_set_id_name (CRAdditionalSel * a_this, CRString * a_id)
+{
+        g_return_if_fail (a_this && a_this->type == ID_ADD_SELECTOR);
+
+        if (a_this->content.id_name) {
+                cr_string_destroy (a_this->content.id_name);
+        }
+
+        a_this->content.id_name = a_id;
+}
+
+/**
+ * cr_additional_sel_set_pseudo:
+ * @a_this: the "this pointer" of the current instance
+ * of #CRAdditionalSel .
+ * @a_pseudo: the new pseudo to set.
+ *
+ * Sets a new pseudo to a
+ * PSEUDO additional selector.
+ */
+void
+cr_additional_sel_set_pseudo (CRAdditionalSel * a_this, CRPseudo * a_pseudo)
+{
+        g_return_if_fail (a_this
+                          && a_this->type == PSEUDO_CLASS_ADD_SELECTOR);
+
+        if (a_this->content.pseudo) {
+                cr_pseudo_destroy (a_this->content.pseudo);
+        }
+
+        a_this->content.pseudo = a_pseudo;
+}
+
+/**
+ * cr_additional_sel_set_attr_sel:
+ * @a_this: the "this pointer" of the current instance
+ * of #CRAdditionalSel .
+ * @a_sel: the new instance of #CRAttrSel to set.
+ *
+ * Sets a new instance of #CRAttrSel to 
+ * a ATTRIBUTE additional selector.
+ */
+void
+cr_additional_sel_set_attr_sel (CRAdditionalSel * a_this, CRAttrSel * a_sel)
+{
+        g_return_if_fail (a_this && a_this->type == ATTRIBUTE_ADD_SELECTOR);
+
+        if (a_this->content.attr_sel) {
+                cr_attr_sel_destroy (a_this->content.attr_sel);
+        }
+
+        a_this->content.attr_sel = a_sel;
+}
+
+/**
+ * cr_additional_sel_append:
+ * @a_this: the "this pointer" of the current instance
+ * of #CRAdditionalSel .
+ * @a_sel: the new instance to #CRAdditional to append.
+ *
+ * Appends a new instance of #CRAdditional to the
+ * current list of #CRAdditional.
+ *
+ * Returns the new list of CRAdditionalSel or NULL if an error arises.
+ */
+CRAdditionalSel *
+cr_additional_sel_append (CRAdditionalSel * a_this, CRAdditionalSel * a_sel)
+{
+        CRAdditionalSel *cur_sel = NULL;
+
+        g_return_val_if_fail (a_sel, NULL);
+
+        if (a_this == NULL) {
+                return a_sel;
+        }
+
+        if (a_sel == NULL)
+                return NULL;
+
+        for (cur_sel = a_this;
+             cur_sel && cur_sel->next; cur_sel = cur_sel->next) ;
+
+        g_return_val_if_fail (cur_sel != NULL, NULL);
+
+        cur_sel->next = a_sel;
+        a_sel->prev = cur_sel;
+
+        return a_this;
+}
+
+/**
+ * cr_additional_sel_prepend:
+ * @a_this: the "this pointer" of the current instance
+ * of #CRAdditionalSel .
+ * @a_sel: the new instance to #CRAdditional to preappend.
+ *
+ * Preppends a new instance of #CRAdditional to the
+ * current list of #CRAdditional.
+ *
+ * Returns the new list of CRAdditionalSel or NULL if an error arises.
+ */
+CRAdditionalSel *
+cr_additional_sel_prepend (CRAdditionalSel * a_this, CRAdditionalSel * a_sel)
+{
+        g_return_val_if_fail (a_sel, NULL);
+
+        if (a_this == NULL) {
+                return a_sel;
+        }
+
+        a_sel->next = a_this;
+        a_this->prev = a_sel;
+
+        return a_sel;
+}
+
+guchar *
+cr_additional_sel_to_string (CRAdditionalSel const * a_this)
+{
+        guchar *result = NULL;
+        GString *str_buf = NULL;
+        CRAdditionalSel const *cur = NULL;
+
+        g_return_val_if_fail (a_this, NULL);
+
+        str_buf = g_string_new (NULL);
+
+        for (cur = a_this; cur; cur = cur->next) {
+                switch (cur->type) {
+                case CLASS_ADD_SELECTOR:
+                        {
+                                guchar *name = NULL;
+
+                                if (cur->content.class_name) {
+                                        name = (guchar *) g_strndup
+                                                (cur->content.class_name->stryng->str,
+                                                 cur->content.class_name->stryng->len);
+
+                                        if (name) {
+                                                g_string_append_printf
+                                                        (str_buf, ".%s",
+                                                         name);
+                                                g_free (name);
+                                                name = NULL;
+                                        }
+                                }
+                        }
+                        break;
+
+                case ID_ADD_SELECTOR:
+                        {
+                                guchar *name = NULL;
+
+                                if (cur->content.id_name) {
+                                        name = (guchar *) g_strndup
+                                                (cur->content.id_name->stryng->str,
+                                                 cur->content.id_name->stryng->len);
+
+                                        if (name) {
+                                                g_string_append_printf
+                                                        (str_buf, "#%s",
+                                                         name);
+                                                g_free (name);
+                                                name = NULL;
+                                        }
+                                }
+                        }
+
+                        break;
+
+                case PSEUDO_CLASS_ADD_SELECTOR:
+                        {
+                                if (cur->content.pseudo) {
+                                        guchar *tmp_str = NULL;
+
+                                        tmp_str = cr_pseudo_to_string
+                                                (cur->content.pseudo);
+                                        if (tmp_str) {
+                                                g_string_append_printf
+                                                        (str_buf, ":%s",
+                                                         tmp_str);
+                                                g_free (tmp_str);
+                                                tmp_str = NULL;
+                                        }
+                                }
+                        }
+                        break;
+
+                case ATTRIBUTE_ADD_SELECTOR:
+                        if (cur->content.attr_sel) {
+                                guchar *tmp_str = NULL;
+
+                                g_string_append_c (str_buf, '[');
+                                tmp_str = cr_attr_sel_to_string
+                                        (cur->content.attr_sel);
+                                if (tmp_str) {
+                                        g_string_append_printf
+                                                (str_buf, "%s]", tmp_str);
+                                        g_free (tmp_str);
+                                        tmp_str = NULL;
+                                }
+                        }
+                        break;
+
+                default:
+                        break;
+                }
+        }
+
+        if (str_buf) {
+                result = (guchar *) str_buf->str;
+                g_string_free (str_buf, FALSE);
+                str_buf = NULL;
+        }
+
+        return result;
+}
+
+guchar * 
+cr_additional_sel_one_to_string (CRAdditionalSel const *a_this)
+{
+        guchar *result = NULL;
+        GString *str_buf = NULL;
+
+        g_return_val_if_fail (a_this, NULL) ;
+
+        str_buf = g_string_new (NULL) ;
+
+        switch (a_this->type) {
+        case CLASS_ADD_SELECTOR:
+        {
+                guchar *name = NULL;
+
+                if (a_this->content.class_name) {
+                        name = (guchar *) g_strndup
+                                (a_this->content.class_name->stryng->str,
+                                 a_this->content.class_name->stryng->len);
+
+                        if (name) {
+                                g_string_append_printf
+                                        (str_buf, ".%s",
+                                         name);
+                                g_free (name);
+                                name = NULL;
+                        }
+                }
+        }
+        break;
+
+        case ID_ADD_SELECTOR:
+        {
+                guchar *name = NULL;
+
+                if (a_this->content.id_name) {
+                        name = (guchar *) g_strndup
+                                (a_this->content.id_name->stryng->str,
+                                 a_this->content.id_name->stryng->len);
+
+                        if (name) {
+                                g_string_append_printf
+                                        (str_buf, "#%s",
+                                         name);
+                                g_free (name);
+                                name = NULL;
+                        }
+                }
+        }
+
+        break;
+
+        case PSEUDO_CLASS_ADD_SELECTOR:
+        {
+                if (a_this->content.pseudo) {
+                        guchar *tmp_str = NULL;
+
+                        tmp_str = cr_pseudo_to_string
+                                (a_this->content.pseudo);
+                        if (tmp_str) {
+                                g_string_append_printf
+                                        (str_buf, ":%s",
+                                         tmp_str);
+                                g_free (tmp_str);
+                                tmp_str = NULL;
+                        }
+                }
+        }
+        break;
+
+        case ATTRIBUTE_ADD_SELECTOR:
+                if (a_this->content.attr_sel) {
+                        guchar *tmp_str = NULL;
+
+                        g_string_append_printf (str_buf, "[");
+                        tmp_str = cr_attr_sel_to_string
+                                (a_this->content.attr_sel);
+                        if (tmp_str) {
+                                g_string_append_printf
+                                        (str_buf, "%s]", tmp_str);
+                                g_free (tmp_str);
+                                tmp_str = NULL;
+                        }
+                }
+                break;
+
+        default:
+                break;
+        }
+
+        if (str_buf) {
+                result = (guchar *) str_buf->str;
+                g_string_free (str_buf, FALSE);
+                str_buf = NULL;
+        }
+
+        return result;
+}
+
+/**
+ * cr_additional_sel_dump:
+ * @a_this: the "this pointer" of the current instance of
+ * #CRAdditionalSel.
+ * @a_fp: the destination file.
+ *
+ * Dumps the current instance of #CRAdditionalSel to a file
+ */
+void
+cr_additional_sel_dump (CRAdditionalSel const * a_this, FILE * a_fp)
+{
+        guchar *tmp_str = NULL;
+
+        g_return_if_fail (a_fp);
+
+        if (a_this) {
+                tmp_str = cr_additional_sel_to_string (a_this);
+                if (tmp_str) {
+                        fprintf (a_fp, "%s", tmp_str);
+                        g_free (tmp_str);
+                        tmp_str = NULL;
+                }
+        }
+}
+
+/**
+ * cr_additional_sel_destroy:
+ * @a_this: the "this pointer" of the current instance
+ * of #CRAdditionalSel .
+ *
+ * Destroys an instance of #CRAdditional.
+ */
+void
+cr_additional_sel_destroy (CRAdditionalSel * a_this)
+{
+        g_return_if_fail (a_this);
+
+        switch (a_this->type) {
+        case CLASS_ADD_SELECTOR:
+                cr_string_destroy (a_this->content.class_name);
+                a_this->content.class_name = NULL;
+                break;
+
+        case PSEUDO_CLASS_ADD_SELECTOR:
+                cr_pseudo_destroy (a_this->content.pseudo);
+                a_this->content.pseudo = NULL;
+                break;
+
+        case ID_ADD_SELECTOR:
+                cr_string_destroy (a_this->content.id_name);
+                a_this->content.id_name = NULL;
+                break;
+
+        case ATTRIBUTE_ADD_SELECTOR:
+                cr_attr_sel_destroy (a_this->content.attr_sel);
+                a_this->content.attr_sel = NULL;
+                break;
+
+        default:
+                break;
+        }
+
+        if (a_this->next) {
+                cr_additional_sel_destroy (a_this->next);
+        }
+
+        g_free (a_this);
+}
diff --git a/src/st/croco/cr-additional-sel.h b/src/st/croco/cr-additional-sel.h
new file mode 100644
index 000000000..7ca3e07d5
--- /dev/null
+++ b/src/st/croco/cr-additional-sel.h
@@ -0,0 +1,98 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See the COPYRIGHTS file for copyright information.
+ */
+
+
+#ifndef __CR_ADD_SEL_H__
+#define __CR_ADD_SEL_H__
+
+#include <stdio.h>
+#include <glib.h>
+#include "cr-utils.h"
+#include "cr-attr-sel.h"
+#include "cr-pseudo.h"
+#include "cr-additional-sel.h"
+
+G_BEGIN_DECLS
+
+enum AddSelectorType
+{
+        NO_ADD_SELECTOR = 0 ,
+        CLASS_ADD_SELECTOR = 1 ,
+        PSEUDO_CLASS_ADD_SELECTOR = 1 << 1,
+        ID_ADD_SELECTOR = 1 << 3,
+        ATTRIBUTE_ADD_SELECTOR = 1 << 4
+} ;
+
+union CRAdditionalSelectorContent
+{
+        CRString *class_name ;
+        CRString *id_name ;
+        CRPseudo *pseudo ;
+        CRAttrSel *attr_sel ;
+} ;
+
+typedef struct _CRAdditionalSel CRAdditionalSel ;
+
+struct _CRAdditionalSel
+{
+        enum AddSelectorType type ;
+        union CRAdditionalSelectorContent content ;
+
+        CRAdditionalSel * next ;
+        CRAdditionalSel * prev ;
+        CRParsingLocation location ;
+} ;
+
+CRAdditionalSel * cr_additional_sel_new (void) ;
+
+CRAdditionalSel * cr_additional_sel_new_with_type  (enum AddSelectorType a_sel_type) ;
+
+CRAdditionalSel * cr_additional_sel_append (CRAdditionalSel *a_this, 
+                                            CRAdditionalSel *a_sel) ;
+
+void cr_additional_sel_set_class_name (CRAdditionalSel *a_this,
+                                       CRString *a_class_name) ;
+
+void cr_additional_sel_set_id_name (CRAdditionalSel *a_this,
+                                    CRString *a_id) ;
+
+void cr_additional_sel_set_pseudo (CRAdditionalSel *a_this,
+                                   CRPseudo *a_pseudo) ;
+
+void cr_additional_sel_set_attr_sel (CRAdditionalSel *a_this,
+                                     CRAttrSel *a_sel) ;
+
+CRAdditionalSel * cr_additional_sel_prepend (CRAdditionalSel *a_this, 
+                                             CRAdditionalSel *a_sel) ;
+
+guchar * cr_additional_sel_to_string (CRAdditionalSel const *a_this) ;
+
+guchar * cr_additional_sel_one_to_string (CRAdditionalSel const *a_this) ;
+
+void cr_additional_sel_dump (CRAdditionalSel const *a_this, FILE *a_fp) ;
+
+void cr_additional_sel_destroy (CRAdditionalSel *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_ADD_SEL_H*/
diff --git a/src/st/croco/cr-attr-sel.c b/src/st/croco/cr-attr-sel.c
new file mode 100644
index 000000000..c057bbbf6
--- /dev/null
+++ b/src/st/croco/cr-attr-sel.c
@@ -0,0 +1,235 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ * 
+ * See COPYRIGHTS file for copyrights information.
+ */
+
+#include <stdio.h>
+#include "cr-attr-sel.h"
+
+/**
+ * CRAttrSel:
+ *
+ * #CRAdditionalSel abstracts an attribute selector.
+ * Attributes selectors are described in the css2 spec [5.8].
+ * There are more generally used in the css2 selectors described in
+ * css2 spec [5] .
+ */
+
+/**
+ * cr_attr_sel_new:
+ * The constructor of #CRAttrSel.
+ * Returns the newly allocated instance
+ * of #CRAttrSel.
+ */
+CRAttrSel *
+cr_attr_sel_new (void)
+{
+        CRAttrSel *result = NULL;
+
+        result = g_malloc0 (sizeof (CRAttrSel));
+
+        return result;
+}
+
+/**
+ * cr_attr_sel_append_attr_sel:
+ * @a_this: the this pointer of the current instance of  #CRAttrSel.
+ * @a_attr_sel: selector to append.
+ *
+ * Appends an attribute selector to the current list of
+ * attribute selectors represented by a_this.
+ * Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_attr_sel_append_attr_sel (CRAttrSel * a_this, CRAttrSel * a_attr_sel)
+{
+        CRAttrSel *cur_sel = NULL;
+
+        g_return_val_if_fail (a_this && a_attr_sel, 
+                              CR_BAD_PARAM_ERROR);
+
+        for (cur_sel = a_this; 
+             cur_sel->next; 
+             cur_sel = cur_sel->next) ;
+
+        cur_sel->next = a_attr_sel;
+        a_attr_sel->prev = cur_sel;
+
+        return CR_OK;
+}
+
+/**
+ * cr_attr_sel_prepend_attr_sel:
+ *@a_this: the "this pointer" of the current instance *of #CRAttrSel.
+ *@a_attr_sel: the attribute selector to append.
+ *
+ *Prepends an attribute selector to the list of
+ *attributes selector represented by a_this.
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_attr_sel_prepend_attr_sel (CRAttrSel * a_this, 
+                              CRAttrSel * a_attr_sel)
+{
+        g_return_val_if_fail (a_this && a_attr_sel, 
+                              CR_BAD_PARAM_ERROR);
+
+        a_attr_sel->next = a_this;
+        a_this->prev = a_attr_sel;
+
+        return CR_OK;
+}
+
+/**
+ * cr_attr_sel_to_string:
+ * @a_this: the current instance of #CRAttrSel.
+ *
+ * Serializes an attribute selector into a string
+ * Returns the serialized attribute selector.
+ */
+guchar *
+cr_attr_sel_to_string (CRAttrSel const * a_this)
+{
+        CRAttrSel const *cur = NULL;
+        guchar *result = NULL;
+        GString *str_buf = NULL;
+
+        g_return_val_if_fail (a_this, NULL);
+
+        str_buf = g_string_new (NULL);
+
+        for (cur = a_this; cur; cur = cur->next) {
+                if (cur->prev) {
+                        g_string_append_c (str_buf, ' ');
+                }
+
+                if (cur->name) {
+                        guchar *name = NULL;
+
+                        name = (guchar *) g_strndup (cur->name->stryng->str, 
+                                          cur->name->stryng->len);
+                        if (name) {
+                                g_string_append (str_buf, (const gchar *) name);
+                                g_free (name);
+                                name = NULL;
+                        }
+                }
+
+                if (cur->value) {
+                        guchar *value = NULL;
+
+                        value = (guchar *) g_strndup (cur->value->stryng->str, 
+                                           cur->value->stryng->len);
+                        if (value) {
+                                switch (cur->match_way) {
+                                case SET:
+                                        break;
+
+                                case EQUALS:
+                                        g_string_append_c (str_buf, '=');
+                                        break;
+
+                                case INCLUDES:
+                                        g_string_append (str_buf, "~=");
+                                        break;
+
+                                case DASHMATCH:
+                                        g_string_append (str_buf, "|=");
+                                        break;
+
+                                default:
+                                        break;
+                                }
+
+                                g_string_append_printf
+                                        (str_buf, "\"%s\"", value);
+
+                                g_free (value);
+                                value = NULL;
+                        }
+                }
+        }
+
+        if (str_buf) {
+                result = (guchar *) str_buf->str;
+                g_string_free (str_buf, FALSE);
+        }
+
+        return result;
+}
+
+/**
+ * cr_attr_sel_dump:
+ * @a_this: the "this pointer" of the current instance of
+ * #CRAttrSel.
+ * @a_fp: the destination file.
+ *
+ * Dumps the current instance of #CRAttrSel to a file.
+ */
+void
+cr_attr_sel_dump (CRAttrSel const * a_this, FILE * a_fp)
+{
+        guchar *tmp_str = NULL;
+
+        g_return_if_fail (a_this);
+
+        tmp_str = cr_attr_sel_to_string (a_this);
+
+        if (tmp_str) {
+                fprintf (a_fp, "%s", tmp_str);
+                g_free (tmp_str);
+                tmp_str = NULL;
+        }
+}
+
+/**
+ *cr_attr_sel_destroy:
+ *@a_this: the "this pointer" of the current
+ *instance of #CRAttrSel.
+ *
+ *Destroys the current instance of #CRAttrSel.
+ *Frees all the fields if they are non null.
+ */
+void
+cr_attr_sel_destroy (CRAttrSel * a_this)
+{
+        g_return_if_fail (a_this);
+
+        if (a_this->name) {
+                cr_string_destroy (a_this->name);
+                a_this->name = NULL;
+        }
+
+        if (a_this->value) {
+                cr_string_destroy (a_this->value);
+                a_this->value = NULL;
+        }
+
+        if (a_this->next) {
+                cr_attr_sel_destroy (a_this->next);
+                a_this->next = NULL;
+        }
+
+        if (a_this) {
+                g_free (a_this);
+                a_this = NULL;
+        }
+}
+
diff --git a/src/st/croco/cr-attr-sel.h b/src/st/croco/cr-attr-sel.h
new file mode 100644
index 000000000..82d5a87d7
--- /dev/null
+++ b/src/st/croco/cr-attr-sel.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#ifndef __CR_ATTR_SEL_H__
+#define __CR_ATTR_SEL_H__
+
+#include <stdio.h>
+#include <glib.h>
+#include "cr-utils.h"
+#include "cr-parsing-location.h"
+#include "cr-string.h"
+
+G_BEGIN_DECLS
+
+
+struct _CRAttrSel ;
+typedef struct _CRAttrSel CRAttrSel ;
+
+enum AttrMatchWay
+{
+        NO_MATCH = 0,
+        SET,
+        EQUALS,
+        INCLUDES,
+        DASHMATCH
+} ;
+
+struct _CRAttrSel
+{
+        CRString             *name ;
+        CRString             *value ;
+        enum AttrMatchWay  match_way ;
+        CRAttrSel          *next ;
+        CRAttrSel          *prev ;
+        CRParsingLocation location ;
+} ;
+
+CRAttrSel * cr_attr_sel_new (void) ;
+
+enum CRStatus cr_attr_sel_append_attr_sel (CRAttrSel * a_this, 
+                                           CRAttrSel *a_attr_sel) ;
+
+enum CRStatus cr_attr_sel_prepend_attr_sel (CRAttrSel *a_this, 
+                                            CRAttrSel *a_attr_sel) ;
+        
+guchar * cr_attr_sel_to_string (CRAttrSel const *a_this) ;
+
+void cr_attr_sel_dump (CRAttrSel const *a_this, FILE *a_fp) ;
+
+void cr_attr_sel_destroy (CRAttrSel *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_ATTR_SEL_H__*/
diff --git a/src/st/croco/cr-cascade.c b/src/st/croco/cr-cascade.c
new file mode 100644
index 000000000..b8f827716
--- /dev/null
+++ b/src/st/croco/cr-cascade.c
@@ -0,0 +1,215 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * Copyright (C) 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the 
+ * GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the 
+ * GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*
+ *$Id$
+ */
+
+#include <string.h>
+#include "cr-cascade.h"
+
+#define PRIVATE(a_this) ((a_this)->priv)
+
+struct _CRCascadePriv {
+ /**
+	 *the 3 style sheets of the cascade:
+	 *author, user, and useragent sheet.
+	 *Intended to be addressed by
+	 *sheets[ORIGIN_AUTHOR] or sheets[ORIGIN_USER]
+	 *of sheets[ORIGIN_UA] ;
+	 */
+        CRStyleSheet *sheets[3];
+        guint ref_count;
+};
+
+/**
+ * cr_cascade_new:
+ *@a_author_sheet: the author origin style sheet.  May be NULL.
+ *@a_user_sheet: the user origin style sheet.  May be NULL.
+ *@a_ua_sheet: the user agent origin style sheet.  May be NULL.
+ *
+ *Constructor of the #CRCascade class.
+ *Note that all three parameters of this
+ *method are ref counted and their refcount is increased.
+ *Their refcount will be decreased at the destruction of
+ *the instance of #CRCascade.
+ *So the caller should not call their destructor. The caller
+ *should call their ref/unref method instead if it wants
+ *
+ *Returns the newly built instance of CRCascade or NULL if
+ *an error arose during constrution.
+ */
+CRCascade *
+cr_cascade_new (CRStyleSheet * a_author_sheet,
+                CRStyleSheet * a_user_sheet, CRStyleSheet * a_ua_sheet)
+{
+        CRCascade *result = NULL;
+
+        result = g_try_malloc (sizeof (CRCascade));
+        if (!result) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+        memset (result, 0, sizeof (CRCascade));
+
+        PRIVATE (result) = g_try_malloc (sizeof (CRCascadePriv));
+        if (!PRIVATE (result)) {
+                cr_utils_trace_info ("Out of memory");
+                g_free (result);
+                return NULL;
+        }
+        memset (PRIVATE (result), 0, sizeof (CRCascadePriv));
+
+        if (a_author_sheet) {
+                cr_cascade_set_sheet (result, a_author_sheet, ORIGIN_AUTHOR);
+        }
+        if (a_user_sheet) {
+                cr_cascade_set_sheet (result, a_user_sheet, ORIGIN_USER);
+        }
+        if (a_ua_sheet) {
+                cr_cascade_set_sheet (result, a_ua_sheet, ORIGIN_UA);
+        }
+
+        return result;
+}
+
+/**
+ * cr_cascade_get_sheet:
+ *@a_this: the current instance of #CRCascade.
+ *@a_origin: the origin of the style sheet as
+ *defined in the css2 spec in chapter 6.4.
+ *Gets a given origin sheet.
+ *
+ *Gets a sheet, part of the cascade.
+ *Note that the returned stylesheet
+ *is refcounted so if the caller wants
+ *to manage it's lifecycle, it must use
+ *cr_stylesheet_ref()/cr_stylesheet_unref() instead
+ *of the cr_stylesheet_destroy() method.
+ *Returns the style sheet, or NULL if it does not
+ *exist.
+ */
+CRStyleSheet *
+cr_cascade_get_sheet (CRCascade * a_this, enum CRStyleOrigin a_origin)
+{
+        g_return_val_if_fail (a_this
+                              && a_origin >= ORIGIN_UA
+                              && a_origin < NB_ORIGINS, NULL);
+
+        return PRIVATE (a_this)->sheets[a_origin];
+}
+
+/**
+ * cr_cascade_set_sheet:
+ *@a_this: the current instance of #CRCascade.
+ *@a_sheet: the stylesheet to set.
+ *@a_origin: the origin of the stylesheet.
+ *
+ *Sets a stylesheet in the cascade
+ *
+ *Returns CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_cascade_set_sheet (CRCascade * a_this,
+                      CRStyleSheet * a_sheet, enum CRStyleOrigin a_origin)
+{
+        g_return_val_if_fail (a_this
+                              && a_sheet
+                              && a_origin >= ORIGIN_UA
+                              && a_origin < NB_ORIGINS, CR_BAD_PARAM_ERROR);
+
+        if (PRIVATE (a_this)->sheets[a_origin])
+                cr_stylesheet_unref (PRIVATE (a_this)->sheets[a_origin]);
+        PRIVATE (a_this)->sheets[a_origin] = a_sheet;
+        cr_stylesheet_ref (a_sheet);
+        a_sheet->origin = a_origin;
+        return CR_OK;
+}
+
+/**
+ *cr_cascade_ref:
+ *@a_this: the current instance of #CRCascade
+ *
+ *Increases the reference counter of the current instance
+ *of #CRCascade.
+ */
+void
+cr_cascade_ref (CRCascade * a_this)
+{
+        g_return_if_fail (a_this && PRIVATE (a_this));
+
+        PRIVATE (a_this)->ref_count++;
+}
+
+/**
+ * cr_cascade_unref:
+ *@a_this: the current instance of 
+ *#CRCascade.
+ *
+ *Decrements the reference counter associated
+ *to this instance of #CRCascade. If the reference
+ *counter reaches zero, the instance is destroyed 
+ *using cr_cascade_destroy()
+ */
+void
+cr_cascade_unref (CRCascade * a_this)
+{
+        g_return_if_fail (a_this && PRIVATE (a_this));
+
+        if (PRIVATE (a_this)->ref_count)
+                PRIVATE (a_this)->ref_count--;
+        if (!PRIVATE (a_this)->ref_count) {
+                cr_cascade_destroy (a_this);
+        }
+}
+
+/**
+ * cr_cascade_destroy:
+ * @a_this: the current instance of #CRCascade
+ *
+ * Destructor of #CRCascade.
+ */
+void
+cr_cascade_destroy (CRCascade * a_this)
+{
+        g_return_if_fail (a_this);
+
+        if (PRIVATE (a_this)) {
+                gulong i = 0;
+
+                for (i = 0; PRIVATE (a_this)->sheets && i < NB_ORIGINS; i++) {
+                        if (PRIVATE (a_this)->sheets[i]) {
+                                if (cr_stylesheet_unref
+                                    (PRIVATE (a_this)->sheets[i])
+                                    == TRUE) {
+                                        PRIVATE (a_this)->sheets[i] = NULL;
+                                }
+                        }
+                }
+                g_free (PRIVATE (a_this));
+                PRIVATE (a_this) = NULL;
+        }
+        g_free (a_this);
+}
diff --git a/src/st/croco/cr-cascade.h b/src/st/croco/cr-cascade.h
new file mode 100644
index 000000000..3119ae85f
--- /dev/null
+++ b/src/st/croco/cr-cascade.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the 
+ * GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the 
+ * GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ */
+
+/*
+ *$Id$
+ */
+
+#ifndef __CR_CASCADE_H__
+#define __CR_CASCADE_H__
+
+#include "cr-stylesheet.h"
+
+/**
+ *@file
+ *the declaration of the #CRCascade class.
+ */
+
+G_BEGIN_DECLS
+
+
+typedef struct _CRCascadePriv CRCascadePriv ;
+
+/**
+ *An abstraction of the "Cascade" defined
+ *in the css2 spec, chapter 6.4.
+ */
+typedef struct _CRCascade CRCascade ;
+
+struct _CRCascade
+{
+	CRCascadePriv *priv ;
+};
+
+
+CRCascade * cr_cascade_new (CRStyleSheet *a_author_sheet,
+                            CRStyleSheet *a_user_sheet,
+                            CRStyleSheet *a_ua_sheet) ;
+
+CRStyleSheet * cr_cascade_get_sheet (CRCascade *a_this,
+                                     enum CRStyleOrigin a_origin) ;
+
+enum CRStatus cr_cascade_set_sheet (CRCascade *a_this,
+                                    CRStyleSheet *a_sheet,
+                                    enum CRStyleOrigin a_origin) ;
+
+void cr_cascade_ref (CRCascade *a_this) ;
+
+void cr_cascade_unref (CRCascade *a_this) ;
+
+void cr_cascade_destroy (CRCascade *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_CASCADE_H__*/
diff --git a/src/st/croco/cr-declaration.c b/src/st/croco/cr-declaration.c
new file mode 100644
index 000000000..2a13c8266
--- /dev/null
+++ b/src/st/croco/cr-declaration.c
@@ -0,0 +1,801 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli.
+ * See COPYRIGHTS file for copyright information.
+ */
+
+
+#include <string.h>
+#include "cr-declaration.h"
+#include "cr-statement.h"
+#include "cr-parser.h"
+
+/**
+ *@CRDeclaration:
+ *
+ *The definition of the #CRDeclaration class.
+ */
+
+/**
+ * dump:
+ *@a_this: the current instance of #CRDeclaration.
+ *@a_fp: the destination file pointer.
+ *@a_indent: the number of indentation white char. 
+ *
+ *Dumps (serializes) one css declaration to a file.
+ */
+static void
+dump (CRDeclaration const * a_this, FILE * a_fp, glong a_indent)
+{
+        guchar *str = NULL;
+
+        g_return_if_fail (a_this);
+
+        str = (guchar *) cr_declaration_to_string (a_this, a_indent);
+        if (str) {
+                fprintf (a_fp, "%s", str);
+                g_free (str);
+                str = NULL;
+        }
+}
+
+/**
+ * cr_declaration_new:
+ * @a_statement: the statement this declaration belongs to. can be NULL.
+ *@a_property: the property string of the declaration
+ *@a_value: the value expression of the declaration.
+ *Constructor of #CRDeclaration.
+ *
+ *Returns the newly built instance of #CRDeclaration, or NULL in
+ *case of error.
+ *
+ *The returned CRDeclaration takes ownership of @a_property and @a_value.
+ *(E.g. cr_declaration_destroy on this CRDeclaration will also free
+ *@a_property and @a_value.)
+ */
+CRDeclaration *
+cr_declaration_new (CRStatement * a_statement,
+                    CRString * a_property, CRTerm * a_value)
+{
+        CRDeclaration *result = NULL;
+
+        g_return_val_if_fail (a_property, NULL);
+
+        if (a_statement)
+                g_return_val_if_fail (a_statement
+                                      && ((a_statement->type == RULESET_STMT)
+                                          || (a_statement->type
+                                              == AT_FONT_FACE_RULE_STMT)
+                                          || (a_statement->type
+                                              == AT_PAGE_RULE_STMT)), NULL);
+
+        result = g_try_malloc (sizeof (CRDeclaration));
+        if (!result) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+        memset (result, 0, sizeof (CRDeclaration));
+        result->property = a_property;
+        result->value = a_value;
+
+        if (a_value) {
+                cr_term_ref (a_value);
+        }
+        result->parent_statement = a_statement;
+        return result;
+}
+
+/**
+ * cr_declaration_parse_from_buf:
+ *@a_statement: the parent css2 statement of this
+ *this declaration. Must be non NULL and of type
+ *RULESET_STMT (must be a ruleset).
+ *@a_str: the string that contains the statement.
+ *@a_enc: the encoding of a_str.
+ *
+ *Parses a text buffer that contains
+ *a css declaration.
+ *Returns the parsed declaration, or NULL in case of error.
+ */
+CRDeclaration *
+cr_declaration_parse_from_buf (CRStatement * a_statement,
+                               const guchar * a_str, enum CREncoding a_enc)
+{
+        enum CRStatus status = CR_OK;
+        CRTerm *value = NULL;
+        CRString *property = NULL;
+        CRDeclaration *result = NULL;
+        CRParser *parser = NULL;
+        gboolean important = FALSE;
+
+        g_return_val_if_fail (a_str, NULL);
+        if (a_statement)
+                g_return_val_if_fail (a_statement->type == RULESET_STMT,
+                                      NULL);
+
+        parser = cr_parser_new_from_buf ((guchar*)a_str, strlen ((const char *) a_str), a_enc, FALSE);
+        g_return_val_if_fail (parser, NULL);
+
+        status = cr_parser_try_to_skip_spaces_and_comments (parser);
+        if (status != CR_OK)
+                goto cleanup;
+
+        status = cr_parser_parse_declaration (parser, &property,
+                                              &value, &important);
+        if (status != CR_OK || !property)
+                goto cleanup;
+
+        result = cr_declaration_new (a_statement, property, value);
+        if (result) {
+                property = NULL;
+                value = NULL;
+                result->important = important;
+        }
+
+      cleanup:
+
+        if (parser) {
+                cr_parser_destroy (parser);
+                parser = NULL;
+        }
+
+        if (property) {
+                cr_string_destroy (property);
+                property = NULL;
+        }
+
+        if (value) {
+                cr_term_destroy (value);
+                value = NULL;
+        }
+
+        return result;
+}
+
+/**
+ * cr_declaration_parse_list_from_buf:
+ *@a_str: the input buffer that contains the list of declaration to
+ *parse.
+ *@a_enc: the encoding of a_str
+ *
+ *Parses a ';' separated list of properties declaration.
+ *Returns the parsed list of declaration, NULL if parsing failed.
+ */
+CRDeclaration *
+cr_declaration_parse_list_from_buf (const guchar * a_str,
+                                    enum CREncoding a_enc)
+{
+
+        enum CRStatus status = CR_OK;
+        CRTerm *value = NULL;
+        CRString *property = NULL;
+        CRDeclaration *result = NULL,
+                *cur_decl = NULL;
+        CRParser *parser = NULL;
+        CRTknzr *tokenizer = NULL;
+        gboolean important = FALSE;
+
+        g_return_val_if_fail (a_str, NULL);
+
+        parser = cr_parser_new_from_buf ((guchar*)a_str, strlen ((const char *) a_str), a_enc, FALSE);
+        g_return_val_if_fail (parser, NULL);
+        status = cr_parser_get_tknzr (parser, &tokenizer);
+        if (status != CR_OK || !tokenizer) {
+                if (status == CR_OK)
+                        status = CR_ERROR;
+                goto cleanup;
+        }
+        status = cr_parser_try_to_skip_spaces_and_comments (parser);
+        if (status != CR_OK)
+                goto cleanup;
+
+        status = cr_parser_parse_declaration (parser, &property,
+                                              &value, &important);
+        if (status != CR_OK || !property) {
+                if (status != CR_OK)
+                        status = CR_ERROR;
+                goto cleanup;
+        }
+        result = cr_declaration_new (NULL, property, value);
+        if (result) {
+                property = NULL;
+                value = NULL;
+                result->important = important;
+        }
+        /*now, go parse the other declarations */
+        for (;;) {
+                guint32 c = 0;
+
+                cr_parser_try_to_skip_spaces_and_comments (parser);
+                status = cr_tknzr_peek_char (tokenizer, &c);
+                if (status != CR_OK) {
+                        if (status == CR_END_OF_INPUT_ERROR)
+                                status = CR_OK;
+                        goto cleanup;
+                }
+                if (c == ';') {
+                        status = cr_tknzr_read_char (tokenizer, &c);
+                } else {
+                        break;
+                }
+                important = FALSE;
+                cr_parser_try_to_skip_spaces_and_comments (parser);
+                status = cr_parser_parse_declaration (parser, &property,
+                                                      &value, &important);
+                if (status != CR_OK || !property) {
+                        if (status == CR_END_OF_INPUT_ERROR) {
+                                status = CR_OK;
+                        }
+                        break;
+                }
+                cur_decl = cr_declaration_new (NULL, property, value);
+                if (cur_decl) {
+                        cur_decl->important = important;
+                        result = cr_declaration_append (result, cur_decl);
+                        property = NULL;
+                        value = NULL;
+                        cur_decl = NULL;
+                } else {
+                        break;
+                }
+        }
+
+      cleanup:
+
+        if (parser) {
+                cr_parser_destroy (parser);
+                parser = NULL;
+        }
+
+        if (property) {
+                cr_string_destroy (property);
+                property = NULL;
+        }
+
+        if (value) {
+                cr_term_destroy (value);
+                value = NULL;
+        }
+
+        if (status != CR_OK && result) {
+                cr_declaration_destroy (result);
+                result = NULL;
+        }
+        return result;
+}
+
+/**
+ * cr_declaration_append:
+ *@a_this: the current declaration list.
+ *@a_new: the declaration to append.
+ *
+ *Appends a new declaration to the current declarations list.
+ *Returns the declaration list with a_new appended to it, or NULL
+ *in case of error.
+ */
+CRDeclaration *
+cr_declaration_append (CRDeclaration * a_this, CRDeclaration * a_new)
+{
+        CRDeclaration *cur = NULL;
+
+        g_return_val_if_fail (a_new, NULL);
+
+        if (!a_this)
+                return a_new;
+
+        for (cur = a_this; cur && cur->next; cur = cur->next) ;
+
+        cur->next = a_new;
+        a_new->prev = cur;
+
+        return a_this;
+}
+
+/**
+ * cr_declaration_unlink:
+ *@a_decls: the declaration to unlink.
+ *
+ *Unlinks the declaration from the declaration list.
+ *case of a successfull completion, NULL otherwise.
+ *
+ *Returns a pointer to the unlinked declaration in
+ */
+CRDeclaration *
+cr_declaration_unlink (CRDeclaration * a_decl)
+{
+        CRDeclaration *result = a_decl;
+
+        g_return_val_if_fail (result, NULL);
+
+        /*
+         *some sanity checks first
+         */
+        if (a_decl->prev) {
+                g_return_val_if_fail (a_decl->prev->next == a_decl, NULL);
+
+        }
+        if (a_decl->next) {
+                g_return_val_if_fail (a_decl->next->prev == a_decl, NULL);
+        }
+
+        /*
+         *now, the real unlinking job.
+         */
+        if (a_decl->prev) {
+                a_decl->prev->next = a_decl->next;
+        }
+        if (a_decl->next) {
+                a_decl->next->prev = a_decl->prev;
+        }
+        if (a_decl->parent_statement) {
+                CRDeclaration **children_decl_ptr = NULL;
+
+                switch (a_decl->parent_statement->type) {
+                case RULESET_STMT:
+                        if (a_decl->parent_statement->kind.ruleset) {
+                                children_decl_ptr =
+                                        &a_decl->parent_statement->
+                                        kind.ruleset->decl_list;
+                        }
+
+                        break;
+
+                case AT_FONT_FACE_RULE_STMT:
+                        if (a_decl->parent_statement->kind.font_face_rule) {
+                                children_decl_ptr =
+                                        &a_decl->parent_statement->
+                                        kind.font_face_rule->decl_list;
+                        }
+                        break;
+                case AT_PAGE_RULE_STMT:
+                        if (a_decl->parent_statement->kind.page_rule) {
+                                children_decl_ptr =
+                                        &a_decl->parent_statement->
+                                        kind.page_rule->decl_list;
+                        }
+
+                default:
+                        break;
+                }
+                if (children_decl_ptr
+                    && *children_decl_ptr && *children_decl_ptr == a_decl)
+                        *children_decl_ptr = (*children_decl_ptr)->next;
+        }
+
+        a_decl->next = NULL;
+        a_decl->prev = NULL;
+        a_decl->parent_statement = NULL;
+
+        return result;
+}
+
+/**
+ * cr_declaration_prepend:
+ * @a_this: the current declaration list.
+ * @a_new: the declaration to prepend.
+ *
+ * prepends a declaration to the current declaration list.
+ *
+ * Returns the list with a_new prepended or NULL in case of error.
+ */
+CRDeclaration *
+cr_declaration_prepend (CRDeclaration * a_this, CRDeclaration * a_new)
+{
+        CRDeclaration *cur = NULL;
+
+        g_return_val_if_fail (a_new, NULL);
+
+        if (!a_this)
+                return a_new;
+
+        a_this->prev = a_new;
+        a_new->next = a_this;
+
+        for (cur = a_new; cur && cur->prev; cur = cur->prev) ;
+
+        return cur;
+}
+
+/**
+ * cr_declaration_append2:
+ *@a_this: the current declaration list.
+ *@a_prop: the property string of the declaration to append.
+ *@a_value: the value of the declaration to append.
+ *
+ *Appends a declaration to the current declaration list.
+ *Returns the list with the new property appended to it, or NULL in
+ *case of an error.
+ */
+CRDeclaration *
+cr_declaration_append2 (CRDeclaration * a_this,
+                        CRString * a_prop, CRTerm * a_value)
+{
+        CRDeclaration *new_elem = NULL;
+
+        if (a_this) {
+                new_elem = cr_declaration_new (a_this->parent_statement,
+                                               a_prop, a_value);
+        } else {
+                new_elem = cr_declaration_new (NULL, a_prop, a_value);
+        }
+
+        g_return_val_if_fail (new_elem, NULL);
+
+        return cr_declaration_append (a_this, new_elem);
+}
+
+/**
+ * cr_declaration_dump:
+ *@a_this: the current instance of #CRDeclaration.
+ *@a_fp: the destination file.
+ *@a_indent: the number of indentation white char.
+ *@a_one_per_line: whether to put one declaration per line of not .
+ *
+ *
+ *Dumps a declaration list to a file.
+ */
+void
+cr_declaration_dump (CRDeclaration const * a_this, FILE * a_fp, glong a_indent,
+                     gboolean a_one_per_line)
+{
+        CRDeclaration const *cur = NULL;
+
+        g_return_if_fail (a_this);
+
+        for (cur = a_this; cur; cur = cur->next) {
+                if (cur->prev) {
+                        if (a_one_per_line == TRUE)
+                                fprintf (a_fp, ";\n");
+                        else
+                                fprintf (a_fp, "; ");
+                }
+                dump (cur, a_fp, a_indent);
+        }
+}
+
+/**
+ * cr_declaration_dump_one:
+ *@a_this: the current instance of #CRDeclaration.
+ *@a_fp: the destination file.
+ *@a_indent: the number of indentation white char.
+ *
+ *Dumps the first declaration of the declaration list to a file.
+ */
+void
+cr_declaration_dump_one (CRDeclaration const * a_this, FILE * a_fp, glong a_indent)
+{
+        g_return_if_fail (a_this);
+
+        dump (a_this, a_fp, a_indent);
+}
+
+/**
+ * cr_declaration_to_string:
+ *@a_this: the current instance of #CRDeclaration.
+ *@a_indent: the number of indentation white char
+ *to put before the actual serialisation.
+ *
+ *Serializes the declaration into a string
+ *Returns the serialized form the declaration. The caller must
+ *free the string using g_free().
+ */
+gchar *
+cr_declaration_to_string (CRDeclaration const * a_this, gulong a_indent)
+{
+        GString *stringue = NULL;
+
+        gchar *str = NULL,
+                *result = NULL;
+
+        g_return_val_if_fail (a_this, NULL);
+
+	stringue = g_string_new (NULL);
+
+	if (a_this->property 
+	    && a_this->property->stryng
+	    && a_this->property->stryng->str) {
+		str = g_strndup (a_this->property->stryng->str,
+				 a_this->property->stryng->len);
+		if (str) {
+			cr_utils_dump_n_chars2 (' ', stringue, 
+						a_indent);
+			g_string_append (stringue, str);
+			g_free (str);
+			str = NULL;
+		} else
+                        goto error;
+
+                if (a_this->value) {
+                        guchar *value_str = NULL;
+
+                        value_str = cr_term_to_string (a_this->value);
+                        if (value_str) {
+                                g_string_append_printf (stringue, " : %s",
+                                                        value_str);
+                                g_free (value_str);
+                        } else
+                                goto error;
+                }
+                if (a_this->important == TRUE) {
+                        g_string_append_printf (stringue, " %s",
+                                                "!important");
+                }
+        }
+        if (stringue && stringue->str) {
+                result = stringue->str;
+                g_string_free (stringue, FALSE);
+        }
+        return result;
+
+      error:
+        if (stringue) {
+                g_string_free (stringue, TRUE);
+                stringue = NULL;
+        }
+        if (str) {
+                g_free (str);
+                str = NULL;
+        }
+
+        return result;
+}
+
+/**
+ * cr_declaration_list_to_string:
+ *@a_this: the current instance of #CRDeclaration.
+ *@a_indent: the number of indentation white char
+ *to put before the actual serialisation.
+ *
+ *Serializes the declaration list into a string
+ */
+guchar *
+cr_declaration_list_to_string (CRDeclaration const * a_this, gulong a_indent)
+{
+        CRDeclaration const *cur = NULL;
+        GString *stringue = NULL;
+        guchar *str = NULL,
+                *result = NULL;
+
+        g_return_val_if_fail (a_this, NULL);
+
+        stringue = g_string_new (NULL);
+
+        for (cur = a_this; cur; cur = cur->next) {
+                str = (guchar *) cr_declaration_to_string (cur, a_indent);
+                if (str) {
+                        g_string_append_printf (stringue, "%s;", str);
+                        g_free (str);
+                } else
+                        break;
+        }
+        if (stringue && stringue->str) {
+                result = (guchar *) stringue->str;
+                g_string_free (stringue, FALSE);
+        }
+
+        return result;
+}
+
+/**
+ * cr_declaration_list_to_string2:
+ *@a_this: the current instance of #CRDeclaration.
+ *@a_indent: the number of indentation white char
+ *@a_one_decl_per_line: whether to output one doc per line or not.
+ *to put before the actual serialisation.
+ *
+ *Serializes the declaration list into a string
+ *Returns the serialized form the declararation.
+ */
+guchar *
+cr_declaration_list_to_string2 (CRDeclaration const * a_this,
+                                gulong a_indent, gboolean a_one_decl_per_line)
+{
+        CRDeclaration const *cur = NULL;
+        GString *stringue = NULL;
+        guchar *str = NULL,
+                *result = NULL;
+
+        g_return_val_if_fail (a_this, NULL);
+
+        stringue = g_string_new (NULL);
+
+        for (cur = a_this; cur; cur = cur->next) {
+                str = (guchar *) cr_declaration_to_string (cur, a_indent);
+                if (str) {
+                        if (a_one_decl_per_line == TRUE) {
+                                if (cur->next)
+                                        g_string_append_printf (stringue,
+                                                                "%s;\n", str);
+                                else
+                                        g_string_append (stringue,
+                                                         (const gchar *) str);
+                        } else {
+                                if (cur->next)
+                                        g_string_append_printf (stringue,
+                                                                "%s;", str);
+                                else
+                                        g_string_append (stringue,
+                                                         (const gchar *) str);
+                        }
+                        g_free (str);
+                } else
+                        break;
+        }
+        if (stringue && stringue->str) {
+                result = (guchar *) stringue->str;
+                g_string_free (stringue, FALSE);
+        }
+
+        return result;
+}
+
+/**
+ * cr_declaration_nr_props:
+ *@a_this: the current instance of #CRDeclaration.
+ *Return the number of properties in the declaration
+ */
+gint
+cr_declaration_nr_props (CRDeclaration const * a_this)
+{
+        CRDeclaration const *cur = NULL;
+        int nr = 0;
+
+        g_return_val_if_fail (a_this, -1);
+
+        for (cur = a_this; cur; cur = cur->next)
+                nr++;
+        return nr;
+}
+
+/**
+ * cr_declaration_get_from_list:
+ *@a_this: the current instance of #CRDeclaration.
+ *@itemnr: the index into the declaration list.
+ *
+ *Use an index to get a CRDeclaration from the declaration list.
+ *
+ *Returns #CRDeclaration at position itemnr, 
+ *if itemnr > number of declarations - 1,
+ *it will return NULL.
+ */
+CRDeclaration *
+cr_declaration_get_from_list (CRDeclaration * a_this, int itemnr)
+{
+        CRDeclaration *cur = NULL;
+        int nr = 0;
+
+        g_return_val_if_fail (a_this, NULL);
+
+        for (cur = a_this; cur; cur = cur->next)
+                if (nr++ == itemnr)
+                        return cur;
+        return NULL;
+}
+
+/**
+ * cr_declaration_get_by_prop_name:
+ *@a_this: the current instance of #CRDeclaration.
+ *@a_prop: the property name to search for.
+ *
+ *Use property name to get a CRDeclaration from the declaration list.
+ *Returns #CRDeclaration with property name a_prop, or NULL if not found.
+ */
+CRDeclaration *
+cr_declaration_get_by_prop_name (CRDeclaration * a_this,
+                                 const guchar * a_prop)
+{
+        CRDeclaration *cur = NULL;
+
+        g_return_val_if_fail (a_this, NULL);
+        g_return_val_if_fail (a_prop, NULL);
+
+        for (cur = a_this; cur; cur = cur->next) {
+		if (cur->property 
+		    && cur->property->stryng
+		    && cur->property->stryng->str) {
+			if (!strcmp (cur->property->stryng->str, 
+				     (const char *) a_prop)) {
+				return cur;
+			}
+		}
+	}
+        return NULL;
+}
+
+/**
+ * cr_declaration_ref:
+ *@a_this: the current instance of #CRDeclaration.
+ *
+ *Increases the ref count of the current instance of #CRDeclaration.
+ */
+void
+cr_declaration_ref (CRDeclaration * a_this)
+{
+        g_return_if_fail (a_this);
+
+        a_this->ref_count++;
+}
+
+/**
+ * cr_declaration_unref:
+ *@a_this: the current instance of #CRDeclaration.
+ *
+ *Decrements the ref count of the current instance of #CRDeclaration.
+ *If the ref count reaches zero, the current instance of #CRDeclaration
+ *if destroyed.
+ *Returns TRUE if @a_this was destroyed (ref count reached zero),
+ *FALSE otherwise.
+ */
+gboolean
+cr_declaration_unref (CRDeclaration * a_this)
+{
+        g_return_val_if_fail (a_this, FALSE);
+
+        if (a_this->ref_count) {
+                a_this->ref_count--;
+        }
+
+        if (a_this->ref_count == 0) {
+                cr_declaration_destroy (a_this);
+                return TRUE;
+        }
+        return FALSE;
+}
+
+/**
+ * cr_declaration_destroy:
+ *@a_this: the current instance of #CRDeclaration.
+ *
+ *Destructor of the declaration list.
+ */
+void
+cr_declaration_destroy (CRDeclaration * a_this)
+{
+        CRDeclaration *cur = NULL;
+
+        g_return_if_fail (a_this);
+
+        /*
+         * Go to the last element of the list.
+         */
+        for (cur = a_this; cur->next; cur = cur->next)
+                g_assert (cur->next->prev == cur);
+
+        /*
+         * Walk backward the list and free each "next" element.
+         * Meanwhile, free each property/value pair contained in the list.
+         */
+        for (; cur; cur = cur->prev) {
+                g_free (cur->next);
+                cur->next = NULL;
+
+                if (cur->property) {
+                        cr_string_destroy (cur->property);
+                        cur->property = NULL;
+                }
+
+                if (cur->value) {
+                        cr_term_destroy (cur->value);
+                        cur->value = NULL;
+                }
+        }
+
+        g_free (a_this);
+}
diff --git a/src/st/croco/cr-declaration.h b/src/st/croco/cr-declaration.h
new file mode 100644
index 000000000..eee8be321
--- /dev/null
+++ b/src/st/croco/cr-declaration.h
@@ -0,0 +1,136 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ * 
+ * See the COPYRIGHTS file for copyright information.
+ */
+
+#ifndef __CR_DECLARATION_H__
+#define __CR_DECLARATION_H__
+
+#include <stdio.h>
+#include "cr-utils.h"
+#include "cr-term.h"
+#include "cr-parsing-location.h"
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *The declaration of the #CRDeclaration class.
+ */
+
+/*forward declaration of what is defined in cr-statement.h*/
+typedef struct _CRStatement CRStatement ;
+
+/**
+ *The abstraction of a css declaration defined by the
+ *css2 spec in chapter 4.
+ *It is actually a chained list of property/value pairs.
+ */
+typedef struct _CRDeclaration CRDeclaration ;
+struct _CRDeclaration
+{
+	/**The property.*/
+	CRString *property ;
+
+	/**The value of the property.*/
+	CRTerm *value ;
+	
+	/*the ruleset that contains this declaration*/
+	CRStatement *parent_statement ;
+
+	/*the next declaration*/
+	CRDeclaration *next ;
+
+	/*the previous one declaration*/
+	CRDeclaration *prev ;
+
+	/*does the declaration have the important keyword ?*/
+	gboolean important ;
+
+	glong ref_count ;
+
+	CRParsingLocation location ;
+	/*reserved for future usage*/	
+	gpointer rfu0 ;	
+	gpointer rfu1 ;
+	gpointer rfu2 ;
+	gpointer rfu3 ;
+} ;
+
+
+CRDeclaration * cr_declaration_new (CRStatement *a_statement,
+				    CRString *a_property, 
+				    CRTerm *a_value) ;
+
+
+CRDeclaration * cr_declaration_parse_from_buf (CRStatement *a_statement,
+					       const guchar *a_str,
+					       enum CREncoding a_enc) ;
+
+CRDeclaration * cr_declaration_parse_list_from_buf (const guchar *a_str, 
+						    enum CREncoding a_enc) ;
+
+CRDeclaration * cr_declaration_append (CRDeclaration *a_this, 
+				       CRDeclaration *a_new) ;
+
+CRDeclaration * cr_declaration_append2 (CRDeclaration *a_this, 
+					CRString *a_prop,
+					CRTerm *a_value) ;
+
+CRDeclaration * cr_declaration_prepend (CRDeclaration *a_this, 
+					CRDeclaration *a_new) ;
+
+CRDeclaration * cr_declaration_unlink (CRDeclaration * a_decl) ;
+
+void
+cr_declaration_dump (CRDeclaration const *a_this,
+		     FILE *a_fp, glong a_indent,
+		     gboolean a_one_per_line) ;
+
+void cr_declaration_dump_one (CRDeclaration const *a_this,
+			      FILE *a_fp, glong a_indent) ;
+
+gint cr_declaration_nr_props (CRDeclaration const *a_this) ;
+
+CRDeclaration * cr_declaration_get_from_list (CRDeclaration *a_this, 
+					      int itemnr) ;
+
+CRDeclaration * cr_declaration_get_by_prop_name (CRDeclaration *a_this, 
+						 const guchar *a_str) ;
+
+gchar * cr_declaration_to_string (CRDeclaration const *a_this,
+				  gulong a_indent) ;
+
+guchar * cr_declaration_list_to_string (CRDeclaration const *a_this,
+					gulong a_indent) ;
+
+guchar * cr_declaration_list_to_string2 (CRDeclaration const *a_this,
+					 gulong a_indent,
+					 gboolean a_one_decl_per_line) ;
+
+void  cr_declaration_ref (CRDeclaration *a_this) ;
+
+gboolean cr_declaration_unref (CRDeclaration *a_this) ;
+
+void cr_declaration_destroy (CRDeclaration *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_DECLARATION_H__*/
diff --git a/src/st/croco/cr-doc-handler.c b/src/st/croco/cr-doc-handler.c
new file mode 100644
index 000000000..bbb158298
--- /dev/null
+++ b/src/st/croco/cr-doc-handler.c
@@ -0,0 +1,276 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ * 
+ * See COPRYRIGHTS file for copyright information.
+ */
+
+#include <string.h>
+#include "cr-doc-handler.h"
+#include "cr-parser.h"
+
+/**
+ *@CRDocHandler:
+ *
+ *The definition of the CRDocHandler class.
+ *Contains methods to instantiate, destroy,
+ *and initialyze instances of #CRDocHandler
+ *to custom values.
+ */
+
+#define PRIVATE(obj) (obj)->priv
+
+struct _CRDocHandlerPriv {
+	/**
+	 *This pointer is to hold an application parsing context.
+	 *For example, it used by the Object Model parser to 
+	 *store it parsing context. #CRParser does not touch it, but
+	 *#CROMParser does. #CROMParser allocates this pointer at
+	 *the beginning of the css document, and frees it at the end
+	 *of the document.
+	 */
+        gpointer context;
+
+	/**
+	 *The place where #CROMParser puts the result of its parsing, if
+	 *any.
+	 */
+        gpointer result;
+	/**
+	 *a pointer to the parser used to parse
+	 *the current document.
+	 */
+	CRParser *parser ;
+};
+
+/**
+ * cr_doc_handler_new:
+ *Constructor of #CRDocHandler.
+ *
+ *Returns the newly built instance of
+ *#CRDocHandler
+ *
+ */
+CRDocHandler *
+cr_doc_handler_new (void)
+{
+        CRDocHandler *result = NULL;
+
+        result = g_try_malloc (sizeof (CRDocHandler));
+
+        g_return_val_if_fail (result, NULL);
+
+        memset (result, 0, sizeof (CRDocHandler));
+        result->ref_count++;
+
+        result->priv = g_try_malloc (sizeof (CRDocHandlerPriv));
+        if (!result->priv) {
+                cr_utils_trace_info ("Out of memory exception");
+                g_free (result);
+                return NULL;
+        }
+
+        cr_doc_handler_set_default_sac_handler (result);
+
+        return result;
+}
+
+/**
+ * cr_doc_handler_get_ctxt:
+ *@a_this: the current instance of #CRDocHandler.
+ *@a_ctxt: out parameter. The new parsing context.
+ *
+ *Gets the private parsing context associated to the document handler
+ *The private parsing context is used by libcroco only.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_doc_handler_get_ctxt (CRDocHandler const * a_this, gpointer * a_ctxt)
+{
+        g_return_val_if_fail (a_this && a_this->priv, CR_BAD_PARAM_ERROR);
+
+        *a_ctxt = a_this->priv->context;
+
+        return CR_OK;
+}
+
+/**
+ * cr_doc_handler_set_ctxt:
+ *@a_this: the current instance of #CRDocHandler
+ *@a_ctxt: a pointer to the parsing context.
+ *
+ *Sets the private parsing context.
+ *This is used by libcroco only.
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_doc_handler_set_ctxt (CRDocHandler * a_this, gpointer a_ctxt)
+{
+        g_return_val_if_fail (a_this && a_this->priv, CR_BAD_PARAM_ERROR);
+        a_this->priv->context = a_ctxt;
+        return CR_OK;
+}
+
+/**
+ * cr_doc_handler_get_result:
+ *@a_this: the current instance of #CRDocHandler
+ *@a_result: out parameter. The returned result.
+ *
+ *Gets the private parsing result.
+ *The private parsing result is used by libcroco only.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_doc_handler_get_result (CRDocHandler const * a_this, gpointer * a_result)
+{
+        g_return_val_if_fail (a_this && a_this->priv, CR_BAD_PARAM_ERROR);
+
+        *a_result = a_this->priv->result;
+
+        return CR_OK;
+}
+
+/**
+ * cr_doc_handler_set_result:
+ *@a_this: the current instance of #CRDocHandler
+ *@a_result: the new result.
+ *
+ *Sets the private parsing context.
+ *This is used by libcroco only.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_doc_handler_set_result (CRDocHandler * a_this, gpointer a_result)
+{
+        g_return_val_if_fail (a_this && a_this->priv, CR_BAD_PARAM_ERROR);
+        a_this->priv->result = a_result;
+        return CR_OK;
+}
+
+/**
+ *cr_doc_handler_set_default_sac_handler:
+ *@a_this: a pointer to the current instance of #CRDocHandler.
+ *
+ *Sets the sac handlers contained in the current
+ *instance of DocHandler to the default handlers.
+ *For the time being the default handlers are
+ *test handlers. This is expected to change in a
+ *near future, when the libcroco gets a bit debugged.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_doc_handler_set_default_sac_handler (CRDocHandler * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        a_this->start_document = NULL;
+        a_this->end_document = NULL;
+        a_this->import_style = NULL;
+        a_this->namespace_declaration = NULL;
+        a_this->comment = NULL;
+        a_this->start_selector = NULL;
+        a_this->end_selector = NULL;
+        a_this->property = NULL;
+        a_this->start_font_face = NULL;
+        a_this->end_font_face = NULL;
+        a_this->start_media = NULL;
+        a_this->end_media = NULL;
+        a_this->start_page = NULL;
+        a_this->end_page = NULL;
+        a_this->ignorable_at_rule = NULL;
+        a_this->error = NULL;
+        a_this->unrecoverable_error = NULL;
+        return CR_OK;
+}
+
+/**
+ * cr_doc_handler_ref:
+ *@a_this: the current instance of #CRDocHandler.
+ */
+void
+cr_doc_handler_ref (CRDocHandler * a_this)
+{
+        g_return_if_fail (a_this);
+
+        a_this->ref_count++;
+}
+
+/**
+ * cr_doc_handler_unref:
+ *@a_this: the currrent instance of #CRDocHandler.
+ *
+ *Decreases the ref count of the current instance of #CRDocHandler.
+ *If the ref count reaches '0' then, destroys the instance.
+ *
+ *Returns TRUE if the instance as been destroyed, FALSE otherwise.
+ */
+gboolean
+cr_doc_handler_unref (CRDocHandler * a_this)
+{
+        g_return_val_if_fail (a_this, FALSE);
+
+        if (a_this->ref_count > 0) {
+                a_this->ref_count--;
+        }
+
+        if (a_this->ref_count == 0) {
+                cr_doc_handler_destroy (a_this);
+                return TRUE;
+        }
+        return FALSE ;
+}
+
+/**
+ * cr_doc_handler_destroy:
+ *@a_this: the instance of #CRDocHandler to
+ *destroy.
+ *
+ *The destructor of the #CRDocHandler class.
+ */
+void
+cr_doc_handler_destroy (CRDocHandler * a_this)
+{
+        g_return_if_fail (a_this);
+
+        if (a_this->priv) {
+                g_free (a_this->priv);
+                a_this->priv = NULL;
+        }
+        g_free (a_this);
+}
+
+/**
+ * cr_doc_handler_associate_a_parser:
+ *Associates a parser to the current document handler
+ *
+ *@a_this: the current instance of document handler.
+ *@a_parser: the parser to associate.
+ */
+void
+cr_doc_handler_associate_a_parser (CRDocHandler *a_this,
+				   gpointer a_parser)
+{
+	g_return_if_fail (a_this && PRIVATE (a_this) 
+			  && a_parser) ;
+
+	PRIVATE (a_this)->parser = a_parser ;
+}
diff --git a/src/st/croco/cr-doc-handler.h b/src/st/croco/cr-doc-handler.h
new file mode 100644
index 000000000..d12673f31
--- /dev/null
+++ b/src/st/croco/cr-doc-handler.h
@@ -0,0 +1,298 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * See the COPYRIGHTS file for copyright information.
+ */
+
+#ifndef __CR_DOC_HANDLER_H__
+#define __CR_DOC_HANDLER_H__
+
+/**
+ *@file
+ *The declaration of the #CRDocumentHandler class.
+ *This class is actually the parsing events handler.
+ */
+
+#include <glib.h>
+#include "cr-utils.h"
+#include "cr-input.h"
+#include "cr-stylesheet.h"
+
+G_BEGIN_DECLS
+
+
+typedef struct _CRDocHandler CRDocHandler ;
+
+struct _CRDocHandlerPriv ;
+typedef struct _CRDocHandlerPriv CRDocHandlerPriv ;
+
+
+/**
+ *The SAC document handler.
+ *An instance of this class is to
+ *be passed to a parser. Then, during the parsing
+ *the parser calls the convenient function pointer
+ *whenever a particular event (a css construction) occurs.
+ */
+struct _CRDocHandler
+{
+	CRDocHandlerPriv *priv ;
+
+	/**
+	 *This pointer is to be used by the application for
+	 *it custom needs. It is there to extend the doc handler.
+	 */
+	gpointer app_data ;
+
+	/**
+	 *Is called at the beginning of the parsing of the document.
+	 *@param a_this a pointer to the current instance of
+	 *#CRDocHandler.
+	 */
+	void (*start_document) (CRDocHandler *a_this) ;
+
+	/**
+	 *Is called to notify the end of the parsing of the document.
+	 *@param a_this a pointer to the current instance of
+	 *#CRDocHandler.
+	 */
+	void (*end_document) (CRDocHandler *a_this) ;
+
+	/**
+	 *Is called to notify an at charset rule.
+	 *@param a_this the document handler.
+	 *@param a_charset the declared charset.
+	 */
+	void (*charset) (CRDocHandler *a_this, 
+			 CRString *a_charset,
+			 CRParsingLocation *a_charset_sym_location) ;
+
+	/**
+	 *Is called to notify an import statement in 
+	 *the stylesheet.
+	 *@param a_this the current instance of #CRDocHandler.
+	 *@param a_media_list a doubly linked list of GString objects.
+	 *Each GString object contains a string which is the
+	 *destination media for style information.
+	 *@param a_uri the uri of the imported style sheet.
+	 *@param a_uri_default_ns the default namespace of URI
+	 *@param a_location the parsing location of the '\@import' 
+	 *keyword.
+	 *of the imported style sheet.
+	 */
+	void (*import_style) (CRDocHandler *a_this,
+			      GList *a_media_list,
+			      CRString *a_uri,
+			      CRString *a_uri_default_ns,
+			      CRParsingLocation *a_location) ;
+
+	void (*import_style_result) (CRDocHandler *a_this,
+				     GList *a_media_list,
+				     CRString *a_uri,
+				     CRString *a_uri_default_ns,
+				     CRStyleSheet *a_sheet) ;
+
+	/**
+	 *Is called to notify a namespace declaration.
+	 *Not used yet.
+	 *@param a_this the current instance of #CRDocHandler.
+	 *@param a_prefix the prefix of the namespace.
+	 *@param a_uri the uri of the namespace.
+	 *@param a_location the location of the "@namespace" keyword.
+	 */
+	void (*namespace_declaration) (CRDocHandler *a_this,
+				       CRString *a_prefix,
+				       CRString *a_uri,
+				       CRParsingLocation *a_location) ;
+		
+	/**
+	 *Is called to notify a comment.
+	 *@param a_this a pointer to the current instance
+	 *of #CRDocHandler.
+	 *@param a_comment the comment.
+	 */
+	void (*comment) (CRDocHandler *a_this,
+			 CRString *a_comment) ;
+
+	/**
+	 *Is called to notify the beginning of a rule
+	 *statement.
+	 *@param a_this the current instance of #CRDocHandler.
+	 *@param a_selector_list the list of selectors that precedes
+	 *the rule declarations.
+	 */
+	void (*start_selector) (CRDocHandler * a_this,
+				CRSelector *a_selector_list) ;
+
+	/**
+	 *Is called to notify the end of a rule statement.
+	 *@param a_this the current instance of #CRDocHandler.
+	 *@param a_selector_list the list of selectors that precedes
+	 *the rule declarations. This pointer is the same as
+	 *the one passed to start_selector() ;
+	 */
+	void (*end_selector) (CRDocHandler *a_this,
+			      CRSelector *a_selector_list) ;
+
+
+	/**
+	 *Is called to notify a declaration.
+	 *@param a_this a pointer to the current instance
+	 *of #CRDocHandler.
+	 *@param a_name the name of the parsed property.
+	 *@param a_expression a css expression that represents
+	 *the value of the property. A css expression is
+	 *actually a linked list of 'terms'. Each term can
+	 *be linked to other using operators.
+	 *
+	 */
+	void (*property) (CRDocHandler *a_this,
+			  CRString *a_name,
+			  CRTerm *a_expression,
+			  gboolean a_is_important) ;
+	/**
+	 *Is called to notify the start of a font face statement.
+	 *The parser invokes this method at the beginning of every
+	 *font face statement in the style sheet. There will
+	 *be a corresponding end_font_face () event for every
+	 *start_font_face () event.
+	 *
+	 *@param a_this a pointer to the current instance of
+	 *#CRDocHandler.
+	 *@param a_location the parsing location of the "\@font-face"
+	 *keyword.
+	 */
+	void (*start_font_face) (CRDocHandler *a_this,
+				 CRParsingLocation *a_location) ;
+
+	/**
+	 *Is called to notify the end of a font face statement.
+	 *@param a_this a pointer to the current instance of
+	 *#CRDocHandler.
+	 */
+	void (*end_font_face) (CRDocHandler *a_this) ;
+
+
+	/**
+	 *Is called to notify the beginning of a media statement.
+	 *The parser will invoke this method at the beginning of
+	 *every media statement in the style sheet. There will be
+	 *a corresponding end_media() event for every start_media()
+	 *event.
+	 *@param a_this a pointer to the current instance of 
+	 *#CRDocHandler.
+	 *@param a_media_list a double linked list of 
+	 #CRString * objects.
+	 *Each CRString objects is actually a destination media for
+	 *the style information.
+	 */
+	void (*start_media) (CRDocHandler *a_this,
+			     GList *a_media_list,
+			     CRParsingLocation *a_location) ;
+
+	/**
+	 *Is called to notify the end of a media statement.
+	 *@param a_this a pointer to the current instance
+	 *of #CRDocHandler.
+	 *@param a_media_list a double linked list of GString * objects.
+	 *Each GString objects is actually a destination media for
+	 *the style information.
+	 */
+	void (*end_media) (CRDocHandler *a_this,
+			   GList *a_media_list) ;
+
+	/**
+	 *Is called to notify the beginning of a page statement.
+	 *The parser invokes this function at the beginning of
+	 *every page statement in the style sheet. There will be
+	 *a corresponding end_page() event for every single 
+	 *start_page() event.
+	 *@param a_this a pointer to the current instance of
+	 *#CRDocHandler.
+	 *@param a_name the name of the page (if any, null otherwise).
+	 *@param a_pseudo_page the pseudo page (if any, null otherwise).
+	 *@param a_location the parsing location of the "\@page" keyword.
+	 */
+	void (*start_page) (CRDocHandler *a_this,
+			    CRString *a_name, 
+			    CRString *a_pseudo_page,
+			    CRParsingLocation *a_location) ;
+
+	/**
+	 *Is called to notify the end of a page statement.
+	 *@param a_this a pointer to the current instance of
+	 *#CRDocHandler.
+	 *@param a_name the name of the page (if any, null otherwise).
+	 *@param a_pseudo_page the pseudo page (if any, null otherwise).
+	 */
+	void (*end_page) (CRDocHandler *a_this,
+			  CRString *a_name,
+			  CRString *pseudo_page) ;
+		
+	/**
+	 *Is Called to notify an unknown at-rule not supported
+	 *by this parser.
+	 */
+	void (*ignorable_at_rule) (CRDocHandler *a_this,
+				   CRString *a_name) ;
+
+	/**
+	 *Is called to notify a parsing error. After this error
+	 *the application must ignore the rule being parsed, if
+	 *any. After completion of this callback, 
+	 *the parser will then try to resume the parsing,
+	 *ignoring the current error.
+	 */
+	void (*error) (CRDocHandler *a_this) ;
+
+	/**
+	 *Is called to notify an unrecoverable parsing error.
+	 *This is the place to put emergency routines that free allocated
+	 *resources.
+	 */
+	void (*unrecoverable_error) (CRDocHandler *a_this) ;
+
+	gboolean resolve_import ;
+	gulong ref_count ;
+} ;
+
+CRDocHandler * cr_doc_handler_new (void) ;
+
+enum CRStatus cr_doc_handler_set_result (CRDocHandler *a_this, gpointer a_result) ;
+
+enum CRStatus cr_doc_handler_get_result (CRDocHandler const *a_this, gpointer * a_result) ;
+
+enum CRStatus cr_doc_handler_set_ctxt (CRDocHandler *a_this, gpointer a_ctxt) ;
+
+enum CRStatus cr_doc_handler_get_ctxt (CRDocHandler const *a_this, gpointer * a_ctxt) ;
+
+enum CRStatus cr_doc_handler_set_default_sac_handler (CRDocHandler *a_this) ;
+
+void cr_doc_handler_associate_a_parser (CRDocHandler *a_this,
+					gpointer a_parser) ;
+
+void cr_doc_handler_ref (CRDocHandler *a_this) ;
+
+gboolean cr_doc_handler_unref (CRDocHandler *a_this) ;
+
+void cr_doc_handler_destroy (CRDocHandler *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_DOC_HANDLER_H__*/
diff --git a/src/st/croco/cr-enc-handler.c b/src/st/croco/cr-enc-handler.c
new file mode 100644
index 000000000..a7c4269ad
--- /dev/null
+++ b/src/st/croco/cr-enc-handler.c
@@ -0,0 +1,184 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * Copyright (C) 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*
+ *$Id$
+ */
+
+/**
+ *@file
+ *The definition of the #CREncHandler class.
+ */
+
+#include "cr-enc-handler.h"
+#include "cr-utils.h"
+
+#include <string.h>
+
+struct CREncAlias {
+        const gchar *name;
+        enum CREncoding encoding;
+};
+
+static struct CREncAlias gv_default_aliases[] = {
+        {"UTF-8", CR_UTF_8},
+        {"UTF_8", CR_UTF_8},
+        {"UTF8", CR_UTF_8},
+        {"UTF-16", CR_UTF_16},
+        {"UTF_16", CR_UTF_16},
+        {"UTF16", CR_UTF_16},
+        {"UCS1", CR_UCS_1},
+        {"UCS-1", CR_UCS_1},
+        {"UCS_1", CR_UCS_1},
+        {"ISO-8859-1", CR_UCS_1},
+        {"ISO_8859-1", CR_UCS_1},
+        {"UCS-1", CR_UCS_1},
+        {"UCS_1", CR_UCS_1},
+        {"UCS4", CR_UCS_4},
+        {"UCS-4", CR_UCS_4},
+        {"UCS_4", CR_UCS_4},
+        {"ASCII", CR_ASCII},
+        {0, 0}
+};
+
+static CREncHandler gv_default_enc_handlers[] = {
+        {CR_UCS_1, cr_utils_ucs1_to_utf8, cr_utils_utf8_to_ucs1,
+         cr_utils_ucs1_str_len_as_utf8, cr_utils_utf8_str_len_as_ucs1},
+
+        {CR_ISO_8859_1, cr_utils_ucs1_to_utf8, cr_utils_utf8_to_ucs1,
+         cr_utils_ucs1_str_len_as_utf8, cr_utils_utf8_str_len_as_ucs1},
+
+        {CR_ASCII, cr_utils_ucs1_to_utf8, cr_utils_utf8_to_ucs1,
+         cr_utils_ucs1_str_len_as_utf8, cr_utils_utf8_str_len_as_ucs1},
+
+        {0, NULL, NULL, NULL, NULL}
+};
+
+/**
+ * cr_enc_handler_get_instance:
+ *@a_enc: the encoding of the Handler.
+ *
+ *Gets the instance of encoding handler.
+ *This function implements a singleton pattern.
+ *
+ *Returns the instance of #CREncHandler.
+ */
+CREncHandler *
+cr_enc_handler_get_instance (enum CREncoding a_enc)
+{
+        gulong i = 0;
+
+        for (i = 0; gv_default_enc_handlers[i].encoding; i++) {
+                if (gv_default_enc_handlers[i].encoding == a_enc) {
+                        return (CREncHandler *) & gv_default_enc_handlers[i];
+                }
+        }
+
+        return NULL;
+}
+
+/**
+ * cr_enc_handler_resolve_enc_alias:
+ *@a_alias_name: the encoding name.
+ *@a_enc: output param. The returned encoding type
+ *or 0 if the alias is not supported.
+ *
+ *Given an encoding name (called an alias name)
+ *the function returns the matching encoding type.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_enc_handler_resolve_enc_alias (const guchar * a_alias_name,
+                                  enum CREncoding *a_enc)
+{
+        gulong i = 0;
+        guchar *alias_name_up = NULL;
+        enum CRStatus status = CR_ENCODING_NOT_FOUND_ERROR;
+
+        g_return_val_if_fail (a_alias_name != NULL, CR_BAD_PARAM_ERROR);
+
+        alias_name_up = (guchar *) g_ascii_strup ((const gchar *) a_alias_name, -1);
+
+        for (i = 0; gv_default_aliases[i].name; i++) {
+                if (!strcmp (gv_default_aliases[i].name, (const gchar *) alias_name_up)) {
+                        *a_enc = gv_default_aliases[i].encoding;
+                        status = CR_OK;
+                        break;
+                }
+        }
+
+        return status;
+}
+
+/**
+ * cr_enc_handler_convert_input:
+ *@a_this: the current instance of #CREncHandler.
+ *@a_in: the input buffer to convert.
+ *@a_in_len: in/out parameter. The len of the input
+ *buffer to convert. After return, contains the number of
+ *bytes actually consumed.
+ *@a_out: output parameter. The converted output buffer.
+ *Must be freed by the buffer.
+ *@a_out_len: output parameter. The length of the output buffer.
+ *
+ *Converts a raw input buffer into an utf8 buffer.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_enc_handler_convert_input (CREncHandler * a_this,
+                              const guchar * a_in,
+                              gulong * a_in_len,
+                              guchar ** a_out, gulong * a_out_len)
+{
+        enum CRStatus status = CR_OK;
+
+        g_return_val_if_fail (a_this && a_in && a_in_len && a_out,
+                              CR_BAD_PARAM_ERROR);
+
+        if (a_this->decode_input == NULL)
+                return CR_OK;
+
+        if (a_this->enc_str_len_as_utf8) {
+                status = a_this->enc_str_len_as_utf8 (a_in,
+                                                      &a_in[*a_in_len - 1],
+                                                      a_out_len);
+
+                g_return_val_if_fail (status == CR_OK, status);
+        } else {
+                *a_out_len = *a_in_len;
+        }
+
+        *a_out = g_malloc0 (*a_out_len);
+
+        status = a_this->decode_input (a_in, a_in_len, *a_out, a_out_len);
+
+        if (status != CR_OK) {
+                g_free (*a_out);
+                *a_out = NULL;
+        }
+
+        g_return_val_if_fail (status == CR_OK, status);
+
+        return CR_OK;
+}
diff --git a/src/st/croco/cr-enc-handler.h b/src/st/croco/cr-enc-handler.h
new file mode 100644
index 000000000..0727764c0
--- /dev/null
+++ b/src/st/croco/cr-enc-handler.h
@@ -0,0 +1,94 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * Copyright (C) 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*
+ *$Id$
+ */
+
+/**
+ *@file:
+ *The declaration of the #CREncHandler class.
+ *
+ */
+
+#ifndef __CR_ENC_HANDLER_H__
+#define __CR_ENC_HANDLER_H__
+
+#include "cr-utils.h"
+
+G_BEGIN_DECLS
+
+
+typedef struct _CREncHandler CREncHandler ;
+
+typedef enum CRStatus (*CREncInputFunc) (const guchar * a_in,
+                                         gulong *a_in_len,
+                                         guchar *a_out,
+                                         gulong *a_out_len) ;
+
+typedef enum CRStatus (*CREncOutputFunc) (const guchar * a_in,
+                                          gulong *a_in_len,
+                                          guchar *a_out,
+                                          gulong *a_out_len) ;
+
+typedef enum CRStatus (*CREncInputStrLenAsUtf8Func) 
+(const guchar *a_in_start,
+ const guchar *a_in_end,
+ gulong *a_in_size);
+
+typedef enum CRStatus  (*CREncUtf8StrLenAsOutputFunc)
+(const guchar *a_in_start,
+ const guchar *a_in_end,
+ gulong *a_in_size) ;
+
+/**
+ *This class is responsible of the
+ *the encoding conversions stuffs in
+ *libcroco.
+ */
+
+struct _CREncHandler
+{
+        enum CREncoding encoding ;
+        CREncInputFunc decode_input ;                
+        CREncInputFunc encode_output ;
+        CREncInputStrLenAsUtf8Func enc_str_len_as_utf8 ;
+        CREncUtf8StrLenAsOutputFunc utf8_str_len_as_enc ;
+} ;
+
+CREncHandler *
+cr_enc_handler_get_instance (enum CREncoding a_enc) ;
+
+enum CRStatus
+cr_enc_handler_resolve_enc_alias (const guchar *a_alias_name, 
+                                  enum CREncoding *a_enc) ;
+
+enum CRStatus
+cr_enc_handler_convert_input (CREncHandler *a_this,
+                              const guchar *a_in,
+                              gulong *a_in_len,
+                              guchar **a_out,
+                              gulong *a_out_len) ;
+
+G_END_DECLS
+
+#endif /*__CR_ENC_HANDLER_H__*/
diff --git a/src/st/croco/cr-fonts.c b/src/st/croco/cr-fonts.c
new file mode 100644
index 000000000..3a5788cea
--- /dev/null
+++ b/src/st/croco/cr-fonts.c
@@ -0,0 +1,949 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of 
+ * the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the 
+ * GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ *See COPYRIGHTS file for copyright information
+ */
+
+#include "cr-fonts.h"
+#include <string.h>
+
+static enum CRStatus
+cr_font_family_to_string_real (CRFontFamily const * a_this,
+                               gboolean a_walk_list, GString ** a_string)
+{
+        guchar const *name = NULL;
+        enum CRStatus result = CR_OK;
+
+        if (!*a_string) {
+                *a_string = g_string_new (NULL);
+                g_return_val_if_fail (*a_string,
+                                      CR_INSTANCIATION_FAILED_ERROR);
+        }
+
+        if (!a_this) {
+                g_string_append (*a_string, "NULL");
+                return CR_OK;
+        }
+
+        switch (a_this->type) {
+        case FONT_FAMILY_SANS_SERIF:
+                name = (guchar const *) "sans-serif";
+                break;
+
+        case FONT_FAMILY_SERIF:
+                name = (guchar const *) "sans-serif";
+                break;
+
+        case FONT_FAMILY_CURSIVE:
+                name = (guchar const *) "cursive";
+                break;
+
+        case FONT_FAMILY_FANTASY:
+                name = (guchar const *) "fantasy";
+                break;
+
+        case FONT_FAMILY_MONOSPACE:
+                name = (guchar const *) "monospace";
+                break;
+
+        case FONT_FAMILY_NON_GENERIC:
+                name = (guchar const *) a_this->name;
+                break;
+
+        default:
+                name = NULL;
+                break;
+        }
+
+        if (name) {
+                if (a_this->prev) {
+                        g_string_append_printf (*a_string, ", %s", name);
+                } else {
+                        g_string_append (*a_string, (const gchar *) name);
+                }
+        }
+        if (a_walk_list == TRUE && a_this->next) {
+                result = cr_font_family_to_string_real (a_this->next,
+                                                        TRUE, a_string);
+        }
+        return result;
+}
+
+static const gchar *
+cr_predefined_absolute_font_size_to_string (enum CRPredefinedAbsoluteFontSize
+                                            a_code)
+{
+        gchar const *str = NULL;
+
+        switch (a_code) {
+        case FONT_SIZE_XX_SMALL:
+                str = "xx-small";
+                break;
+        case FONT_SIZE_X_SMALL:
+                str = "x-small";
+                break;
+        case FONT_SIZE_SMALL:
+                str = "small";
+                break;
+        case FONT_SIZE_MEDIUM:
+                str = "medium";
+                break;
+        case FONT_SIZE_LARGE:
+                str = "large";
+                break;
+        case FONT_SIZE_X_LARGE:
+                str = "x-large";
+                break;
+        case FONT_SIZE_XX_LARGE:
+                str = "xx-large";
+                break;
+        default:
+                str = "unknown absolute font size value";
+        }
+        return str;
+}
+
+static const gchar *
+cr_relative_font_size_to_string (enum CRRelativeFontSize a_code)
+{
+        gchar const *str = NULL;
+
+        switch (a_code) {
+        case FONT_SIZE_LARGER:
+                str = "larger";
+                break;
+        case FONT_SIZE_SMALLER:
+                str = "smaller";
+                break;
+        default:
+                str = "unknown relative font size value";
+                break;
+        }
+        return str;
+}
+
+/**
+ * cr_font_family_new:
+ * @a_type: the type of font family to create.
+ * @a_name: the name of the font family.
+ *
+ * create a font family.
+ *
+ * Returns the newly built font family.
+ */
+CRFontFamily *
+cr_font_family_new (enum CRFontFamilyType a_type, guchar * a_name)
+{
+        CRFontFamily *result = NULL;
+
+        result = g_try_malloc (sizeof (CRFontFamily));
+
+        if (!result) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+
+        memset (result, 0, sizeof (CRFontFamily));
+        result->type = a_type;
+
+        cr_font_family_set_name (result, a_name);
+
+        return result;
+}
+
+/**
+ * cr_font_family_to_string:
+ * @a_this: the current instance of #CRFontFamily.
+ * @a_walk_font_family_list: wether the serialize the entire list.
+ *
+ * Returns the seriliazed font family. The caller has to free it using
+ * g_free().
+ */
+guchar *
+cr_font_family_to_string (CRFontFamily const * a_this,
+                          gboolean a_walk_font_family_list)
+{
+        enum CRStatus status = CR_OK;
+        guchar *result = NULL;
+        GString *stringue = NULL;
+
+        if (!a_this) {
+                result = (guchar *) g_strdup ("NULL");
+                g_return_val_if_fail (result, NULL);
+                return result;
+        }
+        status = cr_font_family_to_string_real (a_this,
+                                                a_walk_font_family_list,
+                                                &stringue);
+
+        if (status == CR_OK && stringue) {
+                result = (guchar *) stringue->str;
+                g_string_free (stringue, FALSE);
+                stringue = NULL;
+
+        } else {
+                if (stringue) {
+                        g_string_free (stringue, TRUE);
+                        stringue = NULL;
+                }
+        }
+
+        return result;
+}
+
+/**
+ * cr_font_family_set_name:
+ * @a_this: the current instance of #CRFontFamily.
+ * @a_name: the new name
+ *
+ * Returns CR_OK upon sucessful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_font_family_set_name (CRFontFamily * a_this, guchar * a_name)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        /*
+         *only non generic font families can have a name
+         */
+
+        if (a_this->type != FONT_FAMILY_NON_GENERIC) {
+                return CR_BAD_PARAM_ERROR;
+        }
+
+        if (a_this->name) {
+                g_free (a_this->name);
+                a_this->name = NULL;
+        }
+
+        a_this->name = a_name;
+        return CR_OK;
+}
+
+/**
+ * cr_font_family_append:
+ * @a_this: the current instance of #CRFontFamily.
+ * @a_family_to_append: the font family to append to the list
+ *
+ * Returns the new font family list.
+ */
+CRFontFamily *
+cr_font_family_append (CRFontFamily * a_this,
+                       CRFontFamily * a_family_to_append)
+{
+        CRFontFamily *cur_ff = NULL;
+
+        g_return_val_if_fail (a_family_to_append, NULL);
+
+        if (!a_this)
+                return a_family_to_append;
+
+        for (cur_ff = a_this; cur_ff && cur_ff->next; cur_ff = cur_ff->next) ;
+
+        cur_ff->next = a_family_to_append;
+        a_family_to_append->prev = cur_ff;
+
+        return a_this;
+
+}
+
+/**
+ * cr_font_family_prepend:
+ * @a_this: the current instance #CRFontFamily.
+ * @a_family_to_prepend: the font family to prepend to the list.
+ *
+ * Returns the font family list.
+ */
+CRFontFamily *
+cr_font_family_prepend (CRFontFamily * a_this,
+                        CRFontFamily * a_family_to_prepend)
+{
+        g_return_val_if_fail (a_this && a_family_to_prepend, NULL);
+
+        if (!a_this)
+                return a_family_to_prepend;
+
+        a_family_to_prepend->next = a_this;
+        a_this->prev = a_family_to_prepend;
+
+        return a_family_to_prepend;
+}
+
+/**
+ * cr_font_family_destroy:
+ * @a_this: the current instance of #CRFontFamily.
+ *
+ * Returns CR_OK upon sucessful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_font_family_destroy (CRFontFamily * a_this)
+{
+        CRFontFamily *cur_ff = NULL;
+
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        for (cur_ff = a_this; cur_ff && cur_ff->next; cur_ff = cur_ff->next) ;
+
+        for (; cur_ff; cur_ff = cur_ff->prev) {
+                if (a_this->name) {
+                        g_free (a_this->name);
+                        a_this->name = NULL;
+                }
+
+                if (cur_ff->next) {
+                        g_free (cur_ff->next);
+
+                }
+
+                if (cur_ff->prev == NULL) {
+                        g_free (a_this);
+                }
+        }
+
+        return CR_OK;
+}
+
+/***************************************************
+ *'font-size' manipulation functions definitions
+ ***************************************************/
+
+/**
+ * cr_font_size_new:
+ *
+ * Returns the newly created font size.
+ */
+CRFontSize *
+cr_font_size_new (void)
+{
+        CRFontSize *result = NULL;
+
+        result = g_try_malloc (sizeof (CRFontSize));
+        if (!result) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+        memset (result, 0, sizeof (CRFontSize));
+
+        return result;
+}
+
+/**
+ * cr_font_size_clear:
+ * @a_this: the current instance of #CRFontSize
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_font_size_clear (CRFontSize * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        switch (a_this->type) {
+        case PREDEFINED_ABSOLUTE_FONT_SIZE:
+        case RELATIVE_FONT_SIZE:
+        case INHERITED_FONT_SIZE:
+                memset (a_this, 0, sizeof (CRFontSize));
+                break;
+
+        case ABSOLUTE_FONT_SIZE:
+                memset (a_this, 0, sizeof (CRFontSize));
+                break;
+
+        default:
+                return CR_UNKNOWN_TYPE_ERROR;
+        }
+
+        return CR_OK;
+}
+
+/**
+ * cr_font_size_copy:
+ * @a_dst: the destination #CRFontSize (where to copy to).
+ * @a_src: the source #CRFontSize (where to copy from).
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_font_size_copy (CRFontSize * a_dst, CRFontSize const * a_src)
+{
+        g_return_val_if_fail (a_dst && a_src, CR_BAD_PARAM_ERROR);
+
+        switch (a_src->type) {
+        case PREDEFINED_ABSOLUTE_FONT_SIZE:
+        case RELATIVE_FONT_SIZE:
+        case INHERITED_FONT_SIZE:
+                cr_font_size_clear (a_dst);
+                memcpy (a_dst, a_src, sizeof (CRFontSize));
+                break;
+
+        case ABSOLUTE_FONT_SIZE:
+                cr_font_size_clear (a_dst);
+                cr_num_copy (&a_dst->value.absolute,
+                             &a_src->value.absolute);
+                a_dst->type = a_src->type;
+                break;
+
+        default:
+                return CR_UNKNOWN_TYPE_ERROR;
+        }
+        return CR_OK;
+}
+
+/**
+ * cr_font_size_set_predefined_absolute_font_size:
+ * @a_this: the current instance of #CRFontSize.
+ * @a_predefined: what to set.
+ *
+ * Returns CR_OK upon sucessful completion, an error code otherwise.
+ */
+enum CRStatus 
+cr_font_size_set_predefined_absolute_font_size (CRFontSize *a_this, 
+                                                enum CRPredefinedAbsoluteFontSize a_predefined)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+        g_return_val_if_fail (a_predefined >= FONT_SIZE_XX_SMALL
+                              && a_predefined < NB_PREDEFINED_ABSOLUTE_FONT_SIZES,
+                              CR_BAD_PARAM_ERROR) ;
+
+        a_this->type = PREDEFINED_ABSOLUTE_FONT_SIZE ;
+        a_this->value.predefined = a_predefined ;
+
+        return CR_OK ;
+}
+
+/**
+ * cr_font_size_set_relative_font_size:
+ * @a_this: the current instance of #CRFontSize
+ * @a_relative: the new relative font size
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus 
+cr_font_size_set_relative_font_size (CRFontSize *a_this,
+                                     enum CRRelativeFontSize a_relative)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+        g_return_val_if_fail (a_relative >= FONT_SIZE_LARGER
+                              && a_relative < NB_RELATIVE_FONT_SIZE,
+                              CR_BAD_PARAM_ERROR) ;
+        
+        a_this->type = RELATIVE_FONT_SIZE ;
+        a_this->value.relative = a_relative ;
+        return CR_OK ;
+}
+
+/**
+ * cr_font_size_set_absolute_font_size:
+ * @a_this: the current instance of #CRFontSize
+ * @a_num_type: the type of number to set.
+ * @a_value: the actual value to set.
+ *
+ * Returns CR_OK upon succesful completion, an error code otherwise.
+ */
+enum CRStatus 
+cr_font_size_set_absolute_font_size (CRFontSize *a_this,
+                                     enum CRNumType a_num_type,
+                                     gdouble a_value)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+        g_return_val_if_fail (a_num_type >= NUM_AUTO
+                              && a_num_type < NB_NUM_TYPE,
+                              CR_BAD_PARAM_ERROR) ;
+
+        a_this->type = ABSOLUTE_FONT_SIZE ;
+        cr_num_set (&a_this->value.absolute,
+                    a_value, a_num_type) ;        
+        return CR_OK ;
+}
+
+/**
+ * cr_font_size_set_to_inherit:
+ * @a_this: the current instance of #CRFontSize 
+ *
+ * Returns CR_OK upon succesful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_font_size_set_to_inherit (CRFontSize *a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+        cr_font_size_clear (a_this) ;
+        a_this->type = INHERITED_FONT_SIZE ;
+
+        return CR_OK ;
+}
+
+/**
+ * cr_font_size_is_set_to_inherit:
+ * @a_this: the current instance of #CRFontSize.
+ *
+ * Returns TRUE if the current instance is set to 'inherit'. 
+ */
+gboolean
+cr_font_size_is_set_to_inherit (CRFontSize const *a_this)
+{
+        g_return_val_if_fail (a_this, FALSE) ;
+
+        return a_this->type == INHERITED_FONT_SIZE ;
+}
+
+/**
+ * cr_font_size_to_string:
+ * @a_this: the current instance of #CRFontSize
+ *
+ * Returns the serialized form of #CRFontSize. The returned string
+ * has to bee freed using g_free().
+ */
+gchar *
+cr_font_size_to_string (CRFontSize const * a_this)
+{
+        gchar *str = NULL;
+
+        if (!a_this) {
+                str = g_strdup ("NULL");
+                g_return_val_if_fail (str, NULL);
+                return str;
+        }
+        switch (a_this->type) {
+        case PREDEFINED_ABSOLUTE_FONT_SIZE:
+                str = g_strdup (cr_predefined_absolute_font_size_to_string
+                                (a_this->value.predefined));
+                break;
+        case ABSOLUTE_FONT_SIZE:
+                str = (gchar *) cr_num_to_string (&a_this->value.absolute);
+                break;
+        case RELATIVE_FONT_SIZE:
+                str = g_strdup (cr_relative_font_size_to_string
+                                (a_this->value.relative));
+                break;
+        case INHERITED_FONT_SIZE:
+                str = g_strdup ("inherit");
+                break;
+        default:
+                break;
+        }
+        return str;
+}
+
+/**
+ * cr_font_size_get_smaller_predefined:
+ * @a_font_size: the font size to consider.
+ * @a_smaller_size: out parameter. The a smaller value than @a_font_size. 
+ */
+void 
+cr_font_size_get_smaller_predefined_font_size 
+				(enum CRPredefinedAbsoluteFontSize a_font_size,
+			         enum CRPredefinedAbsoluteFontSize *a_smaller_size)
+{
+        enum CRPredefinedAbsoluteFontSize result = FONT_SIZE_MEDIUM ;
+
+        g_return_if_fail (a_smaller_size) ;
+        g_return_if_fail (a_font_size < NB_PREDEFINED_ABSOLUTE_FONT_SIZES
+                          && a_font_size >= FONT_SIZE_XX_SMALL) ;
+
+        switch (a_font_size) {
+        case FONT_SIZE_XX_SMALL:
+                result =  FONT_SIZE_XX_SMALL ;
+                break ;
+        case FONT_SIZE_X_SMALL:
+                result =  FONT_SIZE_XX_SMALL ;
+                break ;
+        case FONT_SIZE_SMALL:
+                result =  FONT_SIZE_X_SMALL;
+                break ;
+        case FONT_SIZE_MEDIUM:
+                result =  FONT_SIZE_SMALL;
+                break ;
+        case FONT_SIZE_LARGE:
+                result =  FONT_SIZE_MEDIUM;
+                break ;
+        case FONT_SIZE_X_LARGE:
+                result =  FONT_SIZE_LARGE;
+                break ;
+        case FONT_SIZE_XX_LARGE:
+                result =  FONT_SIZE_XX_LARGE;
+                break ;
+	case FONT_SIZE_INHERIT:
+                cr_utils_trace_info ("can't return a smaller size for FONT_SIZE_INHERIT") ;                
+                result =  FONT_SIZE_MEDIUM ;
+                break ;
+        default:
+                cr_utils_trace_info ("Unknown FONT_SIZE") ;
+                result = FONT_SIZE_MEDIUM ;
+                break ;
+        }
+        *a_smaller_size = result ;
+}
+
+
+/**
+ * cr_font_size_get_larger_predefined_font_size:
+ * @a_font_size: the font size to consider.
+ * @a_larger_size: out parameter. the font size considered larger than
+ * @a_font_size.
+ *
+ */
+void 
+cr_font_size_get_larger_predefined_font_size 
+			(enum CRPredefinedAbsoluteFontSize a_font_size,
+		         enum CRPredefinedAbsoluteFontSize *a_larger_size)
+{
+        enum CRPredefinedAbsoluteFontSize result = FONT_SIZE_MEDIUM ;
+        
+        g_return_if_fail (a_larger_size) ;
+        g_return_if_fail (a_font_size >= FONT_SIZE_XX_SMALL 
+                          && a_font_size < NB_PREDEFINED_ABSOLUTE_FONT_SIZES) ;
+
+        switch (a_font_size) {
+        case FONT_SIZE_XX_SMALL:
+                result =  FONT_SIZE_X_SMALL ;
+                break ;
+        case FONT_SIZE_X_SMALL:
+                result =  FONT_SIZE_SMALL ;
+                break ;
+        case FONT_SIZE_SMALL:
+                result =  FONT_SIZE_MEDIUM;
+                break ;
+        case FONT_SIZE_MEDIUM:
+                result =  FONT_SIZE_LARGE;
+                break ;
+        case FONT_SIZE_LARGE:
+                result =  FONT_SIZE_X_LARGE;
+                break ;
+        case FONT_SIZE_X_LARGE:
+                result =  FONT_SIZE_XX_LARGE ;
+                break ;
+        case FONT_SIZE_XX_LARGE:
+                result =  FONT_SIZE_XX_LARGE;
+                break ;
+	case FONT_SIZE_INHERIT:
+                cr_utils_trace_info ("can't return a bigger size for FONT_SIZE_INHERIT") ;                
+                result =  FONT_SIZE_MEDIUM ;
+                break ;
+        default:
+                cr_utils_trace_info ("Unknown FONT_SIZE") ;
+                result = FONT_SIZE_MEDIUM ;
+                break ;
+        }
+        *a_larger_size = result ;
+}
+
+/**
+ * cr_font_size_is_predefined_absolute_font_size:
+ * @a_font_size: the font size to consider.
+ *
+ * Returns TRUE if the instance is an predefined absolute font size, FALSE
+ * otherwise.
+ */
+gboolean
+cr_font_size_is_predefined_absolute_font_size 
+				(enum CRPredefinedAbsoluteFontSize a_font_size)
+{
+        if (a_font_size >= FONT_SIZE_XX_SMALL
+            && a_font_size < NB_PREDEFINED_ABSOLUTE_FONT_SIZES) {
+                return TRUE ;
+        } else {
+                return FALSE ;
+        }
+}
+
+/**
+ * cr_font_size_adjust_to_string:
+ * @a_this: the instance of #CRFontSizeAdjust.
+ *
+ * Returns the serialized form of #CRFontSizeAdjust
+ */
+gchar *
+cr_font_size_adjust_to_string (CRFontSizeAdjust const * a_this)
+{
+        gchar *str = NULL;
+
+        if (!a_this) {
+                str = g_strdup ("NULL");
+                g_return_val_if_fail (str, NULL);
+                return str;
+        }
+
+        switch (a_this->type) {
+        case FONT_SIZE_ADJUST_NONE:
+                str = g_strdup ("none");
+                break;
+        case FONT_SIZE_ADJUST_NUMBER:
+                if (a_this->num)
+                        str = (gchar *) cr_num_to_string (a_this->num);
+                else
+                        str = g_strdup ("unknown font-size-adjust property value"); /* Should raise an error no?*/
+                break;
+        case FONT_SIZE_ADJUST_INHERIT:
+                str = g_strdup ("inherit");
+        }
+        return str;
+}
+
+/**
+ * cr_font_style_to_string:
+ * @a_code: the current instance of #CRFontStyle .
+ *
+ * Returns the serialized #CRFontStyle. The caller must free the returned
+ * string using g_free().
+ */
+const gchar *
+cr_font_style_to_string (enum CRFontStyle a_code)
+{
+        gchar *str = NULL;
+
+        switch (a_code) {
+        case FONT_STYLE_NORMAL:
+                str = (gchar *) "normal";
+                break;
+        case FONT_STYLE_ITALIC:
+                str = (gchar *) "italic";
+                break;
+        case FONT_STYLE_OBLIQUE:
+                str = (gchar *) "oblique";
+                break;
+        case FONT_STYLE_INHERIT:
+                str = (gchar *) "inherit";
+                break;
+        default:
+                str = (gchar *) "unknown font style value";
+                break;
+        }
+        return str;
+}
+
+/**
+ * cr_font_variant_to_string:
+ * @a_code: the current instance of #CRFontVariant.
+ *
+ * Returns the serialized form of #CRFontVariant. The caller has
+ * to free the returned string using g_free().
+ */
+const gchar *
+cr_font_variant_to_string (enum CRFontVariant a_code)
+{
+        gchar *str = NULL;
+
+        switch (a_code) {
+        case FONT_VARIANT_NORMAL:
+                str = (gchar *) "normal";
+                break;
+        case FONT_VARIANT_SMALL_CAPS:
+                str = (gchar *) "small-caps";
+                break;
+        case FONT_VARIANT_INHERIT:
+                str = (gchar *) "inherit";
+                break;
+        }
+        return str;
+}
+
+/**
+ * cr_font_weight_get_bolder:
+ * @a_weight: the #CRFontWeight to consider.
+ *
+ * Returns a font weight bolder than @a_weight
+ */
+enum CRFontWeight
+cr_font_weight_get_bolder (enum CRFontWeight a_weight)
+{
+        if (a_weight == FONT_WEIGHT_INHERIT) {
+                cr_utils_trace_info ("can't return a bolder weight for FONT_WEIGHT_INHERIT") ;
+                return a_weight;
+        } else if (a_weight >= FONT_WEIGHT_900) {
+                return FONT_WEIGHT_900 ;
+        } else if (a_weight < FONT_WEIGHT_NORMAL) {
+                return FONT_WEIGHT_NORMAL ;
+        } else if (a_weight == FONT_WEIGHT_BOLDER
+                   || a_weight == FONT_WEIGHT_LIGHTER) {
+                cr_utils_trace_info ("FONT_WEIGHT_BOLDER or FONT_WEIGHT_LIGHTER should not appear here") ;
+                return FONT_WEIGHT_NORMAL ;
+        } else {
+                return a_weight << 1 ;
+        }
+}
+
+/**
+ * cr_font_weight_to_string:
+ * @a_code: the font weight to consider.
+ *
+ * Returns the serialized form of #CRFontWeight.
+ */
+const gchar *
+cr_font_weight_to_string (enum CRFontWeight a_code)
+{
+        gchar *str = NULL;
+
+        switch (a_code) {
+        case FONT_WEIGHT_NORMAL:
+                str = (gchar *) "normal";
+                break;
+        case FONT_WEIGHT_BOLD:
+                str = (gchar *) "bold";
+                break;
+        case FONT_WEIGHT_BOLDER:
+                str = (gchar *) "bolder";
+                break;
+        case FONT_WEIGHT_LIGHTER:
+                str = (gchar *) "lighter";
+                break;
+        case FONT_WEIGHT_100:
+                str = (gchar *) "100";
+                break;
+        case FONT_WEIGHT_200:
+                str = (gchar *) "200";
+                break;
+        case FONT_WEIGHT_300:
+                str = (gchar *) "300";
+                break;
+        case FONT_WEIGHT_400:
+                str = (gchar *) "400";
+                break;
+        case FONT_WEIGHT_500:
+                str = (gchar *) "500";
+                break;
+        case FONT_WEIGHT_600:
+                str = (gchar *) "600";
+                break;
+        case FONT_WEIGHT_700:
+                str = (gchar *) "700";
+                break;
+        case FONT_WEIGHT_800:
+                str = (gchar *) "800";
+                break;
+        case FONT_WEIGHT_900:
+                str = (gchar *) "900";
+                break;
+        case FONT_WEIGHT_INHERIT:
+                str = (gchar *) "inherit";
+                break;
+        default:
+                str = (gchar *) "unknown font-weight property value";
+                break;
+        }
+        return str;
+}
+
+/**
+ * cr_font_stretch_to_string:
+ * @a_code: the instance of #CRFontStretch to consider.
+ *
+ * Returns the serialized form of #CRFontStretch.
+ */
+const gchar *
+cr_font_stretch_to_string (enum CRFontStretch a_code)
+{
+        gchar *str = NULL;
+
+        switch (a_code) {
+        case FONT_STRETCH_NORMAL:
+                str = (gchar *) "normal";
+                break;
+        case FONT_STRETCH_WIDER:
+                str = (gchar *) "wider";
+                break;
+        case FONT_STRETCH_NARROWER:
+                str = (gchar *) "narrower";
+                break;
+        case FONT_STRETCH_ULTRA_CONDENSED:
+                str = (gchar *) "ultra-condensed";
+                break;
+        case FONT_STRETCH_EXTRA_CONDENSED:
+                str = (gchar *) "extra-condensed";
+                break;
+        case FONT_STRETCH_CONDENSED:
+                str = (gchar *) "condensed";
+                break;
+        case FONT_STRETCH_SEMI_CONDENSED:
+                str = (gchar *) "semi-condensed";
+                break;
+        case FONT_STRETCH_SEMI_EXPANDED:
+                str = (gchar *) "semi-expanded";
+                break;
+        case FONT_STRETCH_EXPANDED:
+                str = (gchar *) "expanded";
+                break;
+        case FONT_STRETCH_EXTRA_EXPANDED:
+                str = (gchar *) "extra-expaned";
+                break;
+        case FONT_STRETCH_ULTRA_EXPANDED:
+                str = (gchar *) "ultra-expanded";
+                break;
+        case FONT_STRETCH_INHERIT:
+                str = (gchar *) "inherit";
+                break;
+        }
+        return str;
+}
+
+/**
+ * cr_font_size_destroy:
+ * @a_font_size: the font size to destroy
+ *
+ */
+void
+cr_font_size_destroy (CRFontSize * a_font_size)
+{
+        g_return_if_fail (a_font_size);
+
+        g_free (a_font_size) ;
+}
+
+/*******************************************************
+ *'font-size-adjust' manipulation function definition
+ *******************************************************/
+
+/**
+ * cr_font_size_adjust_new:
+ *
+ * Returns a newly built instance of #CRFontSizeAdjust
+ */
+CRFontSizeAdjust *
+cr_font_size_adjust_new (void)
+{
+        CRFontSizeAdjust *result = NULL;
+
+        result = g_try_malloc (sizeof (CRFontSizeAdjust));
+        if (!result) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+        memset (result, 0, sizeof (CRFontSizeAdjust));
+
+        return result;
+}
+
+/**
+ * cr_font_size_adjust_destroy:
+ * @a_this: the current instance of #CRFontSizeAdjust.
+ *
+ */
+void
+cr_font_size_adjust_destroy (CRFontSizeAdjust * a_this)
+{
+        g_return_if_fail (a_this);
+
+        if (a_this->type == FONT_SIZE_ADJUST_NUMBER && a_this->num) {
+                cr_num_destroy (a_this->num);
+                a_this->num = NULL;
+        }
+}
diff --git a/src/st/croco/cr-fonts.h b/src/st/croco/cr-fonts.h
new file mode 100644
index 000000000..9eaeeeb98
--- /dev/null
+++ b/src/st/croco/cr-fonts.h
@@ -0,0 +1,315 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of 
+ * the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the 
+ * GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#ifndef __CR_FONTS_H__
+#define __CR_FONTS_H__
+
+#include "cr-utils.h"
+#include "cr-num.h"
+
+/**
+ *@file
+ *Various type declarations about font selection related
+ *properties.
+ */
+G_BEGIN_DECLS
+
+
+enum CRFontFamilyType
+{
+	FONT_FAMILY_SANS_SERIF,
+	FONT_FAMILY_SERIF,	
+	FONT_FAMILY_CURSIVE,
+	FONT_FAMILY_FANTASY,
+	FONT_FAMILY_MONOSPACE,
+	FONT_FAMILY_NON_GENERIC,
+	FONT_FAMILY_INHERIT,
+	/**/
+	NB_FONT_FAMILIE_TYPES
+} ;
+
+typedef struct _CRFontFamily CRFontFamily ;
+
+struct _CRFontFamily
+{
+	enum CRFontFamilyType type ;
+
+	/*
+	 *The name of the font family, in case
+	 *it is non generic.
+	 *Is set only if the type is FONT_FAMILY_NON_GENERIC.
+	 */
+	guchar *name ;
+
+	CRFontFamily *next ;
+	CRFontFamily *prev ;
+} ;
+
+
+/**
+ *The different types
+ *of absolute font size.
+ *This is used by the 'font-size'
+ *property defined in css2 spec
+ *in chapter 15.2.4 .
+ *These values a indexes of 
+ *table of size so please, do not
+ *change their definition order unless
+ *you know what you are doing.
+ */
+enum CRPredefinedAbsoluteFontSize
+{
+        FONT_SIZE_XX_SMALL=0,
+        FONT_SIZE_X_SMALL,
+        FONT_SIZE_SMALL,
+        FONT_SIZE_MEDIUM,
+        FONT_SIZE_LARGE,
+        FONT_SIZE_X_LARGE,
+        FONT_SIZE_XX_LARGE,
+	FONT_SIZE_INHERIT,
+        NB_PREDEFINED_ABSOLUTE_FONT_SIZES
+} ;
+
+/**
+ *The different types
+ *of relative font size.
+ *This is used by the 'font-size'
+ *property defined in css2 spec
+ *in chapter 15.2.4 .
+ *These values a indexes of 
+ *table of size so please, do not
+ *change their definition order unless
+ *you know what you are doing.
+ */
+enum CRRelativeFontSize
+{        
+        FONT_SIZE_LARGER,
+        FONT_SIZE_SMALLER,
+        NB_RELATIVE_FONT_SIZE
+} ;
+
+/**
+ *The type of font-size property.
+ *Used to define the type of #CRFontSize .
+ *See css2 spec chapter 15.2.4 to understand.
+ */
+enum CRFontSizeType {
+        /**
+         *If the type of #CRFontSize is
+         *PREDEFINED_ABSOLUTE_FONT_SIZE,
+         *the CRFontSize::value.predefined_absolute 
+         *field will be defined.
+         */
+        PREDEFINED_ABSOLUTE_FONT_SIZE,
+        
+        /**
+         *If the type of #CRFontSize is
+         *ABSOLUTE_FONT_SIZE,
+         *the CRFontSize::value.absolute 
+         *field will be defined.
+         */
+        ABSOLUTE_FONT_SIZE,
+
+        /**
+         *If the type of #CRFontSize is
+         *RELATIVE_FONT_SIZE,
+         *the CRFontSize::value.relative
+         *field will be defined.
+         */
+        RELATIVE_FONT_SIZE,
+
+        /**
+         *If the type of #CRFontSize is
+         *INHERITED_FONT_SIZE,
+         *the None of the field of the CRFontSize::value enum
+         *will be defined.
+         */
+        INHERITED_FONT_SIZE,
+
+        NB_FONT_SIZE_TYPE
+} ;
+
+typedef struct _CRFontSize CRFontSize ;
+struct _CRFontSize {
+        enum CRFontSizeType type ;
+        union  {
+                enum CRPredefinedAbsoluteFontSize predefined ;
+                enum CRRelativeFontSize relative ;
+                CRNum absolute ;
+        } value;
+} ;
+
+enum CRFontSizeAdjustType
+{
+        FONT_SIZE_ADJUST_NONE = 0,
+        FONT_SIZE_ADJUST_NUMBER,
+        FONT_SIZE_ADJUST_INHERIT
+} ;
+typedef struct _CRFontSizeAdjust CRFontSizeAdjust ;
+struct _CRFontSizeAdjust
+{
+        enum CRFontSizeAdjustType type ;
+        CRNum *num ;
+} ;
+
+enum CRFontStyle
+{
+        FONT_STYLE_NORMAL=0,
+        FONT_STYLE_ITALIC,
+        FONT_STYLE_OBLIQUE,
+        FONT_STYLE_INHERIT
+} ;
+
+enum CRFontVariant
+{
+        FONT_VARIANT_NORMAL=0,
+        FONT_VARIANT_SMALL_CAPS,
+        FONT_VARIANT_INHERIT
+} ;
+
+enum CRFontWeight
+{
+        FONT_WEIGHT_NORMAL = 1,
+        FONT_WEIGHT_BOLD = 1<<1,
+        FONT_WEIGHT_BOLDER = 1<<2,
+        FONT_WEIGHT_LIGHTER = 1<<3,
+        FONT_WEIGHT_100 = 1<<4,
+        FONT_WEIGHT_200 = 1<<5,
+        FONT_WEIGHT_300 = 1<<6,
+        FONT_WEIGHT_400 = 1<<7,
+        FONT_WEIGHT_500 = 1<<8,
+        FONT_WEIGHT_600 = 1<<9,
+        FONT_WEIGHT_700 = 1<<10,
+        FONT_WEIGHT_800 = 1<<11,
+        FONT_WEIGHT_900 = 1<<12,
+        FONT_WEIGHT_INHERIT = 1<<13,
+        NB_FONT_WEIGHTS
+} ;
+
+enum CRFontStretch
+{
+        FONT_STRETCH_NORMAL=0,
+        FONT_STRETCH_WIDER,
+        FONT_STRETCH_NARROWER,
+        FONT_STRETCH_ULTRA_CONDENSED,
+        FONT_STRETCH_EXTRA_CONDENSED,
+        FONT_STRETCH_CONDENSED,
+        FONT_STRETCH_SEMI_CONDENSED,
+        FONT_STRETCH_SEMI_EXPANDED,
+        FONT_STRETCH_EXPANDED,
+        FONT_STRETCH_EXTRA_EXPANDED,
+        FONT_STRETCH_ULTRA_EXPANDED,
+        FONT_STRETCH_INHERIT
+} ;
+
+/**************************************
+ *'font-family' manipulation functions
+ ***************************************/
+CRFontFamily *
+cr_font_family_new (enum CRFontFamilyType a_type, guchar *a_name) ;
+
+CRFontFamily *
+cr_font_family_append (CRFontFamily *a_this, 
+		       CRFontFamily *a_family_to_append) ;
+
+guchar *
+cr_font_family_to_string (CRFontFamily const *a_this,
+                          gboolean a_walk_font_family_list) ;
+
+CRFontFamily *
+cr_font_family_prepend (CRFontFamily *a_this, 
+			CRFontFamily *a_family_to_prepend);
+
+enum CRStatus
+cr_font_family_destroy (CRFontFamily *a_this) ;
+
+enum CRStatus
+cr_font_family_set_name (CRFontFamily *a_this, guchar *a_name) ;
+
+
+/************************************
+ *'font-size' manipulation functions
+ ***********************************/
+
+CRFontSize * cr_font_size_new (void) ;
+
+enum CRStatus cr_font_size_clear (CRFontSize *a_this) ;
+
+enum CRStatus cr_font_size_copy (CRFontSize *a_dst, 
+                                 CRFontSize const *a_src) ;
+enum CRStatus cr_font_size_set_predefined_absolute_font_size (CRFontSize *a_this, 
+                                                              enum CRPredefinedAbsoluteFontSize a_predefined) ;
+enum CRStatus cr_font_size_set_relative_font_size (CRFontSize *a_this,
+                                                   enum CRRelativeFontSize a_relative) ;
+
+enum CRStatus cr_font_size_set_absolute_font_size (CRFontSize *a_this,
+                                                   enum CRNumType a_num_type,
+                                                   gdouble a_value) ;
+
+enum CRStatus cr_font_size_set_to_inherit (CRFontSize *a_this) ;
+
+gboolean cr_font_size_is_set_to_inherit (CRFontSize const *a_this) ;
+
+gchar* cr_font_size_to_string (CRFontSize const *a_this) ;
+
+void cr_font_size_destroy (CRFontSize *a_font_size) ;
+
+/*******************************************************
+ *'font-size-adjust' manipulation function declarations
+ *******************************************************/
+
+CRFontSizeAdjust * cr_font_size_adjust_new (void) ;
+
+gchar * cr_font_size_adjust_to_string (CRFontSizeAdjust const *a_this) ;
+
+void cr_font_size_adjust_destroy (CRFontSizeAdjust *a_this) ;
+
+void 
+cr_font_size_get_smaller_predefined_font_size (enum CRPredefinedAbsoluteFontSize a_font_size,
+                                               enum CRPredefinedAbsoluteFontSize *a_smaller_size) ;
+void
+cr_font_size_get_larger_predefined_font_size (enum CRPredefinedAbsoluteFontSize a_font_size,
+                                              enum CRPredefinedAbsoluteFontSize *a_larger_size) ;
+
+gboolean
+cr_font_size_is_predefined_absolute_font_size (enum CRPredefinedAbsoluteFontSize a_font_size) ;
+
+/***********************************
+ *various other font related functions
+ ***********************************/
+const gchar * cr_font_style_to_string (enum CRFontStyle a_code) ;
+
+const gchar * cr_font_weight_to_string (enum CRFontWeight a_code)  ;
+
+enum CRFontWeight
+cr_font_weight_get_bolder (enum CRFontWeight a_weight) ;
+
+const gchar * cr_font_variant_to_string (enum CRFontVariant a_code) ;
+
+const gchar * cr_font_stretch_to_string (enum CRFontStretch a_code) ;
+
+G_END_DECLS
+
+#endif
diff --git a/src/st/croco/cr-input.c b/src/st/croco/cr-input.c
new file mode 100644
index 000000000..3b63a88ee
--- /dev/null
+++ b/src/st/croco/cr-input.c
@@ -0,0 +1,1191 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include "stdio.h"
+#include <string.h>
+#include "cr-input.h"
+#include "cr-enc-handler.h"
+
+/**
+ *@CRInput:
+ *
+ *The definition of the #CRInput class.
+ */
+
+/*******************
+ *Private type defs
+ *******************/
+
+/**
+ *The private attributes of
+ *the #CRInputPriv class.
+ */
+struct _CRInputPriv {
+        /*
+         *The input buffer
+         */
+        guchar *in_buf;
+        gulong in_buf_size;
+
+        gulong nb_bytes;
+
+        /*
+         *The index of the next byte
+         *to be read.
+         */
+        gulong next_byte_index;
+
+        /*
+         *The current line number
+         */
+        gulong line;
+
+        /*
+         *The current col number
+         */
+        gulong col;
+
+        gboolean end_of_line;
+        gboolean end_of_input;
+
+        /*
+         *the reference count of this
+         *instance.
+         */
+        guint ref_count;
+        gboolean free_in_buf;
+};
+
+#define PRIVATE(object) (object)->priv
+
+/***************************
+ *private constants
+ **************************/
+#define CR_INPUT_MEM_CHUNK_SIZE 1024 * 4
+
+static CRInput *cr_input_new_real (void);
+
+static CRInput *
+cr_input_new_real (void)
+{
+        CRInput *result = NULL;
+
+        result = g_try_malloc (sizeof (CRInput));
+        if (!result) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+        memset (result, 0, sizeof (CRInput));
+
+        PRIVATE (result) = g_try_malloc (sizeof (CRInputPriv));
+        if (!PRIVATE (result)) {
+                cr_utils_trace_info ("Out of memory");
+                g_free (result);
+                return NULL;
+        }
+        memset (PRIVATE (result), 0, sizeof (CRInputPriv));
+        PRIVATE (result)->free_in_buf = TRUE;
+        return result;
+}
+
+/****************
+ *Public methods
+ ***************/
+
+/**
+ * cr_input_new_from_buf:
+ *@a_buf: the memory buffer to create the input stream from.
+ *The #CRInput keeps this pointer so user should not free it !.
+ *@a_len: the size of the input buffer.
+ *@a_enc: the buffer's encoding.
+ *@a_free_buf: if set to TRUE, this a_buf will be freed
+ *at the destruction of this instance. If set to false, it is up
+ *to the caller to free it.
+ *
+ *Creates a new input stream from a memory buffer.
+ *Returns the newly built instance of #CRInput.
+ */
+CRInput *
+cr_input_new_from_buf (guchar * a_buf,
+                       gulong a_len,
+                       enum CREncoding a_enc,
+                       gboolean a_free_buf)
+{
+        CRInput *result = NULL;
+        enum CRStatus status = CR_OK;
+        CREncHandler *enc_handler = NULL;
+        gulong len = a_len;
+
+        g_return_val_if_fail (a_buf, NULL);
+
+        result = cr_input_new_real ();
+        g_return_val_if_fail (result, NULL);
+
+        /*transform the encoding in utf8 */
+        if (a_enc != CR_UTF_8) {
+                enc_handler = cr_enc_handler_get_instance (a_enc);
+                if (!enc_handler) {
+                        goto error;
+                }
+
+                status = cr_enc_handler_convert_input
+                        (enc_handler, a_buf, &len,
+                         &PRIVATE (result)->in_buf,
+                         &PRIVATE (result)->in_buf_size);
+                if (status != CR_OK)
+                        goto error;
+                PRIVATE (result)->free_in_buf = TRUE;
+                if (a_free_buf == TRUE && a_buf) {
+                        g_free (a_buf) ;
+                        a_buf = NULL ;
+                }                
+                PRIVATE (result)->nb_bytes = PRIVATE (result)->in_buf_size;
+        } else {
+                PRIVATE (result)->in_buf = (guchar *) a_buf;
+                PRIVATE (result)->in_buf_size = a_len;
+                PRIVATE (result)->nb_bytes = a_len;
+                PRIVATE (result)->free_in_buf = a_free_buf;
+        }
+        PRIVATE (result)->line = 1;
+        PRIVATE (result)->col =  0;
+        return result;
+
+ error:
+        if (result) {
+                cr_input_destroy (result);
+                result = NULL;
+        }
+
+        return NULL;
+}
+
+/**
+ * cr_input_new_from_uri:
+ *@a_file_uri: the file to create *the input stream from.
+ *@a_enc: the encoding of the file *to create the input from.
+ *
+ *Creates a new input stream from
+ *a file.
+ *
+ *Returns the newly created input stream if
+ *this method could read the file and create it,
+ *NULL otherwise.
+ */
+
+CRInput *
+cr_input_new_from_uri (const gchar * a_file_uri, enum CREncoding a_enc)
+{
+        CRInput *result = NULL;
+        enum CRStatus status = CR_OK;
+        FILE *file_ptr = NULL;
+        guchar tmp_buf[CR_INPUT_MEM_CHUNK_SIZE] = { 0 };
+        gulong nb_read = 0,
+                len = 0,
+                buf_size = 0;
+        gboolean loop = TRUE;
+        guchar *buf = NULL;
+
+        g_return_val_if_fail (a_file_uri, NULL);
+
+        file_ptr = fopen (a_file_uri, "r");
+
+        if (file_ptr == NULL) {
+
+#ifdef CR_DEBUG
+                cr_utils_trace_debug ("could not open file");
+#endif
+                g_warning ("Could not open file %s\n", a_file_uri);
+
+                return NULL;
+        }
+
+        /*load the file */
+        while (loop) {
+                nb_read = fread (tmp_buf, 1 /*read bytes */ ,
+                                 CR_INPUT_MEM_CHUNK_SIZE /*nb of bytes */ ,
+                                 file_ptr);
+
+                if (nb_read != CR_INPUT_MEM_CHUNK_SIZE) {
+                        /*we read less chars than we wanted */
+                        if (feof (file_ptr)) {
+                                /*we reached eof */
+                                loop = FALSE;
+                        } else {
+                                /*a pb occurred !! */
+                                cr_utils_trace_debug ("an io error occurred");
+                                status = CR_ERROR;
+                                goto cleanup;
+                        }
+                }
+
+                if (status == CR_OK) {
+                        /*read went well */
+                        buf = g_realloc (buf, len + CR_INPUT_MEM_CHUNK_SIZE);
+                        memcpy (buf + len, tmp_buf, nb_read);
+                        len += nb_read;
+                        buf_size += CR_INPUT_MEM_CHUNK_SIZE;
+                }
+        }
+
+        if (status == CR_OK) {
+                result = cr_input_new_from_buf (buf, len, a_enc, TRUE);
+                if (!result) {
+                        goto cleanup;
+                }
+                /*
+                 *we should  free buf here because it's own by CRInput.
+                 *(see the last parameter of cr_input_new_from_buf().
+                 */
+                buf = NULL;
+        }
+
+ cleanup:
+        if (file_ptr) {
+                fclose (file_ptr);
+                file_ptr = NULL;
+        }
+
+        if (buf) {
+                g_free (buf);
+                buf = NULL;
+        }
+
+        return result;
+}
+
+/**
+ * cr_input_destroy:
+ *@a_this: the current instance of #CRInput.
+ *
+ *The destructor of the #CRInput class.
+ */
+void
+cr_input_destroy (CRInput * a_this)
+{
+        if (a_this == NULL)
+                return;
+
+        if (PRIVATE (a_this)) {
+                if (PRIVATE (a_this)->in_buf && PRIVATE (a_this)->free_in_buf) {
+                        g_free (PRIVATE (a_this)->in_buf);
+                        PRIVATE (a_this)->in_buf = NULL;
+                }
+
+                g_free (PRIVATE (a_this));
+                PRIVATE (a_this) = NULL;
+        }
+
+        g_free (a_this);
+}
+
+/**
+ * cr_input_ref:
+ *@a_this: the current instance of #CRInput.
+ *
+ *Increments the reference count of the current
+ *instance of #CRInput.
+ */
+void
+cr_input_ref (CRInput * a_this)
+{
+        g_return_if_fail (a_this && PRIVATE (a_this));
+
+        PRIVATE (a_this)->ref_count++;
+}
+
+/**
+ * cr_input_unref:
+ *@a_this: the current instance of #CRInput.
+ *
+ *Decrements the reference count of this instance
+ *of #CRInput. If the reference count goes down to
+ *zero, this instance is destroyed.
+ *
+ * Returns TRUE if the instance of #CRInput got destroyed, false otherwise.
+ */
+gboolean
+cr_input_unref (CRInput * a_this)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this), FALSE);
+
+        if (PRIVATE (a_this)->ref_count) {
+                PRIVATE (a_this)->ref_count--;
+        }
+
+        if (PRIVATE (a_this)->ref_count == 0) {
+                cr_input_destroy (a_this);
+                return TRUE;
+        }
+        return FALSE;
+}
+
+/**
+ * cr_input_end_of_input:
+ *@a_this: the current instance of #CRInput.
+ *@a_end_of_input: out parameter. Is set to TRUE if
+ *the current instance has reached the end of its input buffer,
+ *FALSE otherwise.
+ *
+ *Tests wether the current instance of
+ *#CRInput has reached its input buffer.
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ * Note that all the out parameters of this method are valid if
+ * and only if this method returns CR_OK.
+ */
+enum CRStatus
+cr_input_end_of_input (CRInput const * a_this, gboolean * a_end_of_input)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_end_of_input, CR_BAD_PARAM_ERROR);
+
+        *a_end_of_input = (PRIVATE (a_this)->next_byte_index
+                           >= PRIVATE (a_this)->in_buf_size) ? TRUE : FALSE;
+
+        return CR_OK;
+}
+
+/**
+ * cr_input_get_nb_bytes_left:
+ *@a_this: the current instance of #CRInput.
+ *
+ *Returns the number of bytes left in the input stream
+ *before the end, -1 in case of error.
+ */
+glong
+cr_input_get_nb_bytes_left (CRInput const * a_this)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this), -1);
+        g_return_val_if_fail (PRIVATE (a_this)->nb_bytes
+                              <= PRIVATE (a_this)->in_buf_size, -1);
+        g_return_val_if_fail (PRIVATE (a_this)->next_byte_index
+                              <= PRIVATE (a_this)->nb_bytes, -1);
+
+        if (PRIVATE (a_this)->end_of_input)
+                return 0;
+
+        return PRIVATE (a_this)->nb_bytes - PRIVATE (a_this)->next_byte_index;
+}
+
+/**
+ * cr_input_read_byte:
+ *@a_this: the current instance of #CRInput.
+ *@a_byte: out parameter the returned byte.
+ *
+ *Gets the next byte of the input.
+ *Updates the state of the input so that
+ *the next invocation of this method  returns
+ *the next coming byte.
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise. All the out parameters of this method are valid if
+ *and only if this method returns CR_OK.
+ */
+enum CRStatus
+cr_input_read_byte (CRInput * a_this, guchar * a_byte)
+{
+        gulong nb_bytes_left = 0;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_byte, CR_BAD_PARAM_ERROR);
+
+        g_return_val_if_fail (PRIVATE (a_this)->next_byte_index <=
+                              PRIVATE (a_this)->nb_bytes, CR_BAD_PARAM_ERROR);
+
+        if (PRIVATE (a_this)->end_of_input == TRUE)
+                return CR_END_OF_INPUT_ERROR;
+
+        nb_bytes_left = cr_input_get_nb_bytes_left (a_this);
+
+        if (nb_bytes_left < 1) {
+                return CR_END_OF_INPUT_ERROR;
+        }
+
+        *a_byte = PRIVATE (a_this)->in_buf[PRIVATE (a_this)->next_byte_index];
+
+        if (PRIVATE (a_this)->nb_bytes -
+            PRIVATE (a_this)->next_byte_index < 2) {
+                PRIVATE (a_this)->end_of_input = TRUE;
+        } else {
+                PRIVATE (a_this)->next_byte_index++;
+        }
+
+        return CR_OK;
+}
+
+/**
+ * cr_input_read_char:
+ *@a_this: the current instance of CRInput.
+ *@a_char: out parameter. The read character.
+ *
+ *Reads an unicode character from the current instance of
+ *#CRInput.
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_input_read_char (CRInput * a_this, guint32 * a_char)
+{
+        enum CRStatus status = CR_OK;
+        gulong consumed = 0,
+                nb_bytes_left = 0;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this) && a_char,
+                              CR_BAD_PARAM_ERROR);
+
+        if (PRIVATE (a_this)->end_of_input == TRUE)
+                return CR_END_OF_INPUT_ERROR;
+
+        nb_bytes_left = cr_input_get_nb_bytes_left (a_this);
+
+        if (nb_bytes_left < 1) {
+                return CR_END_OF_INPUT_ERROR;
+        }
+
+        status = cr_utils_read_char_from_utf8_buf
+                (PRIVATE (a_this)->in_buf
+                 +
+                 PRIVATE (a_this)->next_byte_index,
+                 nb_bytes_left, a_char, &consumed);
+
+        if (status == CR_OK) {
+                /*update next byte index */
+                PRIVATE (a_this)->next_byte_index += consumed;
+
+                /*update line and column number */
+                if (PRIVATE (a_this)->end_of_line == TRUE) {
+                        PRIVATE (a_this)->col = 1;
+                        PRIVATE (a_this)->line++;
+                        PRIVATE (a_this)->end_of_line = FALSE;
+                } else if (*a_char != '\n') {
+                        PRIVATE (a_this)->col++;
+                }
+
+                if (*a_char == '\n') {
+                        PRIVATE (a_this)->end_of_line = TRUE;
+                }
+        }
+
+        return status;
+}
+
+/**
+ * cr_input_set_line_num:
+ *@a_this: the "this pointer" of the current instance of #CRInput.
+ *@a_line_num: the new line number.
+ *
+ *Setter of the current line number.
+ *
+ *Return CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_set_line_num (CRInput * a_this, glong a_line_num)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        PRIVATE (a_this)->line = a_line_num;
+
+        return CR_OK;
+}
+
+/**
+ * cr_input_get_line_num:
+ *@a_this: the "this pointer" of the current instance of #CRInput.
+ *@a_line_num: the returned line number.
+ *
+ *Getter of the current line number.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_get_line_num (CRInput const * a_this, glong * a_line_num)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_line_num, CR_BAD_PARAM_ERROR);
+
+        *a_line_num = PRIVATE (a_this)->line;
+
+        return CR_OK;
+}
+
+/**
+ * cr_input_set_column_num:
+ *@a_this: the "this pointer" of the current instance of #CRInput.
+ *@a_col: the new column number.
+ *
+ *Setter of the current column number.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_set_column_num (CRInput * a_this, glong a_col)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        PRIVATE (a_this)->col = a_col;
+
+        return CR_OK;
+}
+
+/**
+ * cr_input_get_column_num:
+ *@a_this: the "this pointer" of the current instance of #CRInput.
+ *@a_col: out parameter
+ *
+ *Getter of the current column number.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_get_column_num (CRInput const * a_this, glong * a_col)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this) && a_col,
+                              CR_BAD_PARAM_ERROR);
+
+        *a_col = PRIVATE (a_this)->col;
+
+        return CR_OK;
+}
+
+/**
+ * cr_input_increment_line_num:
+ *@a_this: the "this pointer" of the current instance of #CRInput.
+ *@a_increment: the increment to add to the line number.
+ *
+ *Increments the current line number.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_increment_line_num (CRInput * a_this, glong a_increment)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        PRIVATE (a_this)->line += a_increment;
+
+        return CR_OK;
+}
+
+/**
+ * cr_input_increment_col_num:
+ *@a_this: the "this pointer" of the current instance of #CRInput.
+ *@a_increment: the increment to add to the column number.
+ *
+ *Increments the current column number.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_increment_col_num (CRInput * a_this, glong a_increment)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        PRIVATE (a_this)->col += a_increment;
+
+        return CR_OK;
+}
+
+/**
+ * cr_input_consume_char:
+ *@a_this: the this pointer.
+ *@a_char: the character to consume. If set to zero,
+ *consumes any character.
+ *
+ *Consumes the next character of the input stream if
+ *and only if that character equals a_char.
+ *
+ *Returns CR_OK upon successful completion, CR_PARSING_ERROR if
+ *next char is different from a_char, an other error code otherwise
+ */
+enum CRStatus
+cr_input_consume_char (CRInput * a_this, guint32 a_char)
+{
+        guint32 c;
+        enum CRStatus status;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        if ((status = cr_input_peek_char (a_this, &c)) != CR_OK) {
+                return status;
+        }
+
+        if (c == a_char || a_char == 0) {
+                status = cr_input_read_char (a_this, &c);
+        } else {
+                return CR_PARSING_ERROR;
+        }
+
+        return status;
+}
+
+/**
+ * cr_input_consume_chars:
+ *@a_this: the this pointer of the current instance of #CRInput.
+ *@a_char: the character to consume.
+ *@a_nb_char: in/out parameter. The number of characters to consume.
+ *If set to a negative value, the function will consume all the occurences
+ *of a_char found.
+ *After return, if the return value equals CR_OK, this variable contains 
+ *the number of characters actually consumed.
+ *
+ *Consumes up to a_nb_char occurences of the next contiguous characters 
+ *which equal a_char. Note that the next character of the input stream
+ **MUST* equal a_char to trigger the consumption, or else, the error
+ *code CR_PARSING_ERROR is returned.
+ *If the number of contiguous characters that equals a_char is less than
+ *a_nb_char, then this function consumes all the characters it can consume.
+ * 
+ *Returns CR_OK if at least one character has been consumed, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_input_consume_chars (CRInput * a_this, guint32 a_char, gulong * a_nb_char)
+{
+        enum CRStatus status = CR_OK;
+        gulong nb_consumed = 0;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this) && a_nb_char,
+                              CR_BAD_PARAM_ERROR);
+
+        g_return_val_if_fail (a_char != 0 || a_nb_char != NULL,
+                              CR_BAD_PARAM_ERROR);
+
+        for (nb_consumed = 0; ((status == CR_OK)
+                               && (*a_nb_char > 0
+                                   && nb_consumed < *a_nb_char));
+             nb_consumed++) {
+                status = cr_input_consume_char (a_this, a_char);
+        }
+
+        *a_nb_char = nb_consumed;
+
+        if ((nb_consumed > 0)
+            && ((status == CR_PARSING_ERROR)
+                || (status == CR_END_OF_INPUT_ERROR))) {
+                status = CR_OK;
+        }
+
+        return status;
+}
+
+/**
+ * cr_input_consume_white_spaces:
+ *@a_this: the "this pointer" of the current instance of #CRInput.
+ *@a_nb_chars: in/out parameter. The number of white spaces to
+ *consume. After return, holds the number of white spaces actually consumed.
+ *
+ *Same as cr_input_consume_chars() but this one consumes white
+ *spaces.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_consume_white_spaces (CRInput * a_this, gulong * a_nb_chars)
+{
+        enum CRStatus status = CR_OK;
+        guint32 cur_char = 0,
+                nb_consumed = 0;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this) && a_nb_chars,
+                              CR_BAD_PARAM_ERROR);
+
+        for (nb_consumed = 0;
+             ((*a_nb_chars > 0) && (nb_consumed < *a_nb_chars));
+             nb_consumed++) {
+                status = cr_input_peek_char (a_this, &cur_char);
+                if (status != CR_OK)
+                        break;
+
+                /*if the next char is a white space, consume it ! */
+                if (cr_utils_is_white_space (cur_char) == TRUE) {
+                        status = cr_input_read_char (a_this, &cur_char);
+                        if (status != CR_OK)
+                                break;
+                        continue;
+                }
+
+                break;
+
+        }
+
+	*a_nb_chars = (gulong) nb_consumed;
+
+        if (nb_consumed && status == CR_END_OF_INPUT_ERROR) {
+                status = CR_OK;
+        }
+
+        return status;
+}
+
+/**
+ * cr_input_peek_char:
+ *@a_this: the current instance of #CRInput.
+ *@a_char: out parameter. The returned character.
+ *
+ *Same as cr_input_read_char() but does not update the
+ *internal state of the input stream. The next call
+ *to cr_input_peek_char() or cr_input_read_char() will thus
+ *return the same character as the current one.
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_input_peek_char (CRInput const * a_this, guint32 * a_char)
+{
+        enum CRStatus status = CR_OK;
+        gulong consumed = 0,
+                nb_bytes_left = 0;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_char, CR_BAD_PARAM_ERROR);
+
+        if (PRIVATE (a_this)->next_byte_index >=
+            PRIVATE (a_this)->in_buf_size) {
+                return CR_END_OF_INPUT_ERROR;
+        }
+
+        nb_bytes_left = cr_input_get_nb_bytes_left (a_this);
+
+        if (nb_bytes_left < 1) {
+                return CR_END_OF_INPUT_ERROR;
+        }
+
+        status = cr_utils_read_char_from_utf8_buf
+                (PRIVATE (a_this)->in_buf +
+                 PRIVATE (a_this)->next_byte_index,
+                 nb_bytes_left, a_char, &consumed);
+
+        return status;
+}
+
+/**
+ * cr_input_peek_byte:
+ *@a_this: the current instance of #CRInput.
+ *@a_origin: the origin to consider in the calculation
+ *of the position of the byte to peek.
+ *@a_offset: the offset of the byte to peek, starting from
+ *the origin specified by a_origin.
+ *@a_byte: out parameter the peeked byte.
+ *
+ *Gets a byte from the input stream,
+ *starting from the current position in the input stream.
+ *Unlike cr_input_peek_next_byte() this method
+ *does not update the state of the current input stream.
+ *Subsequent calls to cr_input_peek_byte with the same arguments
+ *will return the same byte.
+ *
+ *Returns CR_OK upon successful completion or,
+ *CR_BAD_PARAM_ERROR if at least one of the parameters is invalid;
+ *CR_OUT_OF_BOUNDS_ERROR if the indexed byte is out of bounds.
+ */
+enum CRStatus
+cr_input_peek_byte (CRInput const * a_this, enum CRSeekPos a_origin,
+                    gulong a_offset, guchar * a_byte)
+{
+        gulong abs_offset = 0;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_byte, CR_BAD_PARAM_ERROR);
+
+        switch (a_origin) {
+
+        case CR_SEEK_CUR:
+                abs_offset = PRIVATE (a_this)->next_byte_index - 1 + a_offset;
+                break;
+
+        case CR_SEEK_BEGIN:
+                abs_offset = a_offset;
+                break;
+
+        case CR_SEEK_END:
+                abs_offset = PRIVATE (a_this)->in_buf_size - 1 - a_offset;
+                break;
+
+        default:
+                return CR_BAD_PARAM_ERROR;
+        }
+
+        if (abs_offset < PRIVATE (a_this)->in_buf_size) {
+
+                *a_byte = PRIVATE (a_this)->in_buf[abs_offset];
+
+                return CR_OK;
+
+        } else {
+                return CR_END_OF_INPUT_ERROR;
+        }
+}
+
+/**
+ * cr_input_peek_byte2:
+ *@a_this: the current byte input stream.
+ *@a_offset: the offset of the byte to peek, starting
+ *from the current input position pointer.
+ *@a_eof: out parameter. Is set to true is we reach end of
+ *stream. If set to NULL by the caller, this parameter is not taken
+ *in account.
+ *
+ *Same as cr_input_peek_byte() but with a simplified
+ *interface.
+ *
+ *Returns the read byte or 0 if something bad happened.
+ */
+guchar
+cr_input_peek_byte2 (CRInput const * a_this, gulong a_offset, gboolean * a_eof)
+{
+        guchar result = 0;
+        enum CRStatus status = CR_ERROR;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this), 0);
+
+        if (a_eof)
+                *a_eof = FALSE;
+
+        status = cr_input_peek_byte (a_this, CR_SEEK_CUR, a_offset, &result);
+
+        if ((status == CR_END_OF_INPUT_ERROR)
+            && a_eof)
+                *a_eof = TRUE;
+
+        return result;
+}
+
+/**
+ * cr_input_get_byte_addr:
+ *@a_this: the current instance of #CRInput.
+ *@a_offset: the offset of the byte in the input stream starting
+ *from the beginning of the stream.
+ *
+ *Gets the memory address of the byte located at a given offset
+ *in the input stream.
+ *
+ *Returns the address, otherwise NULL if an error occurred.
+ */
+guchar *
+cr_input_get_byte_addr (CRInput * a_this, gulong a_offset)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this), NULL);
+
+        if (a_offset >= PRIVATE (a_this)->nb_bytes) {
+                return NULL;
+        }
+
+        return &PRIVATE (a_this)->in_buf[a_offset];
+}
+
+/**
+ * cr_input_get_cur_byte_addr:
+ *@a_this: the current input stream
+ *@a_offset: out parameter. The returned address.
+ *
+ *Gets the address of the current character pointer.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_get_cur_byte_addr (CRInput * a_this, guchar ** a_offset)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this) && a_offset,
+                              CR_BAD_PARAM_ERROR);
+
+        if (!PRIVATE (a_this)->next_byte_index) {
+                return CR_START_OF_INPUT_ERROR;
+        }
+
+        *a_offset = cr_input_get_byte_addr
+                (a_this, PRIVATE (a_this)->next_byte_index - 1);
+
+        return CR_OK;
+}
+
+/**
+ * cr_input_seek_index:
+ *@a_this: the current instance of #CRInput.
+ *@a_origin: the origin to consider during the calculation
+ *of the absolute position of the new "current byte index".
+ *@a_pos: the relative offset of the new "current byte index."
+ *This offset is relative to the origin a_origin.
+ *
+ *Sets the "current byte index" of the current instance
+ *of #CRInput. Next call to cr_input_get_byte() will return
+ *the byte next after the new "current byte index".
+ *
+ *Returns CR_OK upon successful completion otherwise returns
+ *CR_BAD_PARAM_ERROR if at least one of the parameters is not valid
+ *or CR_OUT_BOUNDS_ERROR in case of error.
+ */
+enum CRStatus
+cr_input_seek_index (CRInput * a_this, enum CRSeekPos a_origin, gint a_pos)
+{
+
+        glong abs_offset = 0;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        switch (a_origin) {
+
+        case CR_SEEK_CUR:
+                abs_offset = PRIVATE (a_this)->next_byte_index - 1 + a_pos;
+                break;
+
+        case CR_SEEK_BEGIN:
+                abs_offset = a_pos;
+                break;
+
+        case CR_SEEK_END:
+                abs_offset = PRIVATE (a_this)->in_buf_size - 1 - a_pos;
+                break;
+
+        default:
+                return CR_BAD_PARAM_ERROR;
+        }
+
+        if ((abs_offset > 0)
+            && (gulong) abs_offset < PRIVATE (a_this)->nb_bytes) {
+
+                /*update the input stream's internal state */
+                PRIVATE (a_this)->next_byte_index = abs_offset + 1;
+
+                return CR_OK;
+        }
+
+        return CR_OUT_OF_BOUNDS_ERROR;
+}
+
+/**
+ * cr_input_get_cur_pos:
+ *@a_this: the current instance of #CRInput.
+ *@a_pos: out parameter. The returned position.
+ *
+ *Gets the position of the "current byte index" which
+ *is basically the position of the last returned byte in the
+ *input stream.
+ *
+ *Returns CR_OK upon successful completion. Otherwise,
+ *CR_BAD_PARAMETER_ERROR if at least one of the arguments is invalid.
+ *CR_START_OF_INPUT if no call to either cr_input_read_byte()
+ *or cr_input_seek_index() have been issued before calling 
+ *cr_input_get_cur_pos()
+ *Note that the out parameters of this function are valid if and only if this
+ *function returns CR_OK.
+ */
+enum CRStatus
+cr_input_get_cur_pos (CRInput const * a_this, CRInputPos * a_pos)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pos,
+                              CR_BAD_PARAM_ERROR);
+
+        a_pos->next_byte_index = PRIVATE (a_this)->next_byte_index;
+        a_pos->line = PRIVATE (a_this)->line;
+        a_pos->col = PRIVATE (a_this)->col;
+        a_pos->end_of_line = PRIVATE (a_this)->end_of_line;
+        a_pos->end_of_file = PRIVATE (a_this)->end_of_input;
+
+        return CR_OK;
+}
+
+/**
+ * cr_input_get_parsing_location:
+ *@a_this: the current instance of #CRInput
+ *@a_loc: the set parsing location.
+ *
+ *Gets the current parsing location.
+ *The Parsing location is a public datastructure that
+ *represents the current line/column/byte offset/ in the input
+ *stream.
+ *
+ *Returns CR_OK upon successful completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_input_get_parsing_location (CRInput const *a_this,
+                               CRParsingLocation *a_loc)
+{
+        g_return_val_if_fail (a_this 
+                              && PRIVATE (a_this)
+                              && a_loc, 
+                              CR_BAD_PARAM_ERROR) ;
+
+        a_loc->line = PRIVATE (a_this)->line ;
+        a_loc->column = PRIVATE (a_this)->col ;
+        if (PRIVATE (a_this)->next_byte_index) {
+                a_loc->byte_offset = PRIVATE (a_this)->next_byte_index - 1 ;
+        } else {
+                a_loc->byte_offset = PRIVATE (a_this)->next_byte_index  ;
+        }
+        return CR_OK ;
+}
+
+/**
+ * cr_input_get_cur_index:
+ *@a_this: the "this pointer" of the current instance of
+ *#CRInput
+ *@a_index: out parameter. The returned index.
+ *
+ *Getter of the next byte index. 
+ *It actually returns the index of the
+ *next byte to be read.
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_input_get_cur_index (CRInput const * a_this, glong * a_index)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_index, CR_BAD_PARAM_ERROR);
+
+        *a_index = PRIVATE (a_this)->next_byte_index;
+
+        return CR_OK;
+}
+
+/**
+ * cr_input_set_cur_index:
+ *@a_this: the "this pointer" of the current instance
+ *of #CRInput .
+ *@a_index: the new index to set.
+ *
+ *Setter of the next byte index.
+ *It sets the index of the next byte to be read.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_set_cur_index (CRInput * a_this, glong a_index)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        PRIVATE (a_this)->next_byte_index = a_index;
+
+        return CR_OK;
+}
+
+/**
+ * cr_input_set_end_of_file:
+ *@a_this: the current instance of #CRInput.
+ *@a_eof: the new end of file flag.
+ *
+ *Sets the end of file flag.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_set_end_of_file (CRInput * a_this, gboolean a_eof)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        PRIVATE (a_this)->end_of_input = a_eof;
+
+        return CR_OK;
+}
+
+/**
+ * cr_input_get_end_of_file:
+ *@a_this: the current instance of #CRInput.
+ *@a_eof: out parameter the place to put the end of
+ *file flag.
+ *
+ *Gets the end of file flag.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_get_end_of_file (CRInput const * a_this, gboolean * a_eof)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_eof, CR_BAD_PARAM_ERROR);
+
+        *a_eof = PRIVATE (a_this)->end_of_input;
+
+        return CR_OK;
+}
+
+/**
+ * cr_input_set_end_of_line:
+ *@a_this: the current instance of #CRInput.
+ *@a_eol: the new end of line flag.
+ *
+ *Sets the end of line flag.
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_input_set_end_of_line (CRInput * a_this, gboolean a_eol)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        PRIVATE (a_this)->end_of_line = a_eol;
+
+        return CR_OK;
+}
+
+/**
+ * cr_input_get_end_of_line:
+ *@a_this: the current instance of #CRInput
+ *@a_eol: out parameter. The place to put
+ *the returned flag
+ *
+ *Gets the end of line flag of the current input.
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_input_get_end_of_line (CRInput const * a_this, gboolean * a_eol)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_eol, CR_BAD_PARAM_ERROR);
+
+        *a_eol = PRIVATE (a_this)->end_of_line;
+
+        return CR_OK;
+}
+
+/**
+ * cr_input_set_cur_pos:
+ *@a_this: the "this pointer" of the current instance of
+ *#CRInput.
+ *@a_pos: the new position.
+ *
+ *Sets the current position in the input stream.
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_set_cur_pos (CRInput * a_this, CRInputPos const * a_pos)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pos,
+                              CR_BAD_PARAM_ERROR);
+
+        cr_input_set_column_num (a_this, a_pos->col);
+        cr_input_set_line_num (a_this, a_pos->line);
+        cr_input_set_cur_index (a_this, a_pos->next_byte_index);
+        cr_input_set_end_of_line (a_this, a_pos->end_of_line);
+        cr_input_set_end_of_file (a_this, a_pos->end_of_file);
+
+        return CR_OK;
+}
diff --git a/src/st/croco/cr-input.h b/src/st/croco/cr-input.h
new file mode 100644
index 000000000..9eb402a87
--- /dev/null
+++ b/src/st/croco/cr-input.h
@@ -0,0 +1,174 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset:8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ * 
+ * Author: Dodji Seketeli
+ * See the COPYRIGHTS file for copyrights information.
+ */
+
+#ifndef __CR_INPUT_SRC_H__
+#define __CR_INPUT_SRC_H__
+
+
+#include <glib.h>
+#include "cr-utils.h"
+#include "cr-parsing-location.h"
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *The libcroco basic input stream class
+ *declaration file.
+ */
+
+typedef struct _CRInput CRInput ;
+typedef struct _CRInputPriv CRInputPriv ;
+
+/**
+ *The #CRInput class provides the abstraction of 
+ *an utf8-encoded character stream.
+ */
+struct _CRInput 
+{
+        CRInputPriv *priv ;
+} ;
+
+typedef struct _CRInputPos CRInputPos ;
+
+struct _CRInputPos
+{
+        glong line ;
+        glong col ;
+        gboolean end_of_file ;
+        gboolean end_of_line ;
+        glong next_byte_index ;
+} ;
+
+CRInput *
+cr_input_new_from_buf (guchar *a_buf, gulong a_len,
+                       enum CREncoding a_enc, gboolean a_free_buf) ;
+CRInput *
+cr_input_new_from_uri (const gchar *a_file_uri, 
+                       enum CREncoding a_enc) ;
+
+void
+cr_input_destroy (CRInput *a_this) ;
+
+void 
+cr_input_ref (CRInput *a_this) ;
+
+gboolean
+cr_input_unref (CRInput *a_this) ;
+
+enum CRStatus
+cr_input_read_byte (CRInput *a_this, guchar *a_byte) ;
+
+enum CRStatus
+cr_input_read_char (CRInput *a_this, guint32 *a_char) ;
+
+enum CRStatus
+cr_input_consume_chars (CRInput *a_this, guint32 a_char, 
+                        gulong *a_nb_char) ;
+
+enum CRStatus
+cr_input_consume_char (CRInput *a_this, guint32 a_char) ;
+
+enum CRStatus
+cr_input_consume_white_spaces (CRInput *a_this, gulong *a_nb_chars) ;
+
+enum CRStatus
+cr_input_peek_byte (CRInput const *a_this, enum CRSeekPos a_origin,
+                    gulong a_offset, guchar *a_byte) ;
+
+guchar 
+cr_input_peek_byte2 (CRInput const *a_this, gulong a_offset,
+                     gboolean *a_eof) ;
+
+enum CRStatus
+cr_input_peek_char (CRInput const *a_this, guint32 *a_char) ;
+
+guchar *
+cr_input_get_byte_addr (CRInput *a_this, 
+                        gulong a_offset) ;
+
+enum CRStatus
+cr_input_get_cur_byte_addr (CRInput *a_this, guchar ** a_offset) ;
+
+enum CRStatus
+cr_input_seek_index (CRInput *a_this, 
+                     enum CRSeekPos a_origin, gint a_pos) ;
+
+enum CRStatus
+cr_input_get_cur_index (CRInput const *a_this, glong *a_index) ;
+
+enum CRStatus
+cr_input_set_cur_index (CRInput *a_this, glong a_index) ;
+
+enum CRStatus
+cr_input_get_cur_pos (CRInput const *a_this, CRInputPos * a_pos) ;
+
+enum CRStatus
+cr_input_set_cur_pos (CRInput *a_this, CRInputPos const *a_pos) ;
+
+enum CRStatus
+cr_input_get_parsing_location (CRInput const *a_this,
+                               CRParsingLocation *a_loc) ;
+
+enum CRStatus
+cr_input_get_end_of_line (CRInput const *a_this, gboolean *a_eol) ;
+
+enum CRStatus
+cr_input_set_end_of_line (CRInput *a_this, gboolean a_eol) ;
+
+enum CRStatus
+cr_input_get_end_of_file (CRInput const *a_this, gboolean *a_eof) ;
+
+enum CRStatus
+cr_input_set_end_of_file (CRInput *a_this, gboolean a_eof) ;
+
+enum CRStatus
+cr_input_set_line_num (CRInput *a_this, glong a_line_num) ;
+
+enum CRStatus
+cr_input_get_line_num (CRInput const *a_this, glong *a_line_num) ;
+
+enum CRStatus
+cr_input_set_column_num (CRInput *a_this, glong a_col) ;
+
+enum CRStatus
+cr_input_get_column_num (CRInput const *a_this, glong *a_col) ;
+
+enum CRStatus
+cr_input_increment_line_num (CRInput *a_this, 
+                             glong a_increment) ;
+
+enum CRStatus
+cr_input_increment_col_num (CRInput *a_this,
+                            glong a_increment) ;
+        
+glong
+cr_input_get_nb_bytes_left (CRInput const *a_this) ;
+
+enum CRStatus
+cr_input_end_of_input (CRInput const *a_this, gboolean *a_end_of_input) ;
+
+G_END_DECLS
+
+#endif /*__CR_INPUT_SRC_H__*/
+
diff --git a/src/st/croco/cr-num.c b/src/st/croco/cr-num.c
new file mode 100644
index 000000000..d5dbd5fb0
--- /dev/null
+++ b/src/st/croco/cr-num.c
@@ -0,0 +1,313 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyrights information.
+ */
+
+/**
+ *@CRNum:
+ *
+ *The definition
+ *of the #CRNum class.
+ */
+
+#include "cr-num.h"
+#include "string.h"
+
+/**
+ * cr_num_new:
+ *
+ *#CRNum.
+ *
+ *Returns the newly built instance of
+ *#CRNum.
+ */
+CRNum *
+cr_num_new (void)
+{
+        CRNum *result = NULL;
+
+        result = g_try_malloc (sizeof (CRNum));
+
+        if (result == NULL) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+
+        memset (result, 0, sizeof (CRNum));
+
+        return result;
+}
+
+/**
+ * cr_num_new_with_val:
+ * @a_val: the numerical value of the number.
+ * @a_type: the type of number.
+ * 
+ * A constructor of #CRNum.
+ *
+ * Returns the newly built instance of #CRNum or
+ * NULL if an error arises.
+ */
+CRNum *
+cr_num_new_with_val (gdouble a_val, enum CRNumType a_type)
+{
+        CRNum *result = NULL;
+
+        result = cr_num_new ();
+
+        g_return_val_if_fail (result, NULL);
+
+        result->val = a_val;
+        result->type = a_type;
+
+        return result;
+}
+
+/**
+ * cr_num_to_string:
+ *@a_this: the current instance of #CRNum.
+ *
+ *Returns the newly built string representation
+ *of the current instance of #CRNum. The returned
+ *string is NULL terminated. The caller *must*
+ *free the returned string.
+ */
+guchar *
+cr_num_to_string (CRNum const * a_this)
+{
+        gdouble test_val = 0.0;
+
+        guchar *tmp_char1 = NULL,
+                *tmp_char2 = NULL,
+                *result = NULL;
+
+        g_return_val_if_fail (a_this, NULL);
+
+        test_val = a_this->val - (glong) a_this->val;
+
+        if (!test_val) {
+                tmp_char1 = (guchar *) g_strdup_printf ("%ld", (glong) a_this->val);
+        } else {
+                tmp_char1 = (guchar *) g_new0 (char, G_ASCII_DTOSTR_BUF_SIZE + 1);
+                if (tmp_char1 != NULL)
+                        g_ascii_dtostr ((gchar *) tmp_char1, G_ASCII_DTOSTR_BUF_SIZE, a_this->val);
+        }
+
+        g_return_val_if_fail (tmp_char1, NULL);
+
+        switch (a_this->type) {
+        case NUM_LENGTH_EM:
+                tmp_char2 = (guchar *) "em";
+                break;
+
+        case NUM_LENGTH_EX:
+                tmp_char2 = (guchar *) "ex";
+                break;
+
+        case NUM_LENGTH_PX:
+                tmp_char2 = (guchar *) "px";
+                break;
+
+        case NUM_LENGTH_IN:
+                tmp_char2 = (guchar *) "in";
+                break;
+
+        case NUM_LENGTH_CM:
+                tmp_char2 = (guchar *) "cm";
+                break;
+
+        case NUM_LENGTH_MM:
+                tmp_char2 = (guchar *) "mm";
+                break;
+
+        case NUM_LENGTH_PT:
+                tmp_char2 = (guchar *) "pt";
+                break;
+
+        case NUM_LENGTH_PC:
+                tmp_char2 = (guchar *) "pc";
+                break;
+
+        case NUM_ANGLE_DEG:
+                tmp_char2 = (guchar *) "deg";
+                break;
+
+        case NUM_ANGLE_RAD:
+                tmp_char2 = (guchar *) "rad";
+                break;
+
+        case NUM_ANGLE_GRAD:
+                tmp_char2 = (guchar *) "grad";
+                break;
+
+        case NUM_TIME_MS:
+                tmp_char2 = (guchar *) "ms";
+                break;
+
+        case NUM_TIME_S:
+                tmp_char2 = (guchar *) "s";
+                break;
+
+        case NUM_FREQ_HZ:
+                tmp_char2 = (guchar *) "Hz";
+                break;
+
+        case NUM_FREQ_KHZ:
+                tmp_char2 = (guchar *) "KHz";
+                break;
+
+        case NUM_PERCENTAGE:
+                tmp_char2 = (guchar *) "%";
+                break;
+        case NUM_INHERIT:
+                tmp_char2 = (guchar *) "inherit";
+                break ;
+        case NUM_AUTO:
+                tmp_char2 = (guchar *) "auto";
+                break ;
+        case NUM_GENERIC:
+                tmp_char2 = NULL ;
+                break ;
+        default:
+                tmp_char2 = (guchar *) "unknown";
+                break;
+        }
+
+        if (tmp_char2) {
+                result = (guchar *)  g_strconcat ((gchar *) tmp_char1, tmp_char2, NULL);
+                g_free (tmp_char1);
+        } else {
+                result = tmp_char1;
+        }
+
+        return result;
+}
+
+/**
+ * cr_num_copy:
+ *@a_src: the instance of #CRNum to copy.
+ *Must be non NULL.
+ *@a_dest: the destination of the copy.
+ *Must be non NULL
+ *
+ *Copies an instance of #CRNum.
+ *
+ *Returns CR_OK upon successful completion, an
+ *error code otherwise.
+ */
+enum CRStatus
+cr_num_copy (CRNum * a_dest, CRNum const * a_src)
+{
+        g_return_val_if_fail (a_dest && a_src, CR_BAD_PARAM_ERROR);
+
+        memcpy (a_dest, a_src, sizeof (CRNum));
+
+        return CR_OK;
+}
+
+/**
+ * cr_num_dup:
+ *@a_this: the instance of #CRNum to duplicate.
+ *
+ *Duplicates an instance of #CRNum
+ *
+ *Returns the newly created (duplicated) instance of #CRNum.
+ *Must be freed by cr_num_destroy().
+ */
+CRNum *
+cr_num_dup (CRNum const * a_this)
+{
+        CRNum *result = NULL;
+        enum CRStatus status = CR_OK;
+
+        g_return_val_if_fail (a_this, NULL);
+
+        result = cr_num_new ();
+        g_return_val_if_fail (result, NULL);
+
+        status = cr_num_copy (result, a_this);
+        g_return_val_if_fail (status == CR_OK, NULL);
+
+        return result;
+}
+
+/**
+ * cr_num_set:
+ *Sets an instance of #CRNum.
+ *@a_this: the current instance of #CRNum to be set.
+ *@a_val: the new numerical value to be hold by the current
+ *instance of #CRNum
+ *@a_type: the new type of #CRNum.
+ *
+ * Returns CR_OK upon succesful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_num_set (CRNum * a_this, gdouble a_val, enum CRNumType a_type)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        a_this->val = a_val;
+        a_this->type = a_type;
+
+        return CR_OK;
+}
+
+/**
+ * cr_num_is_fixed_length:
+ * @a_this: the current instance of #CRNum .
+ *
+ *Tests if the current instance of #CRNum is a fixed
+ *length value or not. Typically a fixed length value
+ *is anything from NUM_LENGTH_EM to NUM_LENGTH_PC.
+ *See the definition of #CRNumType to see what we mean.
+ *
+ *Returns TRUE if the instance of #CRNum is a fixed length number,
+ *FALSE otherwise.
+ */
+gboolean
+cr_num_is_fixed_length (CRNum const * a_this)
+{
+        gboolean result = FALSE;
+
+        g_return_val_if_fail (a_this, FALSE);
+
+        if (a_this->type >= NUM_LENGTH_EM 
+            && a_this->type <= NUM_LENGTH_PC) {
+                result = TRUE ;
+        }
+        return result ;
+}
+
+/**
+ * cr_num_destroy:
+ *@a_this: the this pointer of
+ *the current instance of #CRNum.
+ *
+ *The destructor of #CRNum.
+ */
+void
+cr_num_destroy (CRNum * a_this)
+{
+        g_return_if_fail (a_this);
+
+        g_free (a_this);
+}
diff --git a/src/st/croco/cr-num.h b/src/st/croco/cr-num.h
new file mode 100644
index 000000000..2b73aaf79
--- /dev/null
+++ b/src/st/croco/cr-num.h
@@ -0,0 +1,127 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information
+ */
+
+
+/**
+ *@file
+ *The declaration
+ *of the #CRNum class.
+ */
+
+#ifndef __CR_NUM_H__
+#define __CR_NUM_H__
+
+#include <glib.h>
+#include "cr-utils.h"
+#include "cr-parsing-location.h"
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *The declaration of the #CRNum class.
+ *
+ */
+
+/**
+ *The different types
+ *of numbers.
+ *Please, do not modify
+ *the declaration order of the enum
+ *members, unless you know 
+ *what you are doing.
+ */
+enum CRNumType
+{
+        NUM_AUTO = 0,
+        NUM_GENERIC,
+        NUM_LENGTH_EM,
+        NUM_LENGTH_EX,
+        NUM_LENGTH_PX,
+        NUM_LENGTH_IN,
+        NUM_LENGTH_CM,
+        NUM_LENGTH_MM,
+        NUM_LENGTH_PT,
+        NUM_LENGTH_PC,
+        NUM_ANGLE_DEG,
+        NUM_ANGLE_RAD,
+        NUM_ANGLE_GRAD,
+        NUM_TIME_MS,
+        NUM_TIME_S,
+        NUM_FREQ_HZ,
+        NUM_FREQ_KHZ,
+        NUM_PERCENTAGE,
+	NUM_INHERIT,
+        NUM_UNKNOWN_TYPE,
+        NB_NUM_TYPE
+} ;
+
+
+/**
+ *An abstraction of a number (num)
+ *as defined in the css2 spec.
+ */
+typedef struct _CRNum CRNum ;
+
+/**
+ *An abstraction of a number (num)
+ *as defined in the css2 spec.
+ */
+struct _CRNum
+{
+        enum CRNumType type ;
+        gdouble val ;
+        CRParsingLocation location ;
+} ;
+
+CRNum *
+cr_num_new (void) ;
+	
+CRNum *
+cr_num_new_with_val (gdouble a_val,
+                     enum CRNumType a_type) ;
+
+CRNum *
+cr_num_dup (CRNum const *a_this) ;
+
+guchar *
+cr_num_to_string (CRNum const *a_this) ;
+
+enum CRStatus
+cr_num_copy (CRNum *a_dest, CRNum const *a_src) ;
+
+enum CRStatus
+cr_num_set (CRNum *a_this, gdouble a_val, 
+            enum CRNumType a_type) ;
+
+gboolean
+cr_num_is_fixed_length (CRNum const *a_this) ;
+
+void
+cr_num_destroy (CRNum *a_this) ;
+
+
+G_END_DECLS
+
+
+#endif /*__CR_NUM_H__*/
diff --git a/src/st/croco/cr-om-parser.c b/src/st/croco/cr-om-parser.c
new file mode 100644
index 000000000..ccc45b3e9
--- /dev/null
+++ b/src/st/croco/cr-om-parser.c
@@ -0,0 +1,1142 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include <string.h>
+#include "cr-utils.h"
+#include "cr-om-parser.h"
+
+/**
+ *@CROMParser:
+ *
+ *The definition of the CSS Object Model Parser.
+ *This parser uses (and sits) the SAC api of libcroco defined
+ *in cr-parser.h and cr-doc-handler.h
+ */
+
+struct _CROMParserPriv {
+        CRParser *parser;
+};
+
+#define PRIVATE(a_this) ((a_this)->priv)
+
+/*
+ *Forward declaration of a type defined later
+ *in this file.
+ */
+struct _ParsingContext;
+typedef struct _ParsingContext ParsingContext;
+
+static ParsingContext *new_parsing_context (void);
+
+static void destroy_context (ParsingContext * a_ctxt);
+
+static void unrecoverable_error (CRDocHandler * a_this);
+
+static void error (CRDocHandler * a_this);
+
+static void property (CRDocHandler * a_this,
+                      CRString * a_name, 
+                      CRTerm * a_expression, 
+                      gboolean a_important);
+
+static void end_selector (CRDocHandler * a_this, 
+                          CRSelector * a_selector_list);
+
+static void start_selector (CRDocHandler * a_this, 
+                            CRSelector * a_selector_list);
+
+static void start_font_face (CRDocHandler * a_this,
+                             CRParsingLocation *a_location);
+
+static void end_font_face (CRDocHandler * a_this);
+
+static void end_document (CRDocHandler * a_this);
+
+static void start_document (CRDocHandler * a_this);
+
+static void charset (CRDocHandler * a_this, 
+                     CRString * a_charset,
+                     CRParsingLocation *a_location);
+
+static void start_page (CRDocHandler * a_this, CRString * a_page,
+                        CRString * a_pseudo_page, 
+                        CRParsingLocation *a_location);
+
+static void end_page (CRDocHandler * a_this, CRString * a_page, 
+                      CRString * a_pseudo_page);
+
+static void start_media (CRDocHandler * a_this, 
+                         GList * a_media_list,
+                         CRParsingLocation *a_location);
+
+static void end_media (CRDocHandler * a_this, 
+                       GList * a_media_list);
+
+static void import_style (CRDocHandler * a_this, 
+                          GList * a_media_list,
+                          CRString * a_uri, 
+                          CRString * a_uri_default_ns,
+                          CRParsingLocation *a_location);
+
+struct _ParsingContext {
+        CRStyleSheet *stylesheet;
+        CRStatement *cur_stmt;
+        CRStatement *cur_media_stmt;
+};
+
+/********************************************
+ *Private methods
+ ********************************************/
+
+static ParsingContext *
+new_parsing_context (void)
+{
+        ParsingContext *result = NULL;
+
+        result = g_try_malloc (sizeof (ParsingContext));
+        if (!result) {
+                cr_utils_trace_info ("Out of Memory");
+                return NULL;
+        }
+        memset (result, 0, sizeof (ParsingContext));
+        return result;
+}
+
+static void
+destroy_context (ParsingContext * a_ctxt)
+{
+        g_return_if_fail (a_ctxt);
+
+        if (a_ctxt->stylesheet) {
+                cr_stylesheet_destroy (a_ctxt->stylesheet);
+                a_ctxt->stylesheet = NULL;
+        }
+        if (a_ctxt->cur_stmt) {
+                cr_statement_destroy (a_ctxt->cur_stmt);
+                a_ctxt->cur_stmt = NULL;
+        }
+        g_free (a_ctxt);
+}
+
+static enum CRStatus
+cr_om_parser_init_default_sac_handler (CROMParser * a_this)
+{
+        CRDocHandler *sac_handler = NULL;
+        gboolean created_handler = FALSE;
+        enum CRStatus status = CR_OK;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->parser,
+                              CR_BAD_PARAM_ERROR);
+
+        status = cr_parser_get_sac_handler (PRIVATE (a_this)->parser,
+                                            &sac_handler);
+        g_return_val_if_fail (status == CR_OK, status);
+
+        if (!sac_handler) {
+                sac_handler = cr_doc_handler_new ();
+                created_handler = TRUE;
+        }
+
+        /*
+         *initialyze here the sac handler.
+         */
+        sac_handler->start_document = start_document;
+        sac_handler->end_document = end_document;
+        sac_handler->start_selector = start_selector;
+        sac_handler->end_selector = end_selector;
+        sac_handler->property = property;
+        sac_handler->start_font_face = start_font_face;
+        sac_handler->end_font_face = end_font_face;
+        sac_handler->error = error;
+        sac_handler->unrecoverable_error = unrecoverable_error;
+        sac_handler->charset = charset;
+        sac_handler->start_page = start_page;
+        sac_handler->end_page = end_page;
+        sac_handler->start_media = start_media;
+        sac_handler->end_media = end_media;
+        sac_handler->import_style = import_style;
+
+        if (created_handler) {
+                status = cr_parser_set_sac_handler (PRIVATE (a_this)->parser,
+                                                    sac_handler);
+                cr_doc_handler_unref (sac_handler);
+        }
+
+        return status;
+
+}
+
+static void
+start_document (CRDocHandler * a_this)
+{
+        ParsingContext *ctxt = NULL;
+        CRStyleSheet *stylesheet = NULL;
+
+        g_return_if_fail (a_this);
+
+        ctxt = new_parsing_context ();
+        g_return_if_fail (ctxt);
+
+        stylesheet = cr_stylesheet_new (NULL);
+        ctxt->stylesheet = stylesheet;
+        cr_doc_handler_set_ctxt (a_this, ctxt);
+}
+
+static void
+start_font_face (CRDocHandler * a_this,
+                 CRParsingLocation *a_location)
+{
+        enum CRStatus status = CR_OK;
+        ParsingContext *ctxt = NULL;
+        ParsingContext **ctxtptr = NULL;
+
+        g_return_if_fail (a_this);
+
+        g_return_if_fail (a_this);
+	ctxtptr = &ctxt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+        g_return_if_fail (status == CR_OK && ctxt);
+        g_return_if_fail (ctxt->cur_stmt == NULL);
+
+        ctxt->cur_stmt =
+                cr_statement_new_at_font_face_rule (ctxt->stylesheet, NULL);
+
+        g_return_if_fail (ctxt->cur_stmt);
+}
+
+static void
+end_font_face (CRDocHandler * a_this)
+{
+        enum CRStatus status = CR_OK;
+        ParsingContext *ctxt = NULL;
+        ParsingContext **ctxtptr = NULL;
+        CRStatement *stmts = NULL;
+
+        g_return_if_fail (a_this);
+
+        g_return_if_fail (a_this);
+	ctxtptr = &ctxt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+        g_return_if_fail (status == CR_OK && ctxt);
+        g_return_if_fail
+                (ctxt->cur_stmt
+                 && ctxt->cur_stmt->type == AT_FONT_FACE_RULE_STMT
+                 && ctxt->stylesheet);
+
+        stmts = cr_statement_append (ctxt->stylesheet->statements,
+                                     ctxt->cur_stmt);
+        if (!stmts)
+                goto error;
+
+        ctxt->stylesheet->statements = stmts;
+        stmts = NULL;
+        ctxt->cur_stmt = NULL;
+
+        return;
+
+      error:
+
+        if (ctxt->cur_stmt) {
+                cr_statement_destroy (ctxt->cur_stmt);
+                ctxt->cur_stmt = NULL;
+        }
+
+        if (!stmts) {
+                cr_statement_destroy (stmts);
+                stmts = NULL;
+        }
+}
+
+static void
+end_document (CRDocHandler * a_this)
+{
+        enum CRStatus status = CR_OK;
+        ParsingContext *ctxt = NULL;
+        ParsingContext **ctxtptr = NULL;
+
+        g_return_if_fail (a_this);
+	ctxtptr = &ctxt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+        g_return_if_fail (status == CR_OK && ctxt);
+
+        if (!ctxt->stylesheet || ctxt->cur_stmt)
+                goto error;
+
+        status = cr_doc_handler_set_result (a_this, ctxt->stylesheet);
+        g_return_if_fail (status == CR_OK);
+
+        ctxt->stylesheet = NULL;
+        destroy_context (ctxt);
+        cr_doc_handler_set_ctxt (a_this, NULL);
+
+        return;
+
+      error:
+        if (ctxt) {
+                destroy_context (ctxt);
+        }
+}
+
+static void
+charset (CRDocHandler * a_this, CRString * a_charset,
+         CRParsingLocation *a_location)
+{
+        enum CRStatus status = CR_OK;
+        CRStatement *stmt = NULL,
+                *stmt2 = NULL;
+        CRString *charset = NULL;
+
+        ParsingContext *ctxt = NULL;
+        ParsingContext **ctxtptr = NULL;
+
+        g_return_if_fail (a_this);
+	ctxtptr = &ctxt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+        g_return_if_fail (status == CR_OK && ctxt);
+        g_return_if_fail (ctxt->stylesheet);
+
+        charset = cr_string_dup (a_charset) ;
+        stmt = cr_statement_new_at_charset_rule (ctxt->stylesheet, charset);
+        g_return_if_fail (stmt);
+        stmt2 = cr_statement_append (ctxt->stylesheet->statements, stmt);
+        if (!stmt2) {
+                if (stmt) {
+                        cr_statement_destroy (stmt);
+                        stmt = NULL;
+                }
+                if (charset) {
+                        cr_string_destroy (charset);
+                }
+                return;
+        }
+        ctxt->stylesheet->statements = stmt2;
+        stmt2 = NULL;
+}
+
+static void
+start_page (CRDocHandler * a_this, 
+            CRString * a_page, 
+            CRString * a_pseudo,
+            CRParsingLocation *a_location)
+{
+        enum CRStatus status = CR_OK;
+        ParsingContext *ctxt = NULL;
+        ParsingContext **ctxtptr = NULL;
+
+        g_return_if_fail (a_this);
+	ctxtptr = &ctxt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+        g_return_if_fail (status == CR_OK && ctxt);
+        g_return_if_fail (ctxt->cur_stmt == NULL);
+
+        ctxt->cur_stmt = cr_statement_new_at_page_rule
+                (ctxt->stylesheet, NULL, NULL, NULL);
+        if (a_page) {
+                ctxt->cur_stmt->kind.page_rule->name =
+                        cr_string_dup (a_page) ;
+
+                if (!ctxt->cur_stmt->kind.page_rule->name) {
+                        goto error;
+                }
+        }
+        if (a_pseudo) {
+                ctxt->cur_stmt->kind.page_rule->pseudo =
+                        cr_string_dup (a_pseudo) ;
+                if (!ctxt->cur_stmt->kind.page_rule->pseudo) {
+                        goto error;
+                }
+        }
+        return;
+
+ error:
+        if (ctxt->cur_stmt) {
+                cr_statement_destroy (ctxt->cur_stmt);
+                ctxt->cur_stmt = NULL;
+        }
+}
+
+static void
+end_page (CRDocHandler * a_this, 
+          CRString * a_page, 
+          CRString * a_pseudo_page)
+{
+        enum CRStatus status = CR_OK;
+        ParsingContext *ctxt = NULL;
+        ParsingContext **ctxtptr = NULL;
+        CRStatement *stmt = NULL;
+
+        (void) a_page;
+        (void) a_pseudo_page;
+
+        g_return_if_fail (a_this);
+
+	ctxtptr = &ctxt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+
+        g_return_if_fail (status == CR_OK && ctxt);
+
+        g_return_if_fail (ctxt->cur_stmt
+                          && ctxt->cur_stmt->type == AT_PAGE_RULE_STMT
+                          && ctxt->stylesheet);
+
+        stmt = cr_statement_append (ctxt->stylesheet->statements,
+                                    ctxt->cur_stmt);
+
+        if (stmt) {
+                ctxt->stylesheet->statements = stmt;
+                stmt = NULL;
+                ctxt->cur_stmt = NULL;
+        }
+
+        if (ctxt->cur_stmt) {
+                cr_statement_destroy (ctxt->cur_stmt);
+                ctxt->cur_stmt = NULL;
+        }
+        a_page = NULL;          /*keep compiler happy */
+        a_pseudo_page = NULL;   /*keep compiler happy */
+}
+
+static void
+start_media (CRDocHandler * a_this, 
+             GList * a_media_list,
+             CRParsingLocation *a_location)
+{
+        enum CRStatus status = CR_OK;
+        ParsingContext *ctxt = NULL;
+        ParsingContext **ctxtptr = NULL;
+        GList *media_list = NULL;
+
+        g_return_if_fail (a_this);
+	ctxtptr = &ctxt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+        g_return_if_fail (status == CR_OK && ctxt);
+
+        g_return_if_fail (ctxt
+                          && ctxt->cur_stmt == NULL
+                          && ctxt->cur_media_stmt == NULL
+                          && ctxt->stylesheet);
+        if (a_media_list) {
+                /*duplicate the media_list */
+                media_list = cr_utils_dup_glist_of_cr_string 
+                        (a_media_list);
+        }
+        ctxt->cur_media_stmt =
+                cr_statement_new_at_media_rule
+                (ctxt->stylesheet, NULL, media_list);
+
+}
+
+static void
+end_media (CRDocHandler * a_this, GList * a_media_list)
+{
+        enum CRStatus status = CR_OK;
+        ParsingContext *ctxt = NULL;
+        ParsingContext **ctxtptr = NULL;
+        CRStatement *stmts = NULL;
+
+        (void) a_media_list;
+
+        g_return_if_fail (a_this);
+
+	ctxtptr = &ctxt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+
+        g_return_if_fail (status == CR_OK && ctxt);
+
+        g_return_if_fail (ctxt
+                          && ctxt->cur_media_stmt
+                          && ctxt->cur_media_stmt->type == AT_MEDIA_RULE_STMT
+                          && ctxt->stylesheet);
+
+        stmts = cr_statement_append (ctxt->stylesheet->statements,
+                                     ctxt->cur_media_stmt);
+
+        if (!stmts) {
+                cr_statement_destroy (ctxt->cur_media_stmt);
+                ctxt->cur_media_stmt = NULL;
+        }
+
+        ctxt->stylesheet->statements = stmts;
+        stmts = NULL;
+
+        ctxt->cur_stmt = NULL ;
+        ctxt->cur_media_stmt = NULL ;
+        a_media_list = NULL;
+}
+
+static void
+import_style (CRDocHandler * a_this, 
+              GList * a_media_list,
+              CRString * a_uri, 
+              CRString * a_uri_default_ns,
+              CRParsingLocation *a_location)
+{
+        enum CRStatus status = CR_OK;
+        CRString *uri = NULL;
+        CRStatement *stmt = NULL,
+                *stmt2 = NULL;
+        ParsingContext *ctxt = NULL;
+        ParsingContext **ctxtptr = NULL;
+        GList *media_list = NULL ;
+
+        (void) a_uri_default_ns;
+
+        g_return_if_fail (a_this);
+
+	ctxtptr = &ctxt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+
+        g_return_if_fail (status == CR_OK && ctxt);
+
+        g_return_if_fail (ctxt->stylesheet);
+
+        uri = cr_string_dup (a_uri) ;
+
+        if (a_media_list)
+                media_list = cr_utils_dup_glist_of_cr_string (a_media_list) ;
+
+        stmt = cr_statement_new_at_import_rule
+                (ctxt->stylesheet, uri, media_list, NULL);
+
+        if (!stmt)
+                goto error;
+
+        if (ctxt->cur_stmt) {
+                stmt2 = cr_statement_append (ctxt->cur_stmt, stmt);
+                if (!stmt2)
+                        goto error;
+                ctxt->cur_stmt = stmt2;
+                stmt2 = NULL;
+                stmt = NULL;
+        } else {
+                stmt2 = cr_statement_append (ctxt->stylesheet->statements,
+                                             stmt);
+                if (!stmt2)
+                        goto error;
+                ctxt->stylesheet->statements = stmt2;
+                stmt2 = NULL;
+                stmt = NULL;
+        }
+
+        return;
+
+      error:
+        if (uri) {
+                cr_string_destroy (uri);
+        }
+
+        if (stmt) {
+                cr_statement_destroy (stmt);
+                stmt = NULL;
+        }
+        a_uri_default_ns = NULL; /*keep compiler happy */
+}
+
+static void
+start_selector (CRDocHandler * a_this, CRSelector * a_selector_list)
+{
+        enum CRStatus status = CR_OK ;
+        ParsingContext *ctxt = NULL;
+        ParsingContext **ctxtptr = NULL;
+
+        g_return_if_fail (a_this);
+	ctxtptr = &ctxt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+        g_return_if_fail (status == CR_OK && ctxt);
+        if (ctxt->cur_stmt) {
+                /*hmm, this should be NULL so free it */
+                cr_statement_destroy (ctxt->cur_stmt);
+                ctxt->cur_stmt = NULL;
+        }
+
+        ctxt->cur_stmt = cr_statement_new_ruleset
+                (ctxt->stylesheet, a_selector_list, NULL, NULL);
+}
+
+static void
+end_selector (CRDocHandler * a_this, CRSelector * a_selector_list)
+{
+        enum CRStatus status = CR_OK;
+        ParsingContext *ctxt = NULL;
+        ParsingContext **ctxtptr = NULL;
+
+        (void) a_selector_list;
+
+        g_return_if_fail (a_this);
+
+	ctxtptr = &ctxt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+
+        g_return_if_fail (status == CR_OK && ctxt);
+
+        g_return_if_fail (ctxt->cur_stmt && ctxt->stylesheet);
+
+        if (ctxt->cur_stmt) {
+                CRStatement *stmts = NULL;
+
+                if (ctxt->cur_media_stmt) {
+                        CRAtMediaRule *media_rule = NULL;
+
+                        media_rule = ctxt->cur_media_stmt->kind.media_rule;
+
+                        stmts = cr_statement_append
+                                (media_rule->rulesets, ctxt->cur_stmt);
+
+                        if (!stmts) {
+                                cr_utils_trace_info
+                                        ("Could not append a new statement");
+                                cr_statement_destroy (media_rule->rulesets);
+                                ctxt->cur_media_stmt->
+                                        kind.media_rule->rulesets = NULL;
+                                return;
+                        }
+                        media_rule->rulesets = stmts;
+                        ctxt->cur_stmt = NULL;
+                } else {
+                        stmts = cr_statement_append
+                                (ctxt->stylesheet->statements,
+                                 ctxt->cur_stmt);
+                        if (!stmts) {
+                                cr_utils_trace_info
+                                        ("Could not append a new statement");
+                                cr_statement_destroy (ctxt->cur_stmt);
+                                ctxt->cur_stmt = NULL;
+                                return;
+                        }
+                        ctxt->stylesheet->statements = stmts;
+                        ctxt->cur_stmt = NULL;
+                }
+
+        }
+
+        a_selector_list = NULL; /*keep compiler happy */
+}
+
+static void
+property (CRDocHandler * a_this,
+          CRString * a_name, 
+          CRTerm * a_expression, 
+          gboolean a_important)
+{
+        enum CRStatus status = CR_OK;
+        ParsingContext *ctxt = NULL;
+        ParsingContext **ctxtptr = NULL;
+        CRDeclaration *decl = NULL,
+                *decl2 = NULL;
+        CRString *str = NULL;
+
+        g_return_if_fail (a_this);
+	ctxtptr = &ctxt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+        g_return_if_fail (status == CR_OK && ctxt);
+
+        /*
+         *make sure a current ruleset statement has been allocated
+         *already.
+         */
+        g_return_if_fail
+                (ctxt->cur_stmt
+                 &&
+                 (ctxt->cur_stmt->type == RULESET_STMT
+                  || ctxt->cur_stmt->type == AT_FONT_FACE_RULE_STMT
+                  || ctxt->cur_stmt->type == AT_PAGE_RULE_STMT));
+
+        if (a_name) {
+                str = cr_string_dup (a_name);
+                g_return_if_fail (str);
+        }
+
+        /*instanciates a new declaration */
+        decl = cr_declaration_new (ctxt->cur_stmt, str, a_expression);
+        g_return_if_fail (decl);
+        str = NULL;
+        decl->important = a_important;
+        /*
+         *add the new declaration to the current statement
+         *being build.
+         */
+        switch (ctxt->cur_stmt->type) {
+        case RULESET_STMT:
+                decl2 = cr_declaration_append
+                        (ctxt->cur_stmt->kind.ruleset->decl_list, decl);
+                if (!decl2) {
+                        cr_declaration_destroy (decl);
+                        cr_utils_trace_info
+                                ("Could not append decl to ruleset");
+                        goto error;
+                }
+                ctxt->cur_stmt->kind.ruleset->decl_list = decl2;
+                decl = NULL;
+                decl2 = NULL;
+                break;
+
+        case AT_FONT_FACE_RULE_STMT:
+                decl2 = cr_declaration_append
+                        (ctxt->cur_stmt->kind.font_face_rule->decl_list,
+                         decl);
+                if (!decl2) {
+                        cr_declaration_destroy (decl);
+                        cr_utils_trace_info
+                                ("Could not append decl to ruleset");
+                        goto error;
+                }
+                ctxt->cur_stmt->kind.font_face_rule->decl_list = decl2;
+                decl = NULL;
+                decl2 = NULL;
+                break;
+        case AT_PAGE_RULE_STMT:
+                decl2 = cr_declaration_append
+                        (ctxt->cur_stmt->kind.page_rule->decl_list, decl);
+                if (!decl2) {
+                        cr_declaration_destroy (decl);
+                        cr_utils_trace_info
+                                ("Could not append decl to ruleset");
+                        goto error;
+                }
+                ctxt->cur_stmt->kind.page_rule->decl_list = decl2;
+                decl = NULL;
+                decl2 = NULL;
+                break;
+
+        default:
+                goto error;
+                break;
+        }
+
+        return;
+
+      error:
+        if (str) {
+                g_free (str);
+                str = NULL;
+        }
+
+        if (decl) {
+                cr_declaration_destroy (decl);
+                decl = NULL;
+        }
+}
+
+static void
+error (CRDocHandler * a_this)
+{
+        enum CRStatus status = CR_OK;
+        ParsingContext *ctxt = NULL;
+        ParsingContext **ctxtptr = NULL;
+
+        g_return_if_fail (a_this);
+	ctxtptr = &ctxt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+        g_return_if_fail (status == CR_OK && ctxt);
+
+        if (ctxt->cur_stmt) {
+                cr_statement_destroy (ctxt->cur_stmt);
+                ctxt->cur_stmt = NULL;
+        }
+}
+
+static void
+unrecoverable_error (CRDocHandler * a_this)
+{
+        enum CRStatus status = CR_OK;
+        ParsingContext *ctxt = NULL;
+        ParsingContext **ctxtptr = NULL;
+
+	ctxtptr = &ctxt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+        g_return_if_fail (status == CR_OK);
+
+        if (ctxt) {
+                if (ctxt->stylesheet) {
+                        status = cr_doc_handler_set_result
+                                (a_this, ctxt->stylesheet);
+                        g_return_if_fail (status == CR_OK);
+                }
+                g_free (ctxt);
+                cr_doc_handler_set_ctxt (a_this, NULL);
+        }
+}
+
+/********************************************
+ *Public methods
+ ********************************************/
+
+/**
+ * cr_om_parser_new:
+ *@a_input: the input stream.
+ *
+ *Constructor of the CROMParser.
+ *Returns the newly built instance of #CROMParser.
+ */
+CROMParser *
+cr_om_parser_new (CRInput * a_input)
+{
+        CROMParser *result = NULL;
+        enum CRStatus status = CR_OK;
+
+        result = g_try_malloc (sizeof (CROMParser));
+
+        if (!result) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+
+        memset (result, 0, sizeof (CROMParser));
+        PRIVATE (result) = g_try_malloc (sizeof (CROMParserPriv));
+
+        if (!PRIVATE (result)) {
+                cr_utils_trace_info ("Out of memory");
+                goto error;
+        }
+
+        memset (PRIVATE (result), 0, sizeof (CROMParserPriv));
+
+        PRIVATE (result)->parser = cr_parser_new_from_input (a_input);
+
+        if (!PRIVATE (result)->parser) {
+                cr_utils_trace_info ("parsing instantiation failed");
+                goto error;
+        }
+
+        status = cr_om_parser_init_default_sac_handler (result);
+
+        if (status != CR_OK) {
+                goto error;
+        }
+
+        return result;
+
+      error:
+
+        if (result) {
+                cr_om_parser_destroy (result);
+        }
+
+        return NULL;
+}
+
+/**
+ * cr_om_parser_parse_buf:
+ *@a_this: the current instance of #CROMParser.
+ *@a_buf: the in memory buffer to parse.
+ *@a_len: the length of the in memory buffer in number of bytes.
+ *@a_enc: the encoding of the in memory buffer.
+ *@a_result: out parameter the resulting style sheet
+ *
+ *Parses the content of an in memory  buffer.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_om_parser_parse_buf (CROMParser * a_this,
+                        const guchar * a_buf,
+                        gulong a_len,
+                        enum CREncoding a_enc, CRStyleSheet ** a_result)
+{
+
+        enum CRStatus status = CR_OK;
+
+        g_return_val_if_fail (a_this && a_result, CR_BAD_PARAM_ERROR);
+
+        if (!PRIVATE (a_this)->parser) {
+                PRIVATE (a_this)->parser = cr_parser_new (NULL);
+        }
+
+        status = cr_parser_parse_buf (PRIVATE (a_this)->parser,
+                                      a_buf, a_len, a_enc);
+
+        if (status == CR_OK) {
+                CRStyleSheet *result = NULL;
+                CRStyleSheet **resultptr = NULL;
+                CRDocHandler *sac_handler = NULL;
+
+                cr_parser_get_sac_handler (PRIVATE (a_this)->parser,
+                                           &sac_handler);
+                g_return_val_if_fail (sac_handler, CR_ERROR);
+		resultptr = &result;
+                status = cr_doc_handler_get_result (sac_handler,
+                                                    (gpointer *) resultptr);
+                g_return_val_if_fail (status == CR_OK, status);
+
+                if (result)
+                        *a_result = result;
+        }
+
+        return status;
+}
+
+/**
+ * cr_om_parser_simply_parse_buf:
+ *@a_buf: the css2 in memory buffer.
+ *@a_len: the length of the in memory buffer.
+ *@a_enc: the encoding of the in memory buffer.
+ *@a_result: out parameter. The resulting css2 style sheet.
+ *
+ *The simpler way to parse an in memory css2 buffer.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_om_parser_simply_parse_buf (const guchar * a_buf,
+                               gulong a_len,
+                               enum CREncoding a_enc,
+                               CRStyleSheet ** a_result)
+{
+        CROMParser *parser = NULL;
+        enum CRStatus status = CR_OK;
+
+        parser = cr_om_parser_new (NULL);
+        if (!parser) {
+                cr_utils_trace_info ("Could not create om parser");
+                cr_utils_trace_info ("System possibly out of memory");
+                return CR_ERROR;
+        }
+
+        status = cr_om_parser_parse_buf (parser, a_buf, a_len,
+                                         a_enc, a_result);
+
+        if (parser) {
+                cr_om_parser_destroy (parser);
+                parser = NULL;
+        }
+
+        return status;
+}
+
+/**
+ * cr_om_parser_parse_file:
+ *@a_this: the current instance of the cssom parser.
+ *@a_file_uri: the uri of the file. 
+ *(only local file paths are suppported so far)
+ *@a_enc: the encoding of the file.
+ *@a_result: out parameter. A pointer 
+ *the build css object model.
+ *
+ *Parses a css2 stylesheet contained
+ *in a file.
+ *
+ * Returns CR_OK upon succesful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_om_parser_parse_file (CROMParser * a_this,
+                         const guchar * a_file_uri,
+                         enum CREncoding a_enc, CRStyleSheet ** a_result)
+{
+        enum CRStatus status = CR_OK;
+
+        g_return_val_if_fail (a_this && a_file_uri && a_result,
+                              CR_BAD_PARAM_ERROR);
+
+        if (!PRIVATE (a_this)->parser) {
+                PRIVATE (a_this)->parser = cr_parser_new_from_file
+                        (a_file_uri, a_enc);
+        }
+
+        status = cr_parser_parse_file (PRIVATE (a_this)->parser,
+                                       a_file_uri, a_enc);
+
+        if (status == CR_OK) {
+                CRStyleSheet *result = NULL;
+                CRStyleSheet **resultptr = NULL;
+                CRDocHandler *sac_handler = NULL;
+
+                cr_parser_get_sac_handler (PRIVATE (a_this)->parser,
+                                           &sac_handler);
+                g_return_val_if_fail (sac_handler, CR_ERROR);
+		resultptr = &result;
+                status = cr_doc_handler_get_result
+                        (sac_handler, (gpointer *) resultptr);
+                g_return_val_if_fail (status == CR_OK, status);
+                if (result)
+                        *a_result = result;
+        }
+
+        return status;
+}
+
+/**
+ * cr_om_parser_simply_parse_file:
+ *@a_file_path: the css2 local file path.
+ *@a_enc: the file encoding.
+ *@a_result: out parameter. The returned css stylesheet.
+ *Must be freed by the caller using cr_stylesheet_destroy.
+ *
+ *The simpler method to parse a css2 file.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ *Note that this method uses cr_om_parser_parse_file() so both methods
+ *have the same return values.
+ */
+enum CRStatus
+cr_om_parser_simply_parse_file (const guchar * a_file_path,
+                                enum CREncoding a_enc,
+                                CRStyleSheet ** a_result)
+{
+        CROMParser *parser = NULL;
+        enum CRStatus status = CR_OK;
+
+        parser = cr_om_parser_new (NULL);
+        if (!parser) {
+                cr_utils_trace_info ("Could not allocate om parser");
+                cr_utils_trace_info ("System may be out of memory");
+                return CR_ERROR;
+        }
+
+        status = cr_om_parser_parse_file (parser, a_file_path,
+                                          a_enc, a_result);
+        if (parser) {
+                cr_om_parser_destroy (parser);
+                parser = NULL;
+        }
+
+        return status;
+}
+
+/**
+ * cr_om_parser_parse_paths_to_cascade:
+ *@a_this: the current instance of #CROMParser
+ *@a_author_path: the path to the author stylesheet
+ *@a_user_path: the path to the user stylesheet
+ *@a_ua_path: the path to the User Agent stylesheet
+ *@a_encoding: the encoding of the sheets.
+ *@a_result: out parameter. The resulting cascade if the parsing
+ *was okay
+ *
+ *Parses three sheets located by their paths and build a cascade
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise
+ */
+enum CRStatus
+cr_om_parser_parse_paths_to_cascade (CROMParser * a_this,
+                                     const guchar * a_author_path,
+                                     const guchar * a_user_path,
+                                     const guchar * a_ua_path,
+                                     enum CREncoding a_encoding,
+                                     CRCascade ** a_result)
+{
+        enum CRStatus status = CR_OK;
+
+        /*0->author sheet, 1->user sheet, 2->UA sheet */
+        CRStyleSheet *sheets[3];
+        guchar *paths[3];
+        CRCascade *result = NULL;
+        gint i = 0;
+
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        memset (sheets, 0, sizeof (CRStyleSheet*) * 3);
+        paths[0] = (guchar *) a_author_path;
+        paths[1] = (guchar *) a_user_path;
+        paths[2] = (guchar *) a_ua_path;
+
+        for (i = 0; i < 3; i++) {
+                status = cr_om_parser_parse_file (a_this, paths[i],
+                                                  a_encoding, &sheets[i]);
+                if (status != CR_OK) {
+                        if (sheets[i]) {
+                                cr_stylesheet_unref (sheets[i]);
+                                sheets[i] = NULL;
+                        }
+                        continue;
+                }
+        }
+        result = cr_cascade_new (sheets[0], sheets[1], sheets[2]);
+        if (!result) {
+                for (i = 0; i < 3; i++) {
+                        cr_stylesheet_unref (sheets[i]);
+                        sheets[i] = 0;
+                }
+                return CR_ERROR;
+        }
+        *a_result = result;
+        return CR_OK;
+}
+
+/**
+ * cr_om_parser_simply_parse_paths_to_cascade:
+ *@a_author_path: the path to the author stylesheet
+ *@a_user_path: the path to the user stylesheet
+ *@a_ua_path: the path to the User Agent stylesheet
+ *@a_encoding: the encoding of the sheets.
+ *@a_result: out parameter. The resulting cascade if the parsing
+ *was okay
+ *
+ *Parses three sheets located by their paths and build a cascade
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise
+ */
+enum CRStatus
+cr_om_parser_simply_parse_paths_to_cascade (const guchar * a_author_path,
+                                            const guchar * a_user_path,
+                                            const guchar * a_ua_path,
+                                            enum CREncoding a_encoding,
+                                            CRCascade ** a_result)
+{
+        enum CRStatus status = CR_OK;
+        CROMParser *parser = NULL;
+
+        parser = cr_om_parser_new (NULL);
+        if (!parser) {
+                cr_utils_trace_info ("could not allocated om parser");
+                cr_utils_trace_info ("System may be out of memory");
+                return CR_ERROR;
+        }
+        status = cr_om_parser_parse_paths_to_cascade (parser,
+                                                      a_author_path,
+                                                      a_user_path,
+                                                      a_ua_path,
+                                                      a_encoding, a_result);
+        if (parser) {
+                cr_om_parser_destroy (parser);
+                parser = NULL;
+        }
+        return status;
+}
+
+/**
+ * cr_om_parser_destroy:
+ *@a_this: the current instance of #CROMParser.
+ *
+ *Destructor of the #CROMParser.
+ */
+void
+cr_om_parser_destroy (CROMParser * a_this)
+{
+        g_return_if_fail (a_this && PRIVATE (a_this));
+
+        if (PRIVATE (a_this)->parser) {
+                cr_parser_destroy (PRIVATE (a_this)->parser);
+                PRIVATE (a_this)->parser = NULL;
+        }
+
+        if (PRIVATE (a_this)) {
+                g_free (PRIVATE (a_this));
+                PRIVATE (a_this) = NULL;
+        }
+
+        if (a_this) {
+                g_free (a_this);
+                a_this = NULL;
+        }
+}
diff --git a/src/st/croco/cr-om-parser.h b/src/st/croco/cr-om-parser.h
new file mode 100644
index 000000000..13d35b1cd
--- /dev/null
+++ b/src/st/croco/cr-om-parser.h
@@ -0,0 +1,98 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * Copyright (C) 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the 
+ * GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*
+ *$Id$
+ */
+
+#ifndef __CR_OM_PARSER_H__
+#define __CR_OM_PARSER_H__
+
+#include "cr-parser.h"
+#include "cr-cascade.h"
+
+
+/**
+ *@file
+ *The definition of the CSS Object Model Parser.
+ *This parser uses (and sits) the SAC api of libcroco defined
+ *in cr-parser.h and cr-doc-handler.h
+ */
+
+G_BEGIN_DECLS
+
+typedef struct _CROMParser CROMParser ;
+typedef struct _CROMParserPriv CROMParserPriv ;
+
+/**
+ *The Object model parser.
+ *Can parse a css file and build a css object model.
+ *This parser uses an instance of #CRParser and defines
+ *a set of SAC callbacks to build the Object Model.
+ */
+struct _CROMParser
+{
+        CROMParserPriv *priv ;
+} ;
+
+CROMParser * cr_om_parser_new (CRInput *a_input) ;
+
+
+enum CRStatus cr_om_parser_simply_parse_file (const guchar *a_file_path,
+                                              enum CREncoding a_enc,
+                                              CRStyleSheet **a_result) ;
+
+enum CRStatus cr_om_parser_parse_file (CROMParser *a_this,
+                                       const guchar *a_file_uri,
+                                       enum CREncoding a_enc,
+                                       CRStyleSheet **a_result) ;
+
+enum CRStatus cr_om_parser_simply_parse_buf (const guchar *a_buf,
+                                             gulong a_len,
+                                             enum CREncoding a_enc,
+                                             CRStyleSheet **a_result) ;
+
+enum CRStatus cr_om_parser_parse_buf (CROMParser *a_this,
+                                      const guchar *a_buf,
+                                      gulong a_len,
+                                      enum CREncoding a_enc,
+                                      CRStyleSheet **a_result) ;
+
+enum CRStatus cr_om_parser_parse_paths_to_cascade (CROMParser *a_this,
+                                                   const guchar *a_author_path,
+                                                   const guchar *a_user_path,
+                                                   const guchar *a_ua_path,
+                                                   enum CREncoding a_encoding,
+                                                   CRCascade ** a_result) ;
+
+enum CRStatus cr_om_parser_simply_parse_paths_to_cascade (const guchar *a_author_path,
+                                                          const guchar *a_user_path,
+                                                          const guchar *a_ua_path,
+                                                          enum CREncoding a_encoding,
+                                                          CRCascade ** a_result) ;
+
+void cr_om_parser_destroy (CROMParser *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_OM_PARSER_H__*/
diff --git a/src/st/croco/cr-parser.c b/src/st/croco/cr-parser.c
new file mode 100644
index 000000000..07f4ed9e8
--- /dev/null
+++ b/src/st/croco/cr-parser.c
@@ -0,0 +1,4525 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the 
+ * GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyrights information.
+ */
+
+/**
+ *@CRParser:
+ *
+ *The definition of the #CRParser class.
+ */
+
+#include "string.h"
+#include "cr-parser.h"
+#include "cr-num.h"
+#include "cr-term.h"
+#include "cr-simple-sel.h"
+#include "cr-attr-sel.h"
+
+/*
+ *Random notes: 
+ *CSS core syntax vs CSS level 2 syntax
+ *=====================================
+ *
+ *One must keep in mind
+ *that css UA must comply with two syntaxes.
+ *
+ *1/the specific syntax that defines the css language
+ *for a given level of specificatin (e.g css2 syntax
+ *defined in appendix D.1 of the css2 spec)
+ *
+ *2/the core (general) syntax that is there to allow
+ *UAs to parse style sheets written in levels of CSS that
+ *didn't exist at the time the UAs were created.
+ *
+ *the name  of parsing functions (or methods) contained in this  file
+ *follows the following scheme: cr_parser_parse_<production_name> (...) ;
+ *where <production_name> is the name 
+ *of a production of the css2 language.
+ *When a given production is 
+ *defined by the css2 level grammar *and* by the
+ *css core syntax, there will be two functions to parse that production:
+ *one will parse the production defined by the css2 level grammar and the
+ *other will parse the production defined by the css core grammar.
+ *The css2 level grammar related parsing function will be called:
+ *cr_parser_parse_<production_name> (...) ;
+ *Then css core grammar related parsing function will be called:
+ *cr_parser_parse_<production_name>_core (...) ;
+ *
+ *If a production is defined only by the css core grammar, then
+ *it will be named:
+ *cr_parser_parse_<production_name>_core (...) ;
+ */
+
+typedef struct _CRParserError CRParserError;
+
+/**
+ *An abstraction of an error reported by by the
+ *parsing routines.
+ */
+struct _CRParserError {
+        guchar *msg;
+        enum CRStatus status;
+        glong line;
+        glong column;
+        glong byte_num;
+};
+
+enum CRParserState {
+        READY_STATE = 0,
+        TRY_PARSE_CHARSET_STATE,
+        CHARSET_PARSED_STATE,
+        TRY_PARSE_IMPORT_STATE,
+        IMPORT_PARSED_STATE,
+        TRY_PARSE_RULESET_STATE,
+        RULESET_PARSED_STATE,
+        TRY_PARSE_MEDIA_STATE,
+        MEDIA_PARSED_STATE,
+        TRY_PARSE_PAGE_STATE,
+        PAGE_PARSED_STATE,
+        TRY_PARSE_FONT_FACE_STATE,
+        FONT_FACE_PARSED_STATE
+} ;
+
+/**
+ *The private attributes of
+ *#CRParser.
+ */
+struct _CRParserPriv {
+        /**
+         *The tokenizer
+         */
+        CRTknzr *tknzr;
+
+        /**
+         *The sac handlers to call
+         *to notify the parsing of
+         *the css2 constructions.
+         */
+        CRDocHandler *sac_handler;
+
+        /**
+         *A stack of errors reported
+         *by the parsing routines.
+         *Contains instance of #CRParserError.
+         *This pointer is the top of the stack.
+         */
+        GList *err_stack;
+
+        enum CRParserState state;
+        gboolean resolve_import;
+        gboolean is_case_sensitive;
+        gboolean use_core_grammar;
+};
+
+#define PRIVATE(obj) ((obj)->priv)
+
+#define CHARS_TAB_SIZE 12
+
+/**
+ * IS_NUM:
+ *@a_char: the char to test.
+ *return TRUE if the character is a number ([0-9]), FALSE otherwise
+ */
+#define IS_NUM(a_char) (((a_char) >= '0' && (a_char) <= '9')?TRUE:FALSE)
+
+/**
+ *Checks if 'status' equals CR_OK. If not, goto the 'error' label.
+ *
+ *@param status the status (of type enum CRStatus) to test.
+ *@param is_exception if set to FALSE, the final status returned 
+ *by the current function will be CR_PARSING_ERROR. If set to TRUE, the
+ *current status will be the current value of the 'status' variable.
+ *
+ */
+#define CHECK_PARSING_STATUS(status, is_exception) \
+if ((status) != CR_OK) \
+{ \
+        if (is_exception == FALSE) \
+        { \
+                status = CR_PARSING_ERROR ; \
+        } \
+        goto error ; \
+}
+
+/**
+ * CHECK_PARSING_STATUS_ERR:
+ *@a_this: the current instance of #CRParser .
+ *@a_status: the status to check. Is of type enum #CRStatus.
+ *@a_is_exception: in case of error, if is TRUE, the status
+ *is set to CR_PARSING_ERROR before goto error. If is false, the
+ *real low level status is kept and will be returned by the
+ *upper level function that called this macro. Usally,this must
+ *be set to FALSE.
+ *
+ *same as CHECK_PARSING_STATUS() but this one pushes an error
+ *on the parser error stack when an error arises.
+ *
+ */
+#define CHECK_PARSING_STATUS_ERR(a_this, a_status, a_is_exception,\
+                                 a_err_msg, a_err_status) \
+if ((a_status) != CR_OK) \
+{ \
+        if (a_is_exception == FALSE) a_status = CR_PARSING_ERROR ; \
+        cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \
+        goto error ; \
+}
+
+/**
+ *Peeks the next char from the input stream of the current parser
+ *by invoking cr_tknzr_input_peek_char().
+ *invokes CHECK_PARSING_STATUS on the status returned by
+ *cr_tknzr_peek_char().
+ *
+ *@param a_this the current instance of #CRParser.
+ *@param a_to_char a pointer to the char where to store the
+ *char peeked.
+ */
+#define PEEK_NEXT_CHAR(a_this, a_to_char) \
+{\
+status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, a_to_char) ; \
+CHECK_PARSING_STATUS (status, TRUE) \
+}
+
+/**
+ *Reads the next char from the input stream of the current parser.
+ *In case of error, jumps to the "error:" label located in the
+ *function where this macro is called.
+ *@param a_this the curent instance of #CRParser
+ *@param to_char a pointer to the guint32 char where to store
+ *the character read.
+ */
+#define READ_NEXT_CHAR(a_this, a_to_char) \
+status = cr_tknzr_read_char (PRIVATE (a_this)->tknzr, a_to_char) ; \
+CHECK_PARSING_STATUS (status, TRUE)
+
+/**
+ *Gets information about the current position in
+ *the input of the parser.
+ *In case of failure, this macro returns from the 
+ *calling function and
+ *returns a status code of type enum #CRStatus.
+ *@param a_this the current instance of #CRParser.
+ *@param a_pos out parameter. A pointer to the position 
+ *inside the current parser input. Must
+ */
+#define RECORD_INITIAL_POS(a_this, a_pos) \
+status = cr_tknzr_get_cur_pos (PRIVATE \
+(a_this)->tknzr, a_pos) ; \
+g_return_val_if_fail (status == CR_OK, status)
+
+/**
+ *Gets the address of the current byte inside the
+ *parser input.
+ *@param parser the current instance of #CRParser.
+ *@param addr out parameter a pointer (guchar*)
+ *to where the address  must be put.
+ */
+#define RECORD_CUR_BYTE_ADDR(a_this, a_addr) \
+status = cr_tknzr_get_cur_byte_addr \
+            (PRIVATE (a_this)->tknzr, a_addr) ; \
+CHECK_PARSING_STATUS (status, TRUE)
+
+/**
+ *Peeks a byte from the topmost parser input at
+ *a given offset from the current position.
+ *If it fails, goto the "error:" label.
+ *
+ *@param a_parser the current instance of #CRParser.
+ *@param a_offset the offset of the byte to peek, the
+ *current byte having the offset '0'.
+ *@param a_byte_ptr out parameter a pointer (guchar*) to
+ *where the peeked char is to be stored.
+ */
+#define PEEK_BYTE(a_parser, a_offset, a_byte_ptr) \
+status = cr_tknzr_peek_byte (PRIVATE (a_this)->tknzr, \
+                              a_offset, \
+                              a_byte_ptr) ; \
+CHECK_PARSING_STATUS (status, TRUE) ;
+
+#define BYTE(a_parser, a_offset, a_eof) \
+cr_tknzr_peek_byte2 (PRIVATE (a_this)->tknzr, a_offset, a_eof)
+
+/**
+ *Reads a byte from the topmost parser input
+ *steam.
+ *If it fails, goto the "error" label.
+ *@param a_this the current instance of #CRParser.
+ *@param a_byte_ptr the guchar * where to put the read char.
+ */
+#define READ_NEXT_BYTE(a_this, a_byte_ptr) \
+status = cr_tknzr_read_byte (PRIVATE (a_this)->tknzr, a_byte_ptr) ; \
+CHECK_PARSING_STATUS (status, TRUE) ;
+
+/**
+ *Skips a given number of byte in the topmost
+ *parser input. Don't update line and column number.
+ *In case of error, jumps to the "error:" label
+ *of the surrounding function.
+ *@param a_parser the current instance of #CRParser.
+ *@param a_nb_bytes the number of bytes to skip.
+ */
+#define SKIP_BYTES(a_this, a_nb_bytes) \
+status = cr_tknzr_seek_index (PRIVATE (a_this)->tknzr, \
+                                        CR_SEEK_CUR, a_nb_bytes) ; \
+CHECK_PARSING_STATUS (status, TRUE) ;
+
+/**
+ *Skip utf8 encoded characters.
+ *Updates line and column numbers.
+ *@param a_parser the current instance of #CRParser.
+ *@param a_nb_chars the number of chars to skip. Must be of
+ *type glong.
+ */
+#define SKIP_CHARS(a_parser, a_nb_chars) \
+{ \
+glong nb_chars = a_nb_chars ; \
+status = cr_tknzr_consume_chars \
+     (PRIVATE (a_parser)->tknzr,0, &nb_chars) ; \
+CHECK_PARSING_STATUS (status, TRUE) ; \
+}
+
+/**
+ *Tests the condition and if it is false, sets
+ *status to "CR_PARSING_ERROR" and goto the 'error'
+ *label.
+ *@param condition the condition to test.
+ */
+#define ENSURE_PARSING_COND(condition) \
+if (! (condition)) {status = CR_PARSING_ERROR; goto error ;}
+
+#define ENSURE_PARSING_COND_ERR(a_this, a_condition, \
+                                a_err_msg, a_err_status) \
+if (! (a_condition)) \
+{ \
+        status = CR_PARSING_ERROR; \
+        cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \
+        goto error ; \
+}
+
+#define GET_NEXT_TOKEN(a_this, a_token_ptr) \
+status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, \
+                                  a_token_ptr) ; \
+ENSURE_PARSING_COND (status == CR_OK) ;
+
+#ifdef WITH_UNICODE_ESCAPE_AND_RANGE
+static enum CRStatus cr_parser_parse_unicode_escape (CRParser * a_this,
+                                                     guint32 * a_unicode);
+static enum CRStatus cr_parser_parse_escape (CRParser * a_this,
+                                             guint32 * a_esc_code);
+
+static enum CRStatus cr_parser_parse_unicode_range (CRParser * a_this,
+                                                    CRString ** a_inf,
+                                                    CRString ** a_sup);
+#endif
+
+static enum CRStatus cr_parser_parse_stylesheet_core (CRParser * a_this);
+
+static enum CRStatus cr_parser_parse_atrule_core (CRParser * a_this);
+
+static enum CRStatus cr_parser_parse_ruleset_core (CRParser * a_this);
+
+static enum CRStatus cr_parser_parse_selector_core (CRParser * a_this);
+
+static enum CRStatus cr_parser_parse_declaration_core (CRParser * a_this);
+
+static enum CRStatus cr_parser_parse_any_core (CRParser * a_this);
+
+static enum CRStatus cr_parser_parse_block_core (CRParser * a_this);
+
+static enum CRStatus cr_parser_parse_value_core (CRParser * a_this);
+
+static enum CRStatus cr_parser_parse_string (CRParser * a_this,
+                                             CRString ** a_str);
+
+static enum CRStatus cr_parser_parse_ident (CRParser * a_this,
+                                            CRString ** a_str);
+
+static enum CRStatus cr_parser_parse_uri (CRParser * a_this,
+                                          CRString ** a_str);
+
+static enum CRStatus cr_parser_parse_function (CRParser * a_this,
+                                               CRString ** a_func_name,
+                                               CRTerm ** a_expr);
+static enum CRStatus cr_parser_parse_property (CRParser * a_this,
+                                               CRString ** a_property);
+
+static enum CRStatus cr_parser_parse_attribute_selector (CRParser * a_this,
+                                                         CRAttrSel ** a_sel);
+
+static enum CRStatus cr_parser_parse_simple_selector (CRParser * a_this,
+                                                      CRSimpleSel ** a_sel);
+
+static enum CRStatus cr_parser_parse_simple_sels (CRParser * a_this,
+                                                  CRSimpleSel ** a_sel);
+
+static CRParserError *cr_parser_error_new (const guchar * a_msg,
+                                           enum CRStatus);
+
+static void cr_parser_error_set_msg (CRParserError * a_this,
+                                     const guchar * a_msg);
+
+static void cr_parser_error_dump (CRParserError * a_this);
+
+static void cr_parser_error_set_status (CRParserError * a_this,
+                                        enum CRStatus a_status);
+
+static void cr_parser_error_set_pos (CRParserError * a_this,
+                                     glong a_line,
+                                     glong a_column, glong a_byte_num);
+static void
+  cr_parser_error_destroy (CRParserError * a_this);
+
+static enum CRStatus cr_parser_push_error (CRParser * a_this,
+                                           const guchar * a_msg,
+                                           enum CRStatus a_status);
+
+static enum CRStatus cr_parser_dump_err_stack (CRParser * a_this,
+                                               gboolean a_clear_errs);
+static enum CRStatus
+  cr_parser_clear_errors (CRParser * a_this);
+
+/*****************************
+ *error managemet methods
+ *****************************/
+
+/**
+ *Constructor of #CRParserError class.
+ *@param a_msg the brute error message.
+ *@param a_status the error status.
+ *@return the newly built instance of #CRParserError.
+ */
+static CRParserError *
+cr_parser_error_new (const guchar * a_msg, enum CRStatus a_status)
+{
+        CRParserError *result = NULL;
+
+        result = g_try_malloc (sizeof (CRParserError));
+
+        if (result == NULL) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+
+        memset (result, 0, sizeof (CRParserError));
+
+        cr_parser_error_set_msg (result, a_msg);
+        cr_parser_error_set_status (result, a_status);
+
+        return result;
+}
+
+/**
+ *Sets the message associated to this instance of #CRError.
+ *@param a_this the current instance of #CRParserError.
+ *@param a_msg the new message.
+ */
+static void
+cr_parser_error_set_msg (CRParserError * a_this, const guchar * a_msg)
+{
+        g_return_if_fail (a_this);
+
+        if (a_this->msg) {
+                g_free (a_this->msg);
+        }
+
+        a_this->msg = (guchar *) g_strdup ((const gchar *) a_msg);
+}
+
+/**
+ *Sets the error status.
+ *@param a_this the current instance of #CRParserError.
+ *@param a_status the new error status.
+ *
+ */
+static void
+cr_parser_error_set_status (CRParserError * a_this, enum CRStatus a_status)
+{
+        g_return_if_fail (a_this);
+
+        a_this->status = a_status;
+}
+
+/**
+ *Sets the position of the parser error.
+ *@param a_this the current instance of #CRParserError.
+ *@param a_line the line number.
+ *@param a_column the column number.
+ *@param a_byte_num the byte number.
+ */
+static void
+cr_parser_error_set_pos (CRParserError * a_this,
+                         glong a_line, glong a_column, glong a_byte_num)
+{
+        g_return_if_fail (a_this);
+
+        a_this->line = a_line;
+        a_this->column = a_column;
+        a_this->byte_num = a_byte_num;
+}
+
+static void
+cr_parser_error_dump (CRParserError * a_this)
+{
+        g_return_if_fail (a_this);
+
+        g_printerr ("parsing error: %ld:%ld:", a_this->line, a_this->column);
+
+        g_printerr ("%s\n", a_this->msg);
+}
+
+/**
+ *The destructor of #CRParserError.
+ *@param a_this the current instance of #CRParserError.
+ */
+static void
+cr_parser_error_destroy (CRParserError * a_this)
+{
+        g_return_if_fail (a_this);
+
+        if (a_this->msg) {
+                g_free (a_this->msg);
+                a_this->msg = NULL;
+        }
+
+        g_free (a_this);
+}
+
+/**
+ *Pushes an error on the parser error stack.
+ *@param a_this the current instance of #CRParser.
+ *@param a_msg the error message.
+ *@param a_status the error status.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_push_error (CRParser * a_this,
+                      const guchar * a_msg, enum CRStatus a_status)
+{
+        enum CRStatus status = CR_OK;
+
+        CRParserError *error = NULL;
+        CRInputPos pos;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_msg, CR_BAD_PARAM_ERROR);
+
+        error = cr_parser_error_new (a_msg, a_status);
+
+        g_return_val_if_fail (error, CR_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &pos);
+
+        cr_parser_error_set_pos
+                (error, pos.line, pos.col, pos.next_byte_index - 1);
+
+        PRIVATE (a_this)->err_stack =
+                g_list_prepend (PRIVATE (a_this)->err_stack, error);
+
+        if (PRIVATE (a_this)->err_stack == NULL)
+                goto error;
+
+        return CR_OK;
+
+      error:
+
+        if (error) {
+                cr_parser_error_destroy (error);
+                error = NULL;
+        }
+
+        return status;
+}
+
+/**
+ *Dumps the error stack on stdout.
+ *@param a_this the current instance of #CRParser.
+ *@param a_clear_errs whether to clear the error stack
+ *after the dump or not.
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+static enum CRStatus
+cr_parser_dump_err_stack (CRParser * a_this, gboolean a_clear_errs)
+{
+        GList *cur = NULL;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        if (PRIVATE (a_this)->err_stack == NULL)
+                return CR_OK;
+
+        for (cur = PRIVATE (a_this)->err_stack; cur; cur = cur->next) {
+                cr_parser_error_dump ((CRParserError *) cur->data);
+        }
+
+        if (a_clear_errs == TRUE) {
+                cr_parser_clear_errors (a_this);
+        }
+
+        return CR_OK;
+}
+
+/**
+ *Clears all the errors contained in the parser error stack.
+ *Frees all the errors, and the stack that contains'em.
+ *@param a_this the current instance of #CRParser.
+ */
+static enum CRStatus
+cr_parser_clear_errors (CRParser * a_this)
+{
+        GList *cur = NULL;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        for (cur = PRIVATE (a_this)->err_stack; cur; cur = cur->next) {
+                if (cur->data) {
+                        cr_parser_error_destroy ((CRParserError *)
+                                                 cur->data);
+                }
+        }
+
+        if (PRIVATE (a_this)->err_stack) {
+                g_list_free (PRIVATE (a_this)->err_stack);
+                PRIVATE (a_this)->err_stack = NULL;
+        }
+
+        return CR_OK;
+}
+
+/**
+ * cr_parser_try_to_skip_spaces_and_comments:
+ *@a_this: the current instance of #CRParser.
+ *
+ *Same as cr_parser_try_to_skip_spaces() but this one skips
+ *spaces and comments.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_try_to_skip_spaces_and_comments (CRParser * a_this)
+{
+        enum CRStatus status = CR_ERROR;
+        CRToken *token = NULL;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR);
+        do {
+                if (token) {
+                        cr_token_destroy (token);
+                        token = NULL;
+                }
+
+                status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+                                                  &token);
+                if (status != CR_OK)
+                        goto error;
+        }
+        while ((token != NULL)
+               && (token->type == COMMENT_TK || token->type == S_TK));
+
+        cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
+
+        return status;
+
+      error:
+
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        return status;
+}
+
+/***************************************
+ *End of Parser input handling routines
+ ***************************************/
+
+
+/*************************************
+ *Non trivial terminal productions
+ *parsing routines
+ *************************************/
+
+/**
+ *Parses a css stylesheet following the core css grammar.
+ *This is mainly done for test purposes.
+ *During the parsing, no callback is called. This is just
+ *to validate that the stylesheet is well formed according to the
+ *css core syntax.
+ *stylesheet  : [ CDO | CDC | S | statement ]*;
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successful completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_stylesheet_core (CRParser * a_this)
+{
+        CRToken *token = NULL;
+        CRInputPos init_pos;
+        enum CRStatus status = CR_ERROR;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+ continue_parsing:
+
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        if (status == CR_END_OF_INPUT_ERROR) {
+                status = CR_OK;
+                goto done;
+        } else if (status != CR_OK) {
+                goto error;
+        }
+
+        switch (token->type) {
+
+        case CDO_TK:
+        case CDC_TK:
+                goto continue_parsing;
+                break;
+        default:
+                status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+                                               token);
+                CHECK_PARSING_STATUS (status, TRUE);
+                token = NULL;
+                status = cr_parser_parse_statement_core (a_this);
+                cr_parser_clear_errors (a_this);
+                if (status == CR_OK) {
+                        goto continue_parsing;
+                } else if (status == CR_END_OF_INPUT_ERROR) {
+                        goto done;
+                } else {
+                        goto error;
+                }
+        }
+
+ done:
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        cr_parser_clear_errors (a_this);
+        return CR_OK;
+
+ error:
+        cr_parser_push_error
+                (a_this, (const guchar *) "could not recognize next production", CR_ERROR);
+
+        cr_parser_dump_err_stack (a_this, TRUE);
+
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/**
+ *Parses an at-rule as defined by the css core grammar
+ *in chapter 4.1 in the css2 spec.
+ *at-rule     : ATKEYWORD S* any* [ block | ';' S* ];
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_atrule_core (CRParser * a_this)
+{
+        CRToken *token = NULL;
+        CRInputPos init_pos;
+        enum CRStatus status = CR_ERROR;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 
+                                          &token);
+        ENSURE_PARSING_COND (status == CR_OK
+                             && token
+                             &&
+                             (token->type == ATKEYWORD_TK
+                              || token->type == IMPORT_SYM_TK
+                              || token->type == PAGE_SYM_TK
+                              || token->type == MEDIA_SYM_TK
+                              || token->type == FONT_FACE_SYM_TK
+                              || token->type == CHARSET_SYM_TK));
+
+        cr_token_destroy (token);
+        token = NULL;
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        do {
+                status = cr_parser_parse_any_core (a_this);
+        } while (status == CR_OK);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+                                          &token);
+        ENSURE_PARSING_COND (status == CR_OK && token);
+
+        if (token->type == CBO_TK) {
+                cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 
+                                      token);
+                token = NULL;
+                status = cr_parser_parse_block_core (a_this);
+                CHECK_PARSING_STATUS (status,
+                                      FALSE);
+                goto done;
+        } else if (token->type == SEMICOLON_TK) {
+                goto done;
+        } else {
+                status = CR_PARSING_ERROR ;
+                goto error;
+        }
+
+ done:
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+        return CR_OK;
+
+ error:
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr,
+                              &init_pos);
+        return status;
+}
+
+/**
+ *Parses a ruleset as defined by the css core grammar in chapter
+ *4.1 of the css2 spec.
+ *ruleset ::= selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*;
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_ruleset_core (CRParser * a_this)
+{
+        CRToken *token = NULL;
+        CRInputPos init_pos;
+        enum CRStatus status = CR_ERROR;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_parser_parse_selector_core (a_this);
+
+        ENSURE_PARSING_COND (status == CR_OK
+                             || status == CR_PARSING_ERROR
+                             || status == CR_END_OF_INPUT_ERROR);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        ENSURE_PARSING_COND (status == CR_OK && token
+                             && token->type == CBO_TK);
+        cr_token_destroy (token);
+        token = NULL;
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+        status = cr_parser_parse_declaration_core (a_this);
+
+      parse_declaration_list:
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        ENSURE_PARSING_COND (status == CR_OK && token);
+        if (token->type == CBC_TK) {
+                goto done;
+        }
+
+        ENSURE_PARSING_COND (status == CR_OK
+                             && token && token->type == SEMICOLON_TK);
+
+        cr_token_destroy (token);
+        token = NULL;
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+        status = cr_parser_parse_declaration_core (a_this);
+        cr_parser_clear_errors (a_this);
+        ENSURE_PARSING_COND (status == CR_OK || status == CR_PARSING_ERROR);
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        ENSURE_PARSING_COND (status == CR_OK && token);
+        if (token->type == CBC_TK) {
+                cr_token_destroy (token);
+                token = NULL;
+                cr_parser_try_to_skip_spaces_and_comments (a_this);
+                goto done;
+        } else {
+                status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+                                               token);
+                token = NULL;
+                goto parse_declaration_list;
+        }
+
+      done:
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        if (status == CR_OK) {
+                return CR_OK;
+        }
+
+      error:
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/**
+ *Parses a "selector" as specified by the css core 
+ *grammar.
+ *selector    : any+;
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_selector_core (CRParser * a_this)
+{
+        CRToken *token = NULL;
+        CRInputPos init_pos;
+        enum CRStatus status = CR_ERROR;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_parser_parse_any_core (a_this);
+        CHECK_PARSING_STATUS (status, FALSE);
+
+        do {
+                status = cr_parser_parse_any_core (a_this);
+
+        } while (status == CR_OK);
+
+        return CR_OK;
+
+ error:
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/**
+ *Parses a "block" as defined in the css core grammar
+ *in chapter 4.1 of the css2 spec.
+ *block ::= '{' S* [ any | block | ATKEYWORD S* | ';' ]* '}' S*;
+ *@param a_this the current instance of #CRParser.
+ *FIXME: code this function.
+ */
+static enum CRStatus
+cr_parser_parse_block_core (CRParser * a_this)
+{
+        CRToken *token = NULL;
+        CRInputPos init_pos;
+        enum CRStatus status = CR_ERROR;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        ENSURE_PARSING_COND (status == CR_OK && token
+                             && token->type == CBO_TK);
+
+      parse_block_content:
+
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        ENSURE_PARSING_COND (status == CR_OK && token);
+
+        if (token->type == CBC_TK) {
+                cr_parser_try_to_skip_spaces_and_comments (a_this);
+                goto done;
+        } else if (token->type == SEMICOLON_TK) {
+                goto parse_block_content;
+        } else if (token->type == ATKEYWORD_TK) {
+                cr_parser_try_to_skip_spaces_and_comments (a_this);
+                goto parse_block_content;
+        } else if (token->type == CBO_TK) {
+                cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
+                token = NULL;
+                status = cr_parser_parse_block_core (a_this);
+                CHECK_PARSING_STATUS (status, FALSE);
+                goto parse_block_content;
+        } else {
+                cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
+                token = NULL;
+                status = cr_parser_parse_any_core (a_this);
+                CHECK_PARSING_STATUS (status, FALSE);
+                goto parse_block_content;
+        }
+
+      done:
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        if (status == CR_OK)
+                return CR_OK;
+
+      error:
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+static enum CRStatus
+cr_parser_parse_declaration_core (CRParser * a_this)
+{
+        CRToken *token = NULL;
+        CRInputPos init_pos;
+        enum CRStatus status = CR_ERROR;
+        CRString *prop = NULL;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_parser_parse_property (a_this, &prop);
+        CHECK_PARSING_STATUS (status, FALSE);
+        cr_parser_clear_errors (a_this);
+        ENSURE_PARSING_COND (status == CR_OK && prop);
+        cr_string_destroy (prop);
+        prop = NULL;
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        ENSURE_PARSING_COND (status == CR_OK
+                             && token
+                             && token->type == DELIM_TK
+                             && token->u.unichar == ':');
+        cr_token_destroy (token);
+        token = NULL;
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+        status = cr_parser_parse_value_core (a_this);
+        CHECK_PARSING_STATUS (status, FALSE);
+
+        return CR_OK;
+
+      error:
+
+        if (prop) {
+                cr_string_destroy (prop);
+                prop = NULL;
+        }
+
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/**
+ *Parses a "value" production as defined by the css core grammar
+ *in chapter 4.1.
+ *value ::= [ any | block | ATKEYWORD S* ]+;
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_value_core (CRParser * a_this)
+{
+        CRToken *token = NULL;
+        CRInputPos init_pos;
+        enum CRStatus status = CR_ERROR;
+        glong ref = 0;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+      continue_parsing:
+
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        ENSURE_PARSING_COND (status == CR_OK && token);
+
+        switch (token->type) {
+        case CBO_TK:
+                status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+                                               token);
+                token = NULL;
+                status = cr_parser_parse_block_core (a_this);
+                CHECK_PARSING_STATUS (status, FALSE);
+                ref++;
+                goto continue_parsing;
+
+        case ATKEYWORD_TK:
+                cr_parser_try_to_skip_spaces_and_comments (a_this);
+                ref++;
+                goto continue_parsing;
+
+        default:
+                status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+                                               token);
+                token = NULL;
+                status = cr_parser_parse_any_core (a_this);
+                if (status == CR_OK) {
+                        ref++;
+                        goto continue_parsing;
+                } else if (status == CR_PARSING_ERROR) {
+                        status = CR_OK;
+                        goto done;
+                } else {
+                        goto error;
+                }
+        }
+
+      done:
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        if (status == CR_OK && ref)
+                return CR_OK;
+      error:
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/**
+ *Parses an "any" as defined by the css core grammar in the
+ *css2 spec in chapter 4.1.
+ *any ::= [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING
+ *        | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES
+ *        | FUNCTION | DASHMATCH | '(' any* ')' | '[' any* ']' ] S*;
+ *
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_any_core (CRParser * a_this)
+{
+        CRToken *token1 = NULL,
+                *token2 = NULL;
+        CRInputPos init_pos;
+        enum CRStatus status = CR_ERROR;
+
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token1);
+
+        ENSURE_PARSING_COND (status == CR_OK && token1);
+
+        switch (token1->type) {
+        case IDENT_TK:
+        case NUMBER_TK:
+        case RGB_TK:
+        case PERCENTAGE_TK:
+        case DIMEN_TK:
+        case EMS_TK:
+        case EXS_TK:
+        case LENGTH_TK:
+        case ANGLE_TK:
+        case FREQ_TK:
+        case TIME_TK:
+        case STRING_TK:
+        case DELIM_TK:
+        case URI_TK:
+        case HASH_TK:
+        case UNICODERANGE_TK:
+        case INCLUDES_TK:
+        case DASHMATCH_TK:
+        case S_TK:
+        case COMMENT_TK:
+        case IMPORTANT_SYM_TK:
+                status = CR_OK;
+                break;
+        case FUNCTION_TK:
+                /*
+                 *this case isn't specified by the spec but it
+                 *does happen. So we have to handle it.
+                 *We must consider function with parameters.
+                 *We consider parameter as being an "any*" production.
+                 */
+                do {
+                        status = cr_parser_parse_any_core (a_this);
+                } while (status == CR_OK);
+
+                ENSURE_PARSING_COND (status == CR_PARSING_ERROR);
+                status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+                                                  &token2);
+                ENSURE_PARSING_COND (status == CR_OK
+                                     && token2 && token2->type == PC_TK);
+                break;
+        case PO_TK:
+                status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+                                                  &token2);
+                ENSURE_PARSING_COND (status == CR_OK && token2);
+
+                if (token2->type == PC_TK) {
+                        cr_token_destroy (token2);
+                        token2 = NULL;
+                        goto done;
+                } else {
+                        status = cr_tknzr_unget_token
+                                (PRIVATE (a_this)->tknzr, token2);
+                        token2 = NULL;
+                }
+
+                do {
+                        status = cr_parser_parse_any_core (a_this);
+                } while (status == CR_OK);
+
+                ENSURE_PARSING_COND (status == CR_PARSING_ERROR);
+
+                status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+                                                  &token2);
+                ENSURE_PARSING_COND (status == CR_OK
+                                     && token2 && token2->type == PC_TK);
+                status = CR_OK;
+                break;
+
+        case BO_TK:
+                status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+                                                  &token2);
+                ENSURE_PARSING_COND (status == CR_OK && token2);
+
+                if (token2->type == BC_TK) {
+                        cr_token_destroy (token2);
+                        token2 = NULL;
+                        goto done;
+                } else {
+                        status = cr_tknzr_unget_token
+                                (PRIVATE (a_this)->tknzr, token2);
+                        token2 = NULL;
+                }
+
+                do {
+                        status = cr_parser_parse_any_core (a_this);
+                } while (status == CR_OK);
+
+                ENSURE_PARSING_COND (status == CR_PARSING_ERROR);
+
+                status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+                                                  &token2);
+                ENSURE_PARSING_COND (status == CR_OK
+                                     && token2 && token2->type == BC_TK);
+                status = CR_OK;
+                break;
+        default:
+                status = CR_PARSING_ERROR;
+                goto error;
+        }
+
+      done:
+        if (token1) {
+                cr_token_destroy (token1);
+                token1 = NULL;
+        }
+
+        if (token2) {
+                cr_token_destroy (token2);
+                token2 = NULL;
+        }
+
+        return CR_OK;
+
+      error:
+
+        if (token1) {
+                cr_token_destroy (token1);
+                token1 = NULL;
+        }
+
+        if (token2) {
+                cr_token_destroy (token2);
+                token2 = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+        return status;
+}
+
+/**
+ *Parses an attribute selector as defined in the css2 spec in
+ *appendix D.1:
+ *attrib ::= '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
+ *            [ IDENT | STRING ] S* ]? ']'
+ *
+ *@param a_this the "this pointer" of the current instance of
+ *#CRParser .
+ *@param a_sel out parameter. The successfully parsed attribute selector.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_attribute_selector (CRParser * a_this, 
+                                    CRAttrSel ** a_sel)
+{
+        enum CRStatus status = CR_OK;
+        CRInputPos init_pos;
+        CRToken *token = NULL;
+        CRAttrSel *result = NULL;
+        CRParsingLocation location = {0} ;
+
+        g_return_val_if_fail (a_this && a_sel, CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        ENSURE_PARSING_COND (status == CR_OK && token
+                             && token->type == BO_TK);
+        cr_parsing_location_copy
+                (&location, &token->location) ;
+        cr_token_destroy (token);
+        token = NULL;
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        result = cr_attr_sel_new ();
+        if (!result) {
+                cr_utils_trace_info ("result failed")  ;
+                status = CR_OUT_OF_MEMORY_ERROR ;
+                goto error ;
+        }
+        cr_parsing_location_copy (&result->location,
+                                  &location) ;
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        ENSURE_PARSING_COND (status == CR_OK
+                             && token && token->type == IDENT_TK);
+
+        result->name = token->u.str;
+        token->u.str = NULL;
+        cr_token_destroy (token);
+        token = NULL;
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        ENSURE_PARSING_COND (status == CR_OK && token);
+
+        if (token->type == INCLUDES_TK) {
+                result->match_way = INCLUDES;
+                goto parse_right_part;
+        } else if (token->type == DASHMATCH_TK) {
+                result->match_way = DASHMATCH;
+                goto parse_right_part;
+        } else if (token->type == DELIM_TK && token->u.unichar == '=') {
+                result->match_way = EQUALS;
+                goto parse_right_part;
+        } else if (token->type == BC_TK) {
+                result->match_way = SET;
+                goto done;
+        }
+
+ parse_right_part:
+
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        ENSURE_PARSING_COND (status == CR_OK && token);
+        
+        if (token->type == IDENT_TK) {
+                result->value = token->u.str;
+                token->u.str = NULL;
+        } else if (token->type == STRING_TK) {
+                result->value = token->u.str;
+                token->u.str = NULL;
+        } else {
+                status = CR_PARSING_ERROR;
+                goto error;
+        }
+
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+
+        ENSURE_PARSING_COND (status == CR_OK && token
+                             && token->type == BC_TK);
+ done:
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        if (*a_sel) {
+                status = cr_attr_sel_append_attr_sel (*a_sel, result);
+                CHECK_PARSING_STATUS (status, FALSE);
+        } else {
+                *a_sel = result;
+        }
+
+        cr_parser_clear_errors (a_this);
+        return CR_OK;
+
+ error:
+
+        if (result) {
+                cr_attr_sel_destroy (result);
+                result = NULL;
+        }
+
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/**
+ *Parses a "property" as specified by the css2 spec at [4.1.1]:
+ *property : IDENT S*;
+ *
+ *@param a_this the "this pointer" of the current instance of #CRParser.
+ *@param GString a_property out parameter. The parsed property without the
+ *trailing spaces. If *a_property is NULL, this function allocates a
+ *new instance of GString and set it content to the parsed property.
+ *If not, the property is just appended to a_property's previous content.
+ *In both cases, it is up to the caller to free a_property.
+ *@return CR_OK upon successfull completion, CR_PARSING_ERROR if the
+ *next construction was not a "property", or an error code.
+ */
+static enum CRStatus
+cr_parser_parse_property (CRParser * a_this, 
+                          CRString ** a_property)
+{
+        enum CRStatus status = CR_OK;
+        CRInputPos init_pos;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->tknzr
+                              && a_property, 
+                              CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_parser_parse_ident (a_this, a_property);
+        CHECK_PARSING_STATUS (status, TRUE);
+        
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        cr_parser_clear_errors (a_this);
+        return CR_OK;
+
+      error:
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/**
+ * cr_parser_parse_term:
+ *@a_term: out parameter. The successfully parsed term.
+ *
+ *Parses a "term" as defined in the css2 spec, appendix D.1:
+ *term ::= unary_operator? [NUMBER S* | PERCENTAGE S* | LENGTH S* | 
+ *EMS S* | EXS S* | ANGLE S* | TIME S* | FREQ S* | function ] |
+ *STRING S* | IDENT S* | URI S* | RGB S* | UNICODERANGE S* | hexcolor
+ *
+ *TODO: handle parsing of 'RGB'
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_term (CRParser * a_this, CRTerm ** a_term)
+{
+        enum CRStatus status = CR_PARSING_ERROR;
+        CRInputPos init_pos;
+        CRTerm *result = NULL;
+        CRTerm *param = NULL;
+        CRToken *token = NULL;
+        CRString *func_name = NULL;
+        CRParsingLocation location = {0} ;
+
+        g_return_val_if_fail (a_this && a_term, CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        result = cr_term_new ();
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 
+                                          &token);
+        if (status != CR_OK || !token)
+                goto error;
+
+        cr_parsing_location_copy (&location, &token->location) ;
+        if (token->type == DELIM_TK && token->u.unichar == '+') {
+                result->unary_op = PLUS_UOP;
+                cr_token_destroy (token) ;
+                token = NULL ;
+                cr_parser_try_to_skip_spaces_and_comments (a_this);
+                status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 
+                                                  &token);
+                if (status != CR_OK || !token)
+                        goto error;
+        } else if (token->type == DELIM_TK && token->u.unichar == '-') {
+                result->unary_op = MINUS_UOP;
+                cr_token_destroy (token) ;
+                token = NULL ;
+                cr_parser_try_to_skip_spaces_and_comments (a_this);
+                status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 
+                                                  &token);
+                if (status != CR_OK || !token)
+                        goto error;
+        }
+
+        if (token->type == EMS_TK
+            || token->type == EXS_TK
+            || token->type == LENGTH_TK
+            || token->type == ANGLE_TK
+            || token->type == TIME_TK
+            || token->type == FREQ_TK
+            || token->type == PERCENTAGE_TK
+            || token->type == NUMBER_TK) {
+                status = cr_term_set_number (result, token->u.num);
+                CHECK_PARSING_STATUS (status, TRUE);
+                token->u.num = NULL;
+                status = CR_OK;
+        } else if (token && token->type == FUNCTION_TK) {
+                status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+                                               token);
+                token = NULL;
+                status = cr_parser_parse_function (a_this, &func_name,
+                                                   &param);
+
+                if (status == CR_OK) {
+                        status = cr_term_set_function (result,
+                                                       func_name,
+                                                       param);
+                        CHECK_PARSING_STATUS (status, TRUE);
+                }
+        } else if (token && token->type == STRING_TK) {
+                status = cr_term_set_string (result, 
+                                             token->u.str);
+                CHECK_PARSING_STATUS (status, TRUE);
+                token->u.str = NULL;
+        } else if (token && token->type == IDENT_TK) {
+                status = cr_term_set_ident (result, token->u.str);
+                CHECK_PARSING_STATUS (status, TRUE);
+                token->u.str = NULL;
+        } else if (token && token->type == URI_TK) {
+                status = cr_term_set_uri (result, token->u.str);
+                CHECK_PARSING_STATUS (status, TRUE);
+                token->u.str = NULL;
+        } else if (token && token->type == RGB_TK) {
+                status = cr_term_set_rgb (result, token->u.rgb);
+                CHECK_PARSING_STATUS (status, TRUE);
+                token->u.rgb = NULL;
+        } else if (token && token->type == UNICODERANGE_TK) {
+                result->type = TERM_UNICODERANGE;
+                status = CR_PARSING_ERROR;
+        } else if (token && token->type == HASH_TK) {
+                status = cr_term_set_hash (result, token->u.str);
+                CHECK_PARSING_STATUS (status, TRUE);
+                token->u.str = NULL;
+        } else {
+                status = CR_PARSING_ERROR;
+        }
+
+        if (status != CR_OK) {
+                goto error;
+        }
+        cr_parsing_location_copy (&result->location,
+                                  &location) ;
+        *a_term = cr_term_append_term (*a_term, result);
+
+        result = NULL;
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        cr_parser_clear_errors (a_this);
+        return CR_OK;
+
+ error:
+
+        if (result) {
+                cr_term_destroy (result);
+                result = NULL;
+        }
+
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        if (param) {
+                cr_term_destroy (param);
+                param = NULL;
+        }
+
+        if (func_name) {
+                cr_string_destroy (func_name);
+                func_name = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/**
+ * cr_parser_parse_simple_selector:
+ *@a_this: the "this pointer" of the current instance of #CRParser.
+ *@a_sel: out parameter. Is set to the successfully parsed simple
+ *selector.
+ *
+ *Parses a "simple_selector" as defined by the css2 spec in appendix D.1 :
+ *element_name? [ HASH | class | attrib | pseudo ]* S*
+ *and where pseudo is:
+ *pseudo ::=  ':' [ IDENT | FUNCTION S* IDENT S* ')' ]
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_simple_selector (CRParser * a_this, CRSimpleSel ** a_sel)
+{
+        enum CRStatus status = CR_ERROR;
+        CRInputPos init_pos;
+        CRToken *token = NULL;
+        CRSimpleSel *sel = NULL;
+        CRAdditionalSel *add_sel_list = NULL;
+        gboolean found_sel = FALSE;
+        guint32 cur_char = 0;
+
+        g_return_val_if_fail (a_this && a_sel, CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        if (status != CR_OK)
+                goto error;
+
+        sel = cr_simple_sel_new ();
+        ENSURE_PARSING_COND (sel);
+
+        cr_parsing_location_copy 
+                (&sel->location, 
+                 &token->location) ;
+
+        if (token && token->type == DELIM_TK 
+            && token->u.unichar == '*') {
+                sel->type_mask |= UNIVERSAL_SELECTOR;
+                sel->name = cr_string_new_from_string ("*");
+                found_sel = TRUE;
+        } else if (token && token->type == IDENT_TK) {
+                sel->name = token->u.str;
+                sel->type_mask |= TYPE_SELECTOR;
+                token->u.str = NULL;
+                found_sel = TRUE;
+        } else {
+                status = cr_tknzr_unget_token 
+                        (PRIVATE (a_this)->tknzr,
+                         token);
+                token = NULL;
+        }
+
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        for (;;) {
+                if (token) {
+                        cr_token_destroy (token);
+                        token = NULL;
+                }
+
+                status = cr_tknzr_get_next_token 
+                        (PRIVATE (a_this)->tknzr,
+                         &token);
+                if (status != CR_OK)
+                        goto error;
+
+                if (token && token->type == HASH_TK) {
+                        /*we parsed an attribute id */
+                        CRAdditionalSel *add_sel = NULL;
+
+                        add_sel = cr_additional_sel_new_with_type
+                                (ID_ADD_SELECTOR);
+
+                        add_sel->content.id_name = token->u.str;
+                        token->u.str = NULL;
+
+                        cr_parsing_location_copy 
+                                (&add_sel->location,
+                                 &token->location) ;
+                        add_sel_list =
+                                cr_additional_sel_append
+                                (add_sel_list, add_sel);                        
+                        found_sel = TRUE;
+                } else if (token && (token->type == DELIM_TK)
+                           && (token->u.unichar == '.')) {
+                        cr_token_destroy (token);
+                        token = NULL;
+
+                        status = cr_tknzr_get_next_token
+                                (PRIVATE (a_this)->tknzr, &token);
+                        if (status != CR_OK)
+                                goto error;
+
+                        if (token && token->type == IDENT_TK) {
+                                CRAdditionalSel *add_sel = NULL;
+
+                                add_sel = cr_additional_sel_new_with_type
+                                        (CLASS_ADD_SELECTOR);
+
+                                add_sel->content.class_name = token->u.str;
+                                token->u.str = NULL;
+
+                                add_sel_list =
+                                        cr_additional_sel_append
+                                        (add_sel_list, add_sel);
+                                found_sel = TRUE;
+
+                                cr_parsing_location_copy 
+                                        (&add_sel->location, 
+                                         & token->location) ;
+                        } else {
+                                status = CR_PARSING_ERROR;
+                                goto error;
+                        }
+                } else if (token && token->type == BO_TK) {
+                        CRAttrSel *attr_sel = NULL;
+                        CRAdditionalSel *add_sel = NULL;
+
+                        status = cr_tknzr_unget_token
+                                (PRIVATE (a_this)->tknzr, token);
+                        if (status != CR_OK)
+                                goto error;
+                        token = NULL;
+
+                        status = cr_parser_parse_attribute_selector
+                                (a_this, &attr_sel);
+                        CHECK_PARSING_STATUS (status, FALSE);
+
+                        add_sel = cr_additional_sel_new_with_type
+                                (ATTRIBUTE_ADD_SELECTOR);
+
+                        ENSURE_PARSING_COND (add_sel != NULL);
+
+                        add_sel->content.attr_sel = attr_sel;
+
+                        add_sel_list =
+                                cr_additional_sel_append
+                                (add_sel_list, add_sel);
+                        found_sel = TRUE;
+                        cr_parsing_location_copy 
+                                (&add_sel->location,
+                                 &attr_sel->location) ;
+                } else if (token && (token->type == DELIM_TK)
+                           && (token->u.unichar == ':')) {
+                        CRPseudo *pseudo = NULL;
+
+                        /*try to parse a pseudo */
+
+                        if (token) {
+                                cr_token_destroy (token);
+                                token = NULL;
+                        }
+
+                        pseudo = cr_pseudo_new ();
+
+                        status = cr_tknzr_get_next_token
+                                (PRIVATE (a_this)->tknzr, &token);
+                        ENSURE_PARSING_COND (status == CR_OK && token);
+
+                        cr_parsing_location_copy 
+                                (&pseudo->location, 
+                                 &token->location) ;
+
+                        if (token->type == IDENT_TK) {
+                                pseudo->type = IDENT_PSEUDO;
+                                pseudo->name = token->u.str;
+                                token->u.str = NULL;
+                                found_sel = TRUE;
+                        } else if (token->type == FUNCTION_TK) {
+                                pseudo->name = token->u.str;
+                                token->u.str = NULL;
+                                cr_parser_try_to_skip_spaces_and_comments
+                                        (a_this);
+                                status = cr_parser_parse_ident
+                                        (a_this, &pseudo->extra);
+
+                                ENSURE_PARSING_COND (status == CR_OK);
+                                READ_NEXT_CHAR (a_this, &cur_char);
+                                ENSURE_PARSING_COND (cur_char == ')');
+                                pseudo->type = FUNCTION_PSEUDO;
+                                found_sel = TRUE;
+                        } else {
+                                status = CR_PARSING_ERROR;
+                                goto error;
+                        }
+
+                        if (status == CR_OK) {
+                                CRAdditionalSel *add_sel = NULL;
+
+                                add_sel = cr_additional_sel_new_with_type
+                                        (PSEUDO_CLASS_ADD_SELECTOR);
+
+                                add_sel->content.pseudo = pseudo;
+                                cr_parsing_location_copy 
+                                        (&add_sel->location, 
+                                         &pseudo->location) ;
+                                add_sel_list =
+                                        cr_additional_sel_append
+                                        (add_sel_list, add_sel);
+                                status = CR_OK;
+                        }
+                } else {
+                        status = cr_tknzr_unget_token
+                                (PRIVATE (a_this)->tknzr, token);
+                        token = NULL;
+                        break;
+                }
+        }
+
+        if (status == CR_OK && found_sel == TRUE) {
+                cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+                sel->add_sel = add_sel_list;
+                add_sel_list = NULL;
+                
+                if (*a_sel == NULL) {
+                        *a_sel = sel;
+                } else {
+                        cr_simple_sel_append_simple_sel (*a_sel, sel);
+                }
+
+                sel = NULL;
+
+                if (token) {
+                        cr_token_destroy (token);
+                        token = NULL;
+                }
+
+                cr_parser_clear_errors (a_this);
+                return CR_OK;
+        } else {
+                status = CR_PARSING_ERROR;
+        }
+
+ error:
+
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        if (add_sel_list) {
+                cr_additional_sel_destroy (add_sel_list);
+                add_sel_list = NULL;
+        }
+
+        if (sel) {
+                cr_simple_sel_destroy (sel);
+                sel = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+
+}
+
+/**
+ * cr_parser_parse_simple_sels:
+ *@a_this: the this pointer of the current instance of #CRParser.
+ *@a_start: a pointer to the 
+ *first chararcter of the successfully parsed
+ *string.
+ *@a_end: a pointer to the last character of the successfully parsed
+ *string.
+ *
+ *Parses a "selector" as defined by the css2 spec in appendix D.1:
+ *selector ::=  simple_selector [ combinator simple_selector ]*
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_simple_sels (CRParser * a_this, 
+                             CRSimpleSel ** a_sel)
+{
+        enum CRStatus status = CR_ERROR;
+        CRInputPos init_pos;
+        CRSimpleSel *sel = NULL;
+        guint32 cur_char = 0;
+
+        g_return_val_if_fail (a_this                               
+                              && PRIVATE (a_this)
+                              && a_sel,
+                              CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_parser_parse_simple_selector (a_this, &sel);
+        CHECK_PARSING_STATUS (status, FALSE);
+
+        *a_sel = cr_simple_sel_append_simple_sel (*a_sel, sel);
+
+        for (;;) {
+                guint32 next_char = 0;
+                enum Combinator comb = 0;
+
+                sel = NULL;
+
+                PEEK_NEXT_CHAR (a_this, &next_char);
+
+                if (next_char == '+') {
+                        READ_NEXT_CHAR (a_this, &cur_char);
+                        comb = COMB_PLUS;
+                        cr_parser_try_to_skip_spaces_and_comments (a_this);
+                } else if (next_char == '>') {
+                        READ_NEXT_CHAR (a_this, &cur_char);
+                        comb = COMB_GT;
+                        cr_parser_try_to_skip_spaces_and_comments (a_this);
+                } else {
+                        comb = COMB_WS;
+                }
+
+                status = cr_parser_parse_simple_selector (a_this, &sel);
+                if (status != CR_OK)
+                        break;
+
+                if (comb && sel) {
+                        sel->combinator = comb;
+                        comb = 0;
+                }
+                if (sel) {
+                        *a_sel = cr_simple_sel_append_simple_sel (*a_sel, 
+                                                                  sel) ;
+                }
+        }
+        cr_parser_clear_errors (a_this);
+        return CR_OK;
+
+ error:
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/**
+ * cr_parser_parse_selector:
+ *@a_this: the current instance of #CRParser.
+ *@a_selector: the parsed list of comma separated
+ *selectors.
+ *
+ *Parses a comma separated list of selectors.
+ *
+ *Returns CR_OK upon successful completion, an error
+ *code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_selector (CRParser * a_this, 
+                          CRSelector ** a_selector)
+{
+        enum CRStatus status = CR_OK;
+        CRInputPos init_pos;
+        guint32 cur_char = 0,
+                next_char = 0;
+        CRSimpleSel *simple_sels = NULL;
+        CRSelector *selector = NULL;
+
+        g_return_val_if_fail (a_this && a_selector, CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_parser_parse_simple_sels (a_this, &simple_sels);
+        CHECK_PARSING_STATUS (status, FALSE);
+
+        if (simple_sels) {
+                selector = cr_selector_append_simple_sel
+                        (selector, simple_sels);
+                if (selector) {
+                        cr_parsing_location_copy
+                                (&selector->location,
+                                 &simple_sels->location) ;
+                }
+                simple_sels = NULL;
+        } else {
+                status = CR_PARSING_ERROR ;
+                goto error ;
+        }
+
+        status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr,
+                                     &next_char);
+        if (status != CR_OK) {
+                if (status == CR_END_OF_INPUT_ERROR) {
+                        status = CR_OK;
+                        goto okay;
+                } else {
+                        goto error;
+                }
+        }
+
+        if (next_char == ',') {
+                for (;;) {
+                        simple_sels = NULL;
+
+                        status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr,
+                                                     &next_char);
+                        if (status != CR_OK) {
+                                if (status == CR_END_OF_INPUT_ERROR) {
+                                        status = CR_OK;
+                                        break;
+                                } else {
+                                        goto error;
+                                }
+                        }
+
+                        if (next_char != ',')
+                                break;
+
+                        /*consume the ',' char */
+                        READ_NEXT_CHAR (a_this, &cur_char);
+
+                        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+                        status = cr_parser_parse_simple_sels
+                                (a_this, &simple_sels);
+
+                        CHECK_PARSING_STATUS (status, FALSE);
+
+                        if (simple_sels) {
+                                selector =
+                                        cr_selector_append_simple_sel
+                                        (selector, simple_sels);
+
+                                simple_sels = NULL;
+                        }
+                }
+        }
+
+      okay:
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        if (!*a_selector) {
+                *a_selector = selector;
+        } else {
+                *a_selector = cr_selector_append (*a_selector, selector);
+        }
+
+        selector = NULL;
+        return CR_OK;
+
+      error:
+
+        if (simple_sels) {
+                cr_simple_sel_destroy (simple_sels);
+                simple_sels = NULL;
+        }
+
+        if (selector) {
+                cr_selector_unref (selector);
+                selector = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/**
+ * cr_parser_parse_function:
+ *@a_this: the "this pointer" of the current instance of #CRParser.
+ *
+ *@a_func_name: out parameter. The parsed function name
+ *@a_expr: out parameter. The successfully parsed term.
+ *
+ *Parses a "function" as defined in css spec at appendix D.1:
+ *function ::= FUNCTION S* expr ')' S*
+ *FUNCTION ::= ident'('
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_function (CRParser * a_this,
+                          CRString ** a_func_name,
+                          CRTerm ** a_expr)
+{
+        CRInputPos init_pos;
+        enum CRStatus status = CR_OK;
+        CRToken *token = NULL;
+        CRTerm *expr = NULL;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_func_name,
+                              CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        if (status != CR_OK)
+                goto error;
+
+        if (token && token->type == FUNCTION_TK) {
+                *a_func_name = token->u.str;
+                token->u.str = NULL;
+        } else {
+                status = CR_PARSING_ERROR;
+                goto error;
+        }
+        cr_token_destroy (token);
+        token = NULL;
+        
+        cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+        status = cr_parser_parse_expr (a_this, &expr);
+
+        CHECK_PARSING_STATUS (status, FALSE);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        if (status != CR_OK)
+                goto error;
+
+        ENSURE_PARSING_COND (token && token->type == PC_TK);
+
+        cr_token_destroy (token);
+        token = NULL;
+
+        if (expr) {
+                *a_expr = cr_term_append_term (*a_expr, expr);
+                expr = NULL;
+        }
+
+        cr_parser_clear_errors (a_this);
+        return CR_OK;
+
+      error:
+
+        if (*a_func_name) {
+                cr_string_destroy (*a_func_name);
+                *a_func_name = NULL;
+        }
+
+        if (expr) {
+                cr_term_destroy (expr);
+                expr = NULL;
+        }
+
+        if (token) {
+                cr_token_destroy (token);
+
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/**
+ * cr_parser_parse_uri:
+ *@a_this: the current instance of #CRParser.
+ *@a_str: the successfully parsed url.
+ *
+ *Parses an uri as defined by the css spec [4.1.1]:
+ * URI ::= url\({w}{string}{w}\)
+ *         |url\({w}([!#$%&*-~]|{nonascii}|{escape})*{w}\)
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_uri (CRParser * a_this, CRString ** a_str)
+{
+
+        enum CRStatus status = CR_PARSING_ERROR;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR);
+
+        status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr,
+                                       URI_TK, NO_ET, a_str, NULL);
+        return status;
+}
+
+/**
+ * cr_parser_parse_string:
+ *@a_this: the current instance of #CRParser.
+ *@a_start: out parameter. Upon successfull completion, 
+ *points to the beginning of the string, points to an undefined value
+ *otherwise.
+ *@a_end: out parameter. Upon successfull completion, points to
+ *the beginning of the string, points to an undefined value otherwise.
+ *
+ *Parses a string type as defined in css spec [4.1.1]:
+ *
+ *string ::= {string1}|{string2}
+ *string1 ::= \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\"
+ *string2 ::= \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\'
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_string (CRParser * a_this, CRString ** a_str)
+{
+        enum CRStatus status = CR_OK;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->tknzr
+                              && a_str, CR_BAD_PARAM_ERROR);
+
+        status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr,
+                                       STRING_TK, NO_ET, a_str, NULL);
+        return status;
+}
+
+/**
+ *Parses an "ident" as defined in css spec [4.1.1]:
+ *ident ::= {nmstart}{nmchar}*
+ *
+ *@param a_this the currens instance of #CRParser.
+ *
+ *@param a_str a pointer to parsed ident. If *a_str is NULL,
+ *this function allocates a new instance of #CRString. If not, 
+ *the function just appends the parsed string to the one passed.
+ *In both cases it is up to the caller to free *a_str.
+ *
+ *@return CR_OK upon successfull completion, an error code 
+ *otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_ident (CRParser * a_this, CRString ** a_str)
+{
+        enum CRStatus status = CR_OK;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->tknzr
+                              && a_str, CR_BAD_PARAM_ERROR);
+
+        status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr,
+                                       IDENT_TK, NO_ET, a_str, NULL);
+        return status;
+}
+
+/**
+ *the next rule is ignored as well. This seems to be a bug
+ *Parses a stylesheet as defined in the css2 spec in appendix D.1:
+ *stylesheet ::= [ CHARSET_SYM S* STRING S* ';' ]? 
+ *               [S|CDO|CDC]* [ import [S|CDO|CDC]* ]*
+ *               [ [ ruleset | media | page | font_face ] [S|CDO|CDC]* ]*
+ *
+ *TODO: Finish the code of this function. Think about splitting it into
+ *smaller functions.
+ *
+ *@param a_this the "this pointer" of the current instance of #CRParser.
+ *@param a_start out parameter. A pointer to the first character of
+ *the successfully parsed string.
+ *@param a_end out parameter. A pointer to the first character of
+ *the successfully parsed string.
+ *
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_stylesheet (CRParser * a_this)
+{
+        enum CRStatus status = CR_OK;
+        CRInputPos init_pos;
+        CRToken *token = NULL;
+        CRString *charset = NULL;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        PRIVATE (a_this)->state = READY_STATE;
+
+        if (PRIVATE (a_this)->sac_handler
+            && PRIVATE (a_this)->sac_handler->start_document) {
+                PRIVATE (a_this)->sac_handler->start_document
+                        (PRIVATE (a_this)->sac_handler);
+        }
+
+ parse_charset:
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+
+        if (status == CR_END_OF_INPUT_ERROR)
+                goto done;
+        CHECK_PARSING_STATUS (status, TRUE);
+
+        if (token && token->type == CHARSET_SYM_TK) {
+                CRParsingLocation location = {0} ;
+                status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+                                               token);
+                CHECK_PARSING_STATUS (status, TRUE);
+                token = NULL;
+
+                status = cr_parser_parse_charset (a_this, 
+                                                  &charset,
+                                                  &location);
+
+                if (status == CR_OK && charset) {
+                        if (PRIVATE (a_this)->sac_handler
+                            && PRIVATE (a_this)->sac_handler->charset) {
+                                PRIVATE (a_this)->sac_handler->charset
+                                        (PRIVATE (a_this)->sac_handler,
+                                         charset, &location);
+                        }
+                } else if (status != CR_END_OF_INPUT_ERROR) {
+                        status = cr_parser_parse_atrule_core (a_this);
+                        CHECK_PARSING_STATUS (status, FALSE);
+                }
+
+                if (charset) {
+                        cr_string_destroy (charset);
+                        charset = NULL;
+                }
+        } else if (token
+                   && (token->type == S_TK 
+                       || token->type == COMMENT_TK)) {
+                status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+                                               token);
+                token = NULL;
+                CHECK_PARSING_STATUS (status, TRUE);
+
+                cr_parser_try_to_skip_spaces_and_comments (a_this);
+                goto parse_charset ;
+        } else if (token) {
+                status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+                                               token);
+                token = NULL;
+                CHECK_PARSING_STATUS (status, TRUE);
+        }
+
+/* parse_imports:*/
+        do {
+                if (token) {
+                        cr_token_destroy (token);
+                        token = NULL;
+                }
+                cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+                status = cr_tknzr_get_next_token
+                        (PRIVATE (a_this)->tknzr, &token);
+
+                if (status == CR_END_OF_INPUT_ERROR)
+                        goto done;
+                CHECK_PARSING_STATUS (status, TRUE);
+        } while (token
+                 && (token->type == S_TK
+                     || token->type == CDO_TK || token->type == CDC_TK));
+
+        if (token) {
+                status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+                                               token);
+                token = NULL;
+        }
+
+        for (;;) {
+                status = cr_tknzr_get_next_token
+                        (PRIVATE (a_this)->tknzr, &token);
+                if (status == CR_END_OF_INPUT_ERROR)
+                        goto done;
+                CHECK_PARSING_STATUS (status, TRUE);
+
+                if (token && token->type == IMPORT_SYM_TK) {
+                        GList *media_list = NULL;
+                        CRString *import_string = NULL;
+                        CRParsingLocation location = {0} ;
+
+                        status = cr_tknzr_unget_token
+                                (PRIVATE (a_this)->tknzr, token);
+                        token = NULL;
+                        CHECK_PARSING_STATUS (status, TRUE);
+
+                        status = cr_parser_parse_import (a_this,
+                                                         &media_list,
+                                                         &import_string,
+                                                         &location);
+                        if (status == CR_OK) {
+                                if (import_string
+                                    && PRIVATE (a_this)->sac_handler
+                                    && PRIVATE (a_this)->sac_handler->import_style) {
+                                        PRIVATE (a_this)->sac_handler->import_style 
+                                                (PRIVATE(a_this)->sac_handler,
+                                                 media_list,
+                                                 import_string,
+                                                 NULL, &location) ;
+
+                                        if ((PRIVATE (a_this)->sac_handler->resolve_import == TRUE)) {
+                                                /*
+                                                 *TODO: resolve the
+                                                 *import rule.
+                                                 */
+                                        }
+
+                                        if ((PRIVATE (a_this)->sac_handler->import_style_result)) {
+                                                PRIVATE (a_this)->sac_handler->import_style_result
+                                                        (PRIVATE (a_this)->sac_handler,
+                                                         media_list, import_string,
+                                                         NULL, NULL);
+                                        }
+                                }
+                        } else if (status != CR_END_OF_INPUT_ERROR) {
+                                if (PRIVATE (a_this)->sac_handler
+                                    && PRIVATE (a_this)->sac_handler->error) {
+                                        PRIVATE (a_this)->sac_handler->error
+                                                (PRIVATE (a_this)->sac_handler);
+                                }
+                                status = cr_parser_parse_atrule_core (a_this);
+                                CHECK_PARSING_STATUS (status, TRUE) ;
+                        } else {
+                                goto error ;
+                        }
+
+                        /*
+                         *then, after calling the appropriate 
+                         *SAC handler, free
+                         *the media_list and import_string.
+                         */
+                        if (media_list) {
+                                GList *cur = NULL;
+
+                                /*free the medium list */
+                                for (cur = media_list; cur; cur = cur->next) {
+                                        if (cur->data) {
+                                                cr_string_destroy (cur->data);
+                                        }
+                                }
+
+                                g_list_free (media_list);
+                                media_list = NULL;
+                        }
+
+                        if (import_string) {
+                                cr_string_destroy (import_string);
+                                import_string = NULL;
+                        }
+
+                        cr_parser_try_to_skip_spaces_and_comments (a_this);
+                } else if (token
+                           && (token->type == S_TK
+                               || token->type == CDO_TK
+                               || token->type == CDC_TK)) {
+                        status = cr_tknzr_unget_token
+                                (PRIVATE (a_this)->tknzr, token);
+                        token = NULL;
+
+                        do {
+                                if (token) {
+                                        cr_token_destroy (token);
+                                        token = NULL;
+                                }
+
+                                status = cr_tknzr_get_next_token
+                                        (PRIVATE (a_this)->tknzr, &token);
+
+                                if (status == CR_END_OF_INPUT_ERROR)
+                                        goto done;
+                                CHECK_PARSING_STATUS (status, TRUE);
+                        } while (token
+                                 && (token->type == S_TK
+                                     || token->type == CDO_TK
+                                     || token->type == CDC_TK));
+                } else {
+                        if (token) {
+                                status = cr_tknzr_unget_token
+                                        (PRIVATE (a_this)->tknzr, token);
+                                token = NULL;
+                        }
+                        goto parse_ruleset_and_others;
+                }
+        }
+
+ parse_ruleset_and_others:
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        for (;;) {
+                status = cr_tknzr_get_next_token
+                        (PRIVATE (a_this)->tknzr, &token);
+                if (status == CR_END_OF_INPUT_ERROR)
+                        goto done;
+                CHECK_PARSING_STATUS (status, TRUE);
+
+                if (token
+                    && (token->type == S_TK
+                        || token->type == CDO_TK || token->type == CDC_TK)) {
+                        status = cr_tknzr_unget_token
+                                (PRIVATE (a_this)->tknzr, token);
+                        token = NULL;
+
+                        do {
+                                if (token) {
+                                        cr_token_destroy (token);
+                                        token = NULL;
+                                }
+
+                                cr_parser_try_to_skip_spaces_and_comments
+                                        (a_this);
+                                status = cr_tknzr_get_next_token
+                                        (PRIVATE (a_this)->tknzr, &token);
+                        } while (token
+                                 && (token->type == S_TK
+                                     || token->type == COMMENT_TK
+                                     || token->type == CDO_TK
+                                     || token->type == CDC_TK));
+                        if (token) {
+                                cr_tknzr_unget_token
+                                        (PRIVATE (a_this)->tknzr, token);
+                                token = NULL;
+                        }
+                } else if (token
+                           && (token->type == HASH_TK
+                               || (token->type == DELIM_TK
+                                   && token->u.unichar == '.')
+                               || (token->type == DELIM_TK
+                                   && token->u.unichar == ':')
+                               || (token->type == DELIM_TK
+                                   && token->u.unichar == '*')
+                               || (token->type == BO_TK)
+                               || token->type == IDENT_TK)) {
+                        /*
+                         *Try to parse a CSS2 ruleset.
+                         *if the parsing fails, try to parse
+                         *a css core ruleset.
+                         */
+                        status = cr_tknzr_unget_token
+                                (PRIVATE (a_this)->tknzr, token);
+                        CHECK_PARSING_STATUS (status, TRUE);
+                        token = NULL;
+
+                        status = cr_parser_parse_ruleset (a_this);
+
+                        if (status == CR_OK) {
+                                continue;
+                        } else {
+                                if (PRIVATE (a_this)->sac_handler
+                                    && PRIVATE (a_this)->sac_handler->error) {
+                                        PRIVATE (a_this)->sac_handler->
+                                                error
+                                                (PRIVATE (a_this)->
+                                                 sac_handler);
+                                }
+
+                                status = cr_parser_parse_ruleset_core
+                                        (a_this);
+
+                                if (status == CR_OK) {
+                                        continue;
+                                } else {
+                                        break;
+                                }
+                        }
+                } else if (token && token->type == MEDIA_SYM_TK) {
+                        status = cr_tknzr_unget_token
+                                (PRIVATE (a_this)->tknzr, token);
+                        CHECK_PARSING_STATUS (status, TRUE);
+                        token = NULL;
+
+                        status = cr_parser_parse_media (a_this);
+                        if (status == CR_OK) {
+                                continue;
+                        } else {
+                                if (PRIVATE (a_this)->sac_handler
+                                    && PRIVATE (a_this)->sac_handler->error) {
+                                        PRIVATE (a_this)->sac_handler->
+                                                error
+                                                (PRIVATE (a_this)->
+                                                 sac_handler);
+                                }
+
+                                status = cr_parser_parse_atrule_core (a_this);
+
+                                if (status == CR_OK) {
+                                        continue;
+                                } else {
+                                        break;
+                                }
+                        }
+
+                } else if (token && token->type == PAGE_SYM_TK) {
+                        status = cr_tknzr_unget_token
+                                (PRIVATE (a_this)->tknzr, token);
+                        CHECK_PARSING_STATUS (status, TRUE);
+                        token = NULL;
+                        status = cr_parser_parse_page (a_this);
+
+                        if (status == CR_OK) {
+                                continue;
+                        } else {
+                                if (PRIVATE (a_this)->sac_handler
+                                    && PRIVATE (a_this)->sac_handler->error) {
+                                        PRIVATE (a_this)->sac_handler->
+                                                error
+                                                (PRIVATE (a_this)->
+                                                 sac_handler);
+                                }
+
+                                status = cr_parser_parse_atrule_core (a_this);
+
+                                if (status == CR_OK) {
+                                        continue;
+                                } else {
+                                        break;
+                                }
+                        }
+                } else if (token && token->type == FONT_FACE_SYM_TK) {
+                        status = cr_tknzr_unget_token
+                                (PRIVATE (a_this)->tknzr, token);
+                        CHECK_PARSING_STATUS (status, TRUE);
+                        token = NULL;
+                        status = cr_parser_parse_font_face (a_this);
+
+                        if (status == CR_OK) {
+                                continue;
+                        } else {
+                                if (PRIVATE (a_this)->sac_handler
+                                    && PRIVATE (a_this)->sac_handler->error) {
+                                        PRIVATE (a_this)->sac_handler->
+                                                error
+                                                (PRIVATE (a_this)->
+                                                 sac_handler);
+                                }
+
+                                status = cr_parser_parse_atrule_core (a_this);
+
+                                if (status == CR_OK) {
+                                        continue;
+                                } else {
+                                        break;
+                                }
+                        }
+                } else {
+                        status = cr_tknzr_unget_token
+                                (PRIVATE (a_this)->tknzr, token);
+                        CHECK_PARSING_STATUS (status, TRUE);
+                        token = NULL;
+                        status = cr_parser_parse_statement_core (a_this);
+
+                        if (status == CR_OK) {
+                                continue;
+                        } else {
+                                break;
+                        }
+                }
+        }
+
+      done:
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        if (status == CR_END_OF_INPUT_ERROR || status == CR_OK) {
+
+                if (PRIVATE (a_this)->sac_handler
+                    && PRIVATE (a_this)->sac_handler->end_document) {
+                        PRIVATE (a_this)->sac_handler->end_document
+                                (PRIVATE (a_this)->sac_handler);
+                }
+
+                return CR_OK;
+        }
+
+        cr_parser_push_error
+                (a_this, (const guchar *) "could not recognize next production", CR_ERROR);
+
+        if (PRIVATE (a_this)->sac_handler
+            && PRIVATE (a_this)->sac_handler->unrecoverable_error) {
+                PRIVATE (a_this)->sac_handler->
+                        unrecoverable_error (PRIVATE (a_this)->sac_handler);
+        }
+
+        cr_parser_dump_err_stack (a_this, TRUE);
+
+        return status;
+
+      error:
+
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        if (PRIVATE (a_this)->sac_handler
+            && PRIVATE (a_this)->sac_handler->unrecoverable_error) {
+                PRIVATE (a_this)->sac_handler->
+                        unrecoverable_error (PRIVATE (a_this)->sac_handler);
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/****************************************
+ *Public CRParser Methods
+ ****************************************/
+
+/**
+ * cr_parser_new:
+ * @a_tknzr: the tokenizer to use for the parsing.
+ *
+ *Creates a new parser to parse data
+ *coming the input stream given in parameter.
+ *
+ *Returns the newly created instance of #CRParser,
+ *or NULL if an error occurred.
+ */
+CRParser *
+cr_parser_new (CRTknzr * a_tknzr)
+{
+        CRParser *result = NULL;
+        enum CRStatus status = CR_OK;
+
+        result = g_malloc0 (sizeof (CRParser));
+
+        PRIVATE (result) = g_malloc0 (sizeof (CRParserPriv));
+
+        if (a_tknzr) {
+                status = cr_parser_set_tknzr (result, a_tknzr);
+        }
+
+        g_return_val_if_fail (status == CR_OK, NULL);
+
+        return result;
+}
+
+/**
+ * cr_parser_new_from_buf:
+ *@a_buf: the buffer to parse.
+ *@a_len: the length of the data in the buffer.
+ *@a_enc: the encoding of the input buffer a_buf.
+ *@a_free_buf: if set to TRUE, a_buf will be freed
+ *during the destruction of the newly built instance 
+ *of #CRParser. If set to FALSE, it is up to the caller to
+ *eventually free it.
+ *
+ *Instanciates a new parser from a memory buffer.
+ * 
+ *Returns the newly built parser, or NULL if an error arises.
+ */
+CRParser *
+cr_parser_new_from_buf (guchar * a_buf,
+                        gulong a_len,
+                        enum CREncoding a_enc, 
+                        gboolean a_free_buf)
+{
+        CRParser *result = NULL;
+        CRInput *input = NULL;
+
+        g_return_val_if_fail (a_buf && a_len, NULL);
+
+        input = cr_input_new_from_buf (a_buf, a_len, a_enc, a_free_buf);
+        g_return_val_if_fail (input, NULL);
+
+        result = cr_parser_new_from_input (input);
+        if (!result) {
+                cr_input_destroy (input);
+                input = NULL;
+                return NULL;
+        }
+        return result;
+}
+
+/**
+ * cr_parser_new_from_input:
+ * @a_input: the parser input stream to use.
+ *
+ * Returns a newly built parser input.
+ */
+CRParser *
+cr_parser_new_from_input (CRInput * a_input)
+{
+        CRParser *result = NULL;
+        CRTknzr *tokenizer = NULL;
+
+        if (a_input) {
+                tokenizer = cr_tknzr_new (a_input);
+                g_return_val_if_fail (tokenizer, NULL);
+        }
+
+        result = cr_parser_new (tokenizer);
+        g_return_val_if_fail (result, NULL);
+
+        return result;
+}
+
+/**
+ * cr_parser_new_from_file:
+ * @a_file_uri: the uri of the file to parse.
+ * @a_enc: the file encoding to use.
+ *
+ * Returns the newly built parser.
+ */
+CRParser *
+cr_parser_new_from_file (const guchar * a_file_uri, enum CREncoding a_enc)
+{
+        CRParser *result = NULL;
+        CRTknzr *tokenizer = NULL;
+
+        tokenizer = cr_tknzr_new_from_uri (a_file_uri, a_enc);
+        if (!tokenizer) {
+                cr_utils_trace_info ("Could not open input file");
+                return NULL;
+        }
+
+        result = cr_parser_new (tokenizer);
+        g_return_val_if_fail (result, NULL);
+        return result;
+}
+
+/**
+ * cr_parser_set_sac_handler:
+ *@a_this: the "this pointer" of the current instance of #CRParser.
+ *@a_handler: the handler to set.
+ *
+ *Sets a SAC document handler to the parser.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_set_sac_handler (CRParser * a_this, CRDocHandler * a_handler)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        if (PRIVATE (a_this)->sac_handler) {
+                cr_doc_handler_unref (PRIVATE (a_this)->sac_handler);
+        }
+
+        PRIVATE (a_this)->sac_handler = a_handler;
+        cr_doc_handler_ref (a_handler);
+
+        return CR_OK;
+}
+
+/**
+ * cr_parser_get_sac_handler:
+ *@a_this: the "this pointer" of the current instance of
+ *#CRParser.
+ *@a_handler: out parameter. The returned handler.
+ *
+ *Gets the SAC document handler.
+ *
+ *Returns CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_parser_get_sac_handler (CRParser * a_this, CRDocHandler ** a_handler)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        *a_handler = PRIVATE (a_this)->sac_handler;
+
+        return CR_OK;
+}
+
+/**
+ * cr_parser_set_default_sac_handler:
+ *@a_this: a pointer to the current instance of #CRParser.
+ *
+ *Sets the SAC handler associated to the current instance
+ *of #CRParser to the default SAC handler.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_set_default_sac_handler (CRParser * a_this)
+{
+        CRDocHandler *default_sac_handler = NULL;
+        enum CRStatus status = CR_ERROR;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        default_sac_handler = cr_doc_handler_new ();
+
+        cr_doc_handler_set_default_sac_handler (default_sac_handler);
+
+        status = cr_parser_set_sac_handler (a_this, default_sac_handler);
+
+        if (status != CR_OK) {
+                cr_doc_handler_destroy (default_sac_handler);
+                default_sac_handler = NULL;
+        }
+
+        return status;
+}
+
+/**
+ * cr_parser_set_use_core_grammar:
+ * @a_this: the current instance of #CRParser.
+ * @a_use_core_grammar: where to parse against the css core grammar.
+ *
+ * Returns CR_OK upon succesful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_set_use_core_grammar (CRParser * a_this,
+                                gboolean a_use_core_grammar)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        PRIVATE (a_this)->use_core_grammar = a_use_core_grammar;
+
+        return CR_OK;
+}
+
+/**
+ * cr_parser_get_use_core_grammar:
+ * @a_this: the current instance of #CRParser.
+ * @a_use_core_grammar: wether to use the core grammar or not.
+ *
+ * Returns CR_OK upon succesful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_get_use_core_grammar (CRParser const * a_this,
+                                gboolean * a_use_core_grammar)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        *a_use_core_grammar = PRIVATE (a_this)->use_core_grammar;
+
+        return CR_OK;
+}
+
+/**
+ * cr_parser_parse_file:
+ *@a_this: a pointer to the current instance of #CRParser.
+ *@a_file_uri: the uri to the file to load. For the time being,
+ *@a_enc: the encoding of the file to parse.
+ *only local files are supported.
+ *
+ *Parses a the given in parameter.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_file (CRParser * a_this,
+                      const guchar * a_file_uri, enum CREncoding a_enc)
+{
+        enum CRStatus status = CR_ERROR;
+        CRTknzr *tknzr = NULL;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_file_uri, CR_BAD_PARAM_ERROR);
+
+        tknzr = cr_tknzr_new_from_uri (a_file_uri, a_enc);
+
+        g_return_val_if_fail (tknzr != NULL, CR_ERROR);
+
+        status = cr_parser_set_tknzr (a_this, tknzr);
+        g_return_val_if_fail (status == CR_OK, CR_ERROR);
+
+        status = cr_parser_parse (a_this);
+
+        return status;
+}
+
+/**
+ * cr_parser_parse_expr:
+ * @a_this: the current instance of #CRParser.
+ * @a_expr: out parameter. the parsed expression.
+ *
+ *Parses an expression as defined by the css2 spec in appendix
+ *D.1:
+ *expr: term [ operator term ]*
+ *
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_expr (CRParser * a_this, CRTerm ** a_expr)
+{
+        enum CRStatus status = CR_ERROR;
+        CRInputPos init_pos;
+        CRTerm *expr = NULL,
+                *expr2 = NULL;
+        guchar next_byte = 0;
+        gulong nb_terms = 0;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_expr, CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_parser_parse_term (a_this, &expr);
+
+        CHECK_PARSING_STATUS (status, FALSE);
+
+        for (;;) {
+                guchar operator = 0;
+
+                status = cr_tknzr_peek_byte (PRIVATE (a_this)->tknzr,
+                                             1, &next_byte);
+                if (status != CR_OK) {
+                        if (status == CR_END_OF_INPUT_ERROR) {
+                                /*
+                                   if (!nb_terms)
+                                   {
+                                   goto error ;
+                                   }
+                                 */
+                                status = CR_OK;
+                                break;
+                        } else {
+                                goto error;
+                        }
+                }
+
+                if (next_byte == '/' || next_byte == ',') {
+                        READ_NEXT_BYTE (a_this, &operator);
+                }
+
+                cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+                status = cr_parser_parse_term (a_this, &expr2);
+
+                if (status != CR_OK || expr2 == NULL) {
+                        status = CR_OK;
+                        break;
+                }
+
+                switch (operator) {
+                case '/':
+                        expr2->the_operator = DIVIDE;
+                        break;
+                case ',':
+                        expr2->the_operator = COMMA;
+
+                default:
+                        break;
+                }
+
+                expr = cr_term_append_term (expr, expr2);
+                expr2 = NULL;
+                operator = 0;
+                nb_terms++;
+        }
+
+        if (status == CR_OK) {
+                *a_expr = cr_term_append_term (*a_expr, expr);
+                expr = NULL;
+
+                cr_parser_clear_errors (a_this);
+                return CR_OK;
+        }
+
+      error:
+
+        if (expr) {
+                cr_term_destroy (expr);
+                expr = NULL;
+        }
+
+        if (expr2) {
+                cr_term_destroy (expr2);
+                expr2 = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/**
+ * cr_parser_parse_prio:
+ *@a_this: the current instance of #CRParser.
+ *@a_prio: a string representing the priority.
+ *Today, only "!important" is returned as only this
+ *priority is defined by css2.
+ *
+ *Parses a declaration priority as defined by
+ *the css2 grammar in appendix C:
+ *prio: IMPORTANT_SYM S*
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_prio (CRParser * a_this, CRString ** a_prio)
+{
+        enum CRStatus status = CR_ERROR;
+        CRInputPos init_pos;
+        CRToken *token = NULL;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_prio
+                              && *a_prio == NULL, CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        if (status == CR_END_OF_INPUT_ERROR) {
+                goto error;
+        }
+        ENSURE_PARSING_COND (status == CR_OK
+                             && token && token->type == IMPORTANT_SYM_TK);
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+        *a_prio = cr_string_new_from_string ("!important");
+        cr_token_destroy (token);
+        token = NULL;
+        return CR_OK;
+
+      error:
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/**
+ * cr_parser_parse_declaration:
+ *@a_this: the "this pointer" of the current instance of #CRParser.
+ *@a_property: the successfully parsed property. The caller
+ * *must* free the returned pointer.
+ *@a_expr: the expression that represents the attribute value.
+ *The caller *must* free the returned pointer.
+ *
+ *TODO: return the parsed priority, so that
+ *upper layers can take benefit from it.
+ *Parses a "declaration" as defined by the css2 spec in appendix D.1:
+ *declaration ::= [property ':' S* expr prio?]?
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_declaration (CRParser * a_this,
+                             CRString ** a_property,
+                             CRTerm ** a_expr, gboolean * a_important)
+{
+        enum CRStatus status = CR_ERROR;
+        CRInputPos init_pos;
+        guint32 cur_char = 0;
+        CRTerm *expr = NULL;
+        CRString *prio = NULL;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_property && a_expr
+                              && a_important, CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_parser_parse_property (a_this, a_property);
+
+        if (status == CR_END_OF_INPUT_ERROR)
+                goto error;
+
+        CHECK_PARSING_STATUS_ERR
+                (a_this, status, FALSE,
+                 (const guchar *) "while parsing declaration: next property is malformed",
+                 CR_SYNTAX_ERROR);
+
+        READ_NEXT_CHAR (a_this, &cur_char);
+
+        if (cur_char != ':') {
+                status = CR_PARSING_ERROR;
+                cr_parser_push_error
+                        (a_this,
+                         (const guchar *) "while parsing declaration: this char must be ':'",
+                         CR_SYNTAX_ERROR);
+                goto error;
+        }
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        status = cr_parser_parse_expr (a_this, &expr);
+
+        CHECK_PARSING_STATUS_ERR
+                (a_this, status, FALSE,
+                 (const guchar *) "while parsing declaration: next expression is malformed",
+                 CR_SYNTAX_ERROR);
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+        status = cr_parser_parse_prio (a_this, &prio);
+        if (prio) {
+                cr_string_destroy (prio);
+                prio = NULL;
+                *a_important = TRUE;
+        } else {
+                *a_important = FALSE;
+        }
+        if (*a_expr) {
+                cr_term_append_term (*a_expr, expr);
+                expr = NULL;
+        } else {
+                *a_expr = expr;
+                expr = NULL;
+        }
+
+        cr_parser_clear_errors (a_this);
+        return CR_OK;
+
+      error:
+
+        if (expr) {
+                cr_term_destroy (expr);
+                expr = NULL;
+        }
+
+        if (*a_property) {
+                cr_string_destroy (*a_property);
+                *a_property = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/**
+ * cr_parser_parse_statement_core:
+ *@a_this: the current instance of #CRParser.
+ *
+ *Parses a statement as defined by the css core grammar in
+ *chapter 4.1 of the css2 spec.
+ *statement   : ruleset | at-rule;
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_statement_core (CRParser * a_this)
+{
+        CRToken *token = NULL;
+        CRInputPos init_pos;
+        enum CRStatus status = CR_ERROR;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+
+        ENSURE_PARSING_COND (status == CR_OK && token);
+
+        switch (token->type) {
+        case ATKEYWORD_TK:
+        case IMPORT_SYM_TK:
+        case PAGE_SYM_TK:
+        case MEDIA_SYM_TK:
+        case FONT_FACE_SYM_TK:
+        case CHARSET_SYM_TK:
+                cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
+                token = NULL;
+                status = cr_parser_parse_atrule_core (a_this);
+                CHECK_PARSING_STATUS (status, TRUE);
+                break;
+
+        default:
+                cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
+                token = NULL;
+                status = cr_parser_parse_ruleset_core (a_this);
+                cr_parser_clear_errors (a_this);
+                CHECK_PARSING_STATUS (status, TRUE);
+        }
+
+        return CR_OK;
+
+      error:
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/**
+ * cr_parser_parse_ruleset:
+ *@a_this: the "this pointer" of the current instance of #CRParser.
+ *
+ *Parses a "ruleset" as defined in the css2 spec at appendix D.1.
+ *ruleset ::= selector [ ',' S* selector ]* 
+ *'{' S* declaration? [ ';' S* declaration? ]* '}' S*;
+ *
+ *This methods calls the the SAC handler on the relevant SAC handler
+ *callbacks whenever it encounters some specific constructions.
+ *See the documentation of #CRDocHandler (the SAC handler) to know
+ *when which SAC handler is called.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_ruleset (CRParser * a_this)
+{
+        enum CRStatus status = CR_OK;
+        CRInputPos init_pos;
+        guint32 cur_char = 0,
+                next_char = 0;
+        CRString *property = NULL;
+        CRTerm *expr = NULL;
+        CRSimpleSel *simple_sels = NULL;
+        CRSelector *selector = NULL;
+        gboolean start_selector = FALSE,
+                is_important = FALSE;
+        CRParsingLocation end_parsing_location;
+
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_parser_parse_selector (a_this, &selector);
+        CHECK_PARSING_STATUS (status, FALSE);
+
+        READ_NEXT_CHAR (a_this, &cur_char);
+
+        ENSURE_PARSING_COND_ERR
+                (a_this, cur_char == '{',
+                 (const guchar *) "while parsing rulset: current char should be '{'",
+                 CR_SYNTAX_ERROR);
+
+        if (PRIVATE (a_this)->sac_handler
+            && PRIVATE (a_this)->sac_handler->start_selector) {
+                /*
+                 *the selector is ref counted so that the parser's user
+                 *can choose to keep it.
+                 */
+                if (selector) {
+                        cr_selector_ref (selector);
+                }
+
+                PRIVATE (a_this)->sac_handler->start_selector
+                        (PRIVATE (a_this)->sac_handler, selector);
+                start_selector = TRUE;
+        }
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        PRIVATE (a_this)->state = TRY_PARSE_RULESET_STATE;
+
+        status = cr_parser_parse_declaration (a_this, &property,
+                                              &expr,
+                                              &is_important);
+        if (expr) {
+                cr_term_ref (expr);
+        }
+        if (status == CR_OK
+            && PRIVATE (a_this)->sac_handler
+            && PRIVATE (a_this)->sac_handler->property) {
+                PRIVATE (a_this)->sac_handler->property
+                        (PRIVATE (a_this)->sac_handler, property, expr,
+                         is_important);
+        }        
+        if (status == CR_OK) {
+                /*
+                 *free the allocated
+                 *'property' and 'term' before parsing
+                 *next declarations.
+                 */
+                if (property) {
+                        cr_string_destroy (property);
+                        property = NULL;
+                }
+                if (expr) {
+                        cr_term_unref (expr);
+                        expr = NULL;
+                }
+        } else {/*status != CR_OK*/                
+                guint32 c = 0 ;
+                /*
+                 *test if we have reached '}', which
+                 *would mean that we are parsing an empty ruleset (eg. x{ })
+                 *In that case, goto end_of_ruleset.
+                 */
+                status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, &c) ;
+                if (status == CR_OK && c == '}') {
+                        status = CR_OK ;
+                        goto end_of_ruleset ;
+                }
+        }
+        CHECK_PARSING_STATUS_ERR
+                (a_this, status, FALSE,
+                 (const guchar *) "while parsing ruleset: next construction should be a declaration",
+                 CR_SYNTAX_ERROR);
+
+        for (;;) {
+                PEEK_NEXT_CHAR (a_this, &next_char);
+                if (next_char != ';')
+                        break;
+
+                /*consume the ';' char */
+                READ_NEXT_CHAR (a_this, &cur_char);
+
+                cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+                status = cr_parser_parse_declaration (a_this, &property,
+                                                      &expr, &is_important);
+
+                if (expr) {
+                        cr_term_ref (expr);
+                }
+                if (status == CR_OK
+                    && PRIVATE (a_this)->sac_handler
+                    && PRIVATE (a_this)->sac_handler->property) {
+                        PRIVATE (a_this)->sac_handler->property
+                                (PRIVATE (a_this)->sac_handler,
+                                 property, expr, is_important);
+                }
+                if (property) {
+                        cr_string_destroy (property);
+                        property = NULL;
+                }
+                if (expr) {
+                        cr_term_unref (expr);
+                        expr = NULL;
+                }
+        }
+
+ end_of_ruleset:
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+        cr_parser_get_parsing_location (a_this, &end_parsing_location);
+        READ_NEXT_CHAR (a_this, &cur_char);
+        ENSURE_PARSING_COND_ERR
+                (a_this, cur_char == '}',
+                 (const guchar *) "while parsing rulset: current char must be a '}'",
+                 CR_SYNTAX_ERROR);
+
+        selector->location = end_parsing_location;
+        if (PRIVATE (a_this)->sac_handler
+            && PRIVATE (a_this)->sac_handler->end_selector) {
+                PRIVATE (a_this)->sac_handler->end_selector
+                        (PRIVATE (a_this)->sac_handler, selector);
+                start_selector = FALSE;
+        }
+
+        if (expr) {
+                cr_term_unref (expr);
+                expr = NULL;
+        }
+
+        if (simple_sels) {
+                cr_simple_sel_destroy (simple_sels);
+                simple_sels = NULL;
+        }
+
+        if (selector) {
+                cr_selector_unref (selector);
+                selector = NULL;
+        }
+
+        cr_parser_clear_errors (a_this);
+        PRIVATE (a_this)->state = RULESET_PARSED_STATE;
+
+        return CR_OK;
+
+ error:
+        if (start_selector == TRUE
+            && PRIVATE (a_this)->sac_handler
+            && PRIVATE (a_this)->sac_handler->error) {
+                PRIVATE (a_this)->sac_handler->error
+                        (PRIVATE (a_this)->sac_handler);
+        }
+        if (expr) {
+                cr_term_unref (expr);
+                expr = NULL;
+        }
+        if (simple_sels) {
+                cr_simple_sel_destroy (simple_sels);
+                simple_sels = NULL;
+        }
+        if (property) {
+                cr_string_destroy (property);
+        }
+        if (selector) {
+                cr_selector_unref (selector);
+                selector = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/**
+ * cr_parser_parse_import:
+ *@a_this: the "this pointer" of the current instance 
+ *of #CRParser.
+ *@a_media_list: out parameter. A linked list of 
+ *#CRString
+ *Each CRString is a string that contains
+ *a 'medium' declaration part of the successfully 
+ *parsed 'import' declaration.
+ *@a_import_string: out parameter. 
+ *A string that contains the 'import 
+ *string". The import string can be either an uri (if it starts with
+ *the substring "uri(") or a any other css2 string. Note that
+ * *a_import_string must be initially set to NULL or else, this function
+ *will return CR_BAD_PARAM_ERROR.
+ *@a_location: the location (line, column) where the import has been parsed
+ *
+ *Parses an 'import' declaration as defined in the css2 spec
+ *in appendix D.1:
+ *
+ *import ::=
+ *\@import [STRING|URI] S* [ medium [ ',' S* medium]* ]? ';' S*
+ *
+ *Returns CR_OK upon sucessfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_import (CRParser * a_this,
+                        GList ** a_media_list,
+                        CRString ** a_import_string,
+                        CRParsingLocation *a_location)
+{
+        enum CRStatus status = CR_OK;
+        CRInputPos init_pos;
+        guint32 cur_char = 0,
+                next_char = 0;
+        CRString *medium = NULL;
+
+        g_return_val_if_fail (a_this
+                              && a_import_string
+                              && (*a_import_string == NULL),
+                              CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        if (BYTE (a_this, 1, NULL) == '@'
+            && BYTE (a_this, 2, NULL) == 'i'
+            && BYTE (a_this, 3, NULL) == 'm'
+            && BYTE (a_this, 4, NULL) == 'p'
+            && BYTE (a_this, 5, NULL) == 'o'
+            && BYTE (a_this, 6, NULL) == 'r'
+            && BYTE (a_this, 7, NULL) == 't') {
+                SKIP_CHARS (a_this, 1);
+                if (a_location) {
+                        cr_parser_get_parsing_location 
+                                (a_this, a_location) ;
+                }
+                SKIP_CHARS (a_this, 6);
+                status = CR_OK;
+        } else {
+                status = CR_PARSING_ERROR;
+                goto error;
+        }
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        PRIVATE (a_this)->state = TRY_PARSE_IMPORT_STATE;
+
+        PEEK_NEXT_CHAR (a_this, &next_char);
+
+        if (next_char == '"' || next_char == '\'') {
+                status = cr_parser_parse_string (a_this, a_import_string);
+
+                CHECK_PARSING_STATUS (status, FALSE);
+        } else {
+                status = cr_parser_parse_uri (a_this, a_import_string);
+
+                CHECK_PARSING_STATUS (status, FALSE);
+        }
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        status = cr_parser_parse_ident (a_this, &medium);
+
+        if (status == CR_OK && medium) {
+                *a_media_list = g_list_append (*a_media_list, medium);
+                medium = NULL;
+        }
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        for (; status == CR_OK;) {
+                if ((status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr,
+                                                  &next_char)) != CR_OK) {
+                        if (status == CR_END_OF_INPUT_ERROR) {
+                                status = CR_OK;
+                                goto okay;
+                        }
+                        goto error;
+                }
+
+                if (next_char == ',') {
+                        READ_NEXT_CHAR (a_this, &cur_char);
+                } else {
+                        break;
+                }
+
+                cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+                status = cr_parser_parse_ident (a_this, &medium);
+
+                cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+                if ((status == CR_OK) && medium) {
+                        *a_media_list = g_list_append (*a_media_list, medium);
+
+                        medium = NULL;
+                }
+
+                CHECK_PARSING_STATUS (status, FALSE);
+                cr_parser_try_to_skip_spaces_and_comments (a_this);
+        }
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+        READ_NEXT_CHAR (a_this, &cur_char);
+        ENSURE_PARSING_COND (cur_char == ';');
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+      okay:
+        cr_parser_clear_errors (a_this);
+        PRIVATE (a_this)->state = IMPORT_PARSED_STATE;
+
+        return CR_OK;
+
+      error:
+
+        if (*a_media_list) {
+                GList *cur = NULL;
+
+                /*
+                 *free each element of *a_media_list.
+                 *Note that each element of *a_medium list *must*
+                 *be a GString* or else, the code that is coming next 
+                 *will corrupt the memory and lead to hard to debug
+                 *random crashes.
+                 *This is where C++ and its compile time
+                 *type checking mecanism (through STL containers) would
+                 *have prevented us to go through this hassle.
+                 */
+                for (cur = *a_media_list; cur; cur = cur->next) {
+                        if (cur->data) {
+                                cr_string_destroy (cur->data);
+                        }
+                }
+
+                g_list_free (*a_media_list);
+                *a_media_list = NULL;
+        }
+
+        if (*a_import_string) {
+                cr_string_destroy (*a_import_string);
+                *a_import_string = NULL;
+        }
+
+        if (medium) {
+                cr_string_destroy (medium);
+                medium = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/**
+ * cr_parser_parse_media:
+ *@a_this: the "this pointer" of the current instance of #CRParser.
+ *
+ *Parses a 'media' declaration as specified in the css2 spec at
+ *appendix D.1:
+ *
+ *media ::= \@media S* medium [ ',' S* medium ]* '{' S* ruleset* '}' S*
+ *
+ *Note that this function calls the required sac handlers during the parsing
+ *to notify media productions. See #CRDocHandler to know the callback called
+ *during \@media parsing.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_media (CRParser * a_this)
+{
+        enum CRStatus status = CR_OK;
+        CRInputPos init_pos;
+        CRToken *token = NULL;
+        guint32 next_char = 0,
+                cur_char = 0;
+        CRString *medium = NULL;
+        GList *media_list = NULL;
+        CRParsingLocation location = {0} ;
+
+        g_return_val_if_fail (a_this 
+                              && PRIVATE (a_this), 
+                              CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 
+                                          &token);
+        ENSURE_PARSING_COND (status == CR_OK
+                             && token 
+                             && token->type == MEDIA_SYM_TK);
+        cr_parsing_location_copy (&location, &token->location) ;
+        cr_token_destroy (token);
+        token = NULL;
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        ENSURE_PARSING_COND (status == CR_OK
+                             && token && token->type == IDENT_TK);
+
+        medium = token->u.str;
+        token->u.str = NULL;
+        cr_token_destroy (token);
+        token = NULL;
+
+        if (medium) {
+                media_list = g_list_append (media_list, medium);
+                medium = NULL;
+        }
+
+        for (; status == CR_OK;) {
+                cr_parser_try_to_skip_spaces_and_comments (a_this);
+                PEEK_NEXT_CHAR (a_this, &next_char);
+
+                if (next_char == ',') {
+                        READ_NEXT_CHAR (a_this, &cur_char);
+                } else {
+                        break;
+                }
+
+                cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+                status = cr_parser_parse_ident (a_this, &medium);
+
+                CHECK_PARSING_STATUS (status, FALSE);
+
+                if (medium) {
+                        media_list = g_list_append (media_list, medium);
+                        medium = NULL;
+                }
+        }
+
+        READ_NEXT_CHAR (a_this, &cur_char);
+
+        ENSURE_PARSING_COND (cur_char == '{');
+
+        /*
+         *call the SAC handler api here.
+         */
+        if (PRIVATE (a_this)->sac_handler
+            && PRIVATE (a_this)->sac_handler->start_media) {
+                PRIVATE (a_this)->sac_handler->start_media
+                        (PRIVATE (a_this)->sac_handler, media_list,
+                         &location);
+        }
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        PRIVATE (a_this)->state = TRY_PARSE_MEDIA_STATE;
+
+        for (; status == CR_OK;) {
+                status = cr_parser_parse_ruleset (a_this);
+                cr_parser_try_to_skip_spaces_and_comments (a_this);
+        }
+
+        READ_NEXT_CHAR (a_this, &cur_char);
+
+        ENSURE_PARSING_COND (cur_char == '}');
+
+        /*
+         *call the right SAC handler api here.
+         */
+        if (PRIVATE (a_this)->sac_handler
+            && PRIVATE (a_this)->sac_handler->end_media) {
+                PRIVATE (a_this)->sac_handler->end_media
+                        (PRIVATE (a_this)->sac_handler, media_list);
+        }
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        /*
+         *Then, free the data structures passed to
+         *the last call to the SAC handler.
+         */
+        if (medium) {
+                cr_string_destroy (medium);
+                medium = NULL;
+        }
+
+        if (media_list) {
+                GList *cur = NULL;
+
+                for (cur = media_list; cur; cur = cur->next) {
+                        cr_string_destroy (cur->data);
+                }
+
+                g_list_free (media_list);
+                media_list = NULL;
+        }
+
+        cr_parser_clear_errors (a_this);
+        PRIVATE (a_this)->state = MEDIA_PARSED_STATE;
+
+        return CR_OK;
+
+      error:
+
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        if (medium) {
+                cr_string_destroy (medium);
+                medium = NULL;
+        }
+
+        if (media_list) {
+                GList *cur = NULL;
+
+                for (cur = media_list; cur; cur = cur->next) {
+                        cr_string_destroy (cur->data);
+                }
+
+                g_list_free (media_list);
+                media_list = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/**
+ * cr_parser_parse_page:
+ *@a_this: the "this pointer" of the current instance of #CRParser.
+ *
+ *Parses '\@page' rule as specified in the css2 spec in appendix D.1:
+ *page ::= PAGE_SYM S* IDENT? pseudo_page? S* 
+ *'{' S* declaration [ ';' S* declaration ]* '}' S*
+ *
+ *This function also calls the relevant SAC handlers whenever it
+ *encounters a construction that must 
+ *be reported to the calling application.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_page (CRParser * a_this)
+{
+        enum CRStatus status = CR_OK;
+        CRInputPos init_pos;
+        CRToken *token = NULL;
+        CRTerm *css_expression = NULL;
+        CRString *page_selector = NULL,
+                *page_pseudo_class = NULL,
+                *property = NULL;
+        gboolean important = TRUE;
+        CRParsingLocation location = {0} ;
+
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 
+                                          &token) ;
+        ENSURE_PARSING_COND (status == CR_OK
+                             && token 
+                             && token->type == PAGE_SYM_TK);
+
+        cr_parsing_location_copy (&location, &token->location) ;
+        cr_token_destroy (token);
+        token = NULL;
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        ENSURE_PARSING_COND (status == CR_OK && token);
+
+        if (token->type == IDENT_TK) {
+                page_selector = token->u.str;
+                token->u.str = NULL;
+                cr_token_destroy (token);
+                token = NULL;
+        } else {
+                cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
+                token = NULL;
+        }
+
+        /* 
+         *try to parse pseudo_page
+         */
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        ENSURE_PARSING_COND (status == CR_OK && token);
+
+        if (token->type == DELIM_TK && token->u.unichar == ':') {
+                cr_token_destroy (token);
+                token = NULL;
+                status = cr_parser_parse_ident (a_this, &page_pseudo_class);
+                CHECK_PARSING_STATUS (status, FALSE);
+        } else {
+                cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
+                token = NULL;
+        }
+
+        /*
+         *parse_block
+         *
+         */
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+
+        ENSURE_PARSING_COND (status == CR_OK && token
+                             && token->type == CBO_TK);
+
+        cr_token_destroy (token);
+        token = NULL;
+
+        /*
+         *Call the appropriate SAC handler here.
+         */
+        if (PRIVATE (a_this)->sac_handler
+            && PRIVATE (a_this)->sac_handler->start_page) {
+                PRIVATE (a_this)->sac_handler->start_page
+                        (PRIVATE (a_this)->sac_handler,
+                         page_selector, page_pseudo_class,
+                         &location);
+        }
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        PRIVATE (a_this)->state = TRY_PARSE_PAGE_STATE;
+
+        status = cr_parser_parse_declaration (a_this, &property,
+                                              &css_expression, 
+                                              &important);
+        ENSURE_PARSING_COND (status == CR_OK);
+
+        /*
+         *call the relevant SAC handler here...
+         */
+        if (PRIVATE (a_this)->sac_handler
+            && PRIVATE (a_this)->sac_handler->property) {
+                if (css_expression)
+                        cr_term_ref (css_expression);
+
+                PRIVATE (a_this)->sac_handler->property
+                        (PRIVATE (a_this)->sac_handler,
+                         property, css_expression, important);
+        }
+        /*
+         *... and free the data structure passed to that last
+         *SAC handler.
+         */
+        if (property) {
+                cr_string_destroy (property);
+                property = NULL;
+        }
+        if (css_expression) {
+                cr_term_unref (css_expression);
+                css_expression = NULL;
+        }
+
+        for (;;) {
+                /*parse the other ';' separated declarations */
+                if (token) {
+                        cr_token_destroy (token);
+                        token = NULL;
+                }
+                status = cr_tknzr_get_next_token
+                        (PRIVATE (a_this)->tknzr, &token);
+
+                ENSURE_PARSING_COND (status == CR_OK && token);
+
+                if (token->type != SEMICOLON_TK) {
+                        cr_tknzr_unget_token
+                                (PRIVATE (a_this)->tknzr,
+                                 token);
+                        token = NULL ;
+                        break;
+                }
+
+                cr_token_destroy (token);
+                token = NULL;
+                cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+                status = cr_parser_parse_declaration (a_this, &property,
+                                                      &css_expression,
+                                                      &important);
+                if (status != CR_OK)
+                        break ;
+
+                /*
+                 *call the relevant SAC handler here...
+                 */
+                if (PRIVATE (a_this)->sac_handler
+                    && PRIVATE (a_this)->sac_handler->property) {
+                        cr_term_ref (css_expression);
+                        PRIVATE (a_this)->sac_handler->property
+                                (PRIVATE (a_this)->sac_handler,
+                                 property, css_expression, important);
+                }
+                /*
+                 *... and free the data structure passed to that last
+                 *SAC handler.
+                 */
+                if (property) {
+                        cr_string_destroy (property);
+                        property = NULL;
+                }
+                if (css_expression) {
+                        cr_term_unref (css_expression);
+                        css_expression = NULL;
+                }
+        }
+        cr_parser_try_to_skip_spaces_and_comments 
+                (a_this) ;
+        if (token) {
+                cr_token_destroy (token) ;
+                token = NULL ;
+        }
+
+        status = cr_tknzr_get_next_token
+                        (PRIVATE (a_this)->tknzr, &token);
+        ENSURE_PARSING_COND (status == CR_OK 
+                             && token 
+                             && token->type == CBC_TK) ;
+        cr_token_destroy (token) ;
+        token = NULL ;
+        /*
+         *call the relevant SAC handler here.
+         */
+        if (PRIVATE (a_this)->sac_handler
+            && PRIVATE (a_this)->sac_handler->end_page) {
+                PRIVATE (a_this)->sac_handler->end_page
+                        (PRIVATE (a_this)->sac_handler,
+                         page_selector, page_pseudo_class);
+        }
+
+        if (page_selector) {
+                cr_string_destroy (page_selector);
+                page_selector = NULL;
+        }
+
+        if (page_pseudo_class) {
+                cr_string_destroy (page_pseudo_class);
+                page_pseudo_class = NULL;
+        }
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        /*here goes the former implem of this function ... */
+
+        cr_parser_clear_errors (a_this);
+        PRIVATE (a_this)->state = PAGE_PARSED_STATE;
+
+        return CR_OK;
+
+ error:
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+        if (page_selector) {
+                cr_string_destroy (page_selector);
+                page_selector = NULL;
+        }
+        if (page_pseudo_class) {
+                cr_string_destroy (page_pseudo_class);
+                page_pseudo_class = NULL;
+        }
+        if (property) {
+                cr_string_destroy (property);
+                property = NULL;
+        }
+        if (css_expression) {
+                cr_term_destroy (css_expression);
+                css_expression = NULL;
+        }
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+        return status;
+}
+
+/**
+ * cr_parser_parse_charset:
+ *@a_this: the "this pointer" of the current instance of #CRParser.
+ *@a_value: out parameter. The actual parsed value of the charset 
+ *declararation. Note that for safety check reasons, *a_value must be
+ *set to NULL.
+ *@a_charset_sym_location: the parsing location of the charset rule
+ *
+ *Parses a charset declaration as defined implictly by the css2 spec in
+ *appendix D.1:
+ *charset ::= CHARSET_SYM S* STRING S* ';'
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_charset (CRParser * a_this, CRString ** a_value,
+                         CRParsingLocation *a_charset_sym_location)
+{
+        enum CRStatus status = CR_OK;
+        CRInputPos init_pos;
+        CRToken *token = NULL;
+        CRString *charset_str = NULL;
+
+        g_return_val_if_fail (a_this && a_value
+                              && (*a_value == NULL), 
+                              CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+
+        ENSURE_PARSING_COND (status == CR_OK
+                             && token && token->type == CHARSET_SYM_TK);
+        if (a_charset_sym_location) {
+                cr_parsing_location_copy (a_charset_sym_location, 
+                                          &token->location) ;
+        }
+        cr_token_destroy (token);
+        token = NULL;
+
+        PRIVATE (a_this)->state = TRY_PARSE_CHARSET_STATE;
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        ENSURE_PARSING_COND (status == CR_OK
+                             && token && token->type == STRING_TK);
+        charset_str = token->u.str;
+        token->u.str = NULL;
+        cr_token_destroy (token);
+        token = NULL;
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+
+        ENSURE_PARSING_COND (status == CR_OK
+                             && token && token->type == SEMICOLON_TK);
+        cr_token_destroy (token);
+        token = NULL;
+
+        if (charset_str) {
+                *a_value = charset_str;
+                charset_str = NULL;
+        }
+
+        PRIVATE (a_this)->state = CHARSET_PARSED_STATE;
+        return CR_OK;
+
+ error:
+
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        if (*a_value) {
+                cr_string_destroy (*a_value);
+                *a_value = NULL;
+        }
+
+        if (charset_str) {
+                cr_string_destroy (charset_str);
+                charset_str = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+        return status;
+}
+
+/**
+ * cr_parser_parse_font_face:
+ *@a_this: the current instance of #CRParser.
+ *
+ *Parses the "\@font-face" rule specified in the css1 spec in
+ *appendix D.1:
+ *
+ *font_face ::= FONT_FACE_SYM S* 
+ *'{' S* declaration [ ';' S* declaration ]* '}' S*
+ *
+ *This function will call SAC handlers whenever it is necessary.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_font_face (CRParser * a_this)
+{
+        enum CRStatus status = CR_ERROR;
+        CRInputPos init_pos;
+        CRString *property = NULL;
+        CRTerm *css_expression = NULL;
+        CRToken *token = NULL;
+        gboolean important = FALSE;
+        guint32 next_char = 0,
+                cur_char = 0;
+        CRParsingLocation location = {0} ;
+
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+        ENSURE_PARSING_COND (status == CR_OK
+                             && token 
+                             && token->type == FONT_FACE_SYM_TK);
+
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+        if (token) {
+                cr_parsing_location_copy (&location, 
+                                          &token->location) ;
+                cr_token_destroy (token);
+                token = NULL;
+        }
+        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 
+                                          &token);
+        ENSURE_PARSING_COND (status == CR_OK && token
+                             && token->type == CBO_TK);
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+        /*
+         *here, call the relevant SAC handler.
+         */
+        if (PRIVATE (a_this)->sac_handler
+            && PRIVATE (a_this)->sac_handler->start_font_face) {
+                PRIVATE (a_this)->sac_handler->start_font_face
+                        (PRIVATE (a_this)->sac_handler, &location);
+        }
+        PRIVATE (a_this)->state = TRY_PARSE_FONT_FACE_STATE;
+        /*
+         *and resume the parsing.
+         */
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+        status = cr_parser_parse_declaration (a_this, &property,
+                                              &css_expression, &important);
+        if (status == CR_OK) {
+                /*
+                 *here, call the relevant SAC handler.
+                 */
+                cr_term_ref (css_expression);
+                if (PRIVATE (a_this)->sac_handler &&
+                    PRIVATE (a_this)->sac_handler->property) {
+                        PRIVATE (a_this)->sac_handler->property
+                                (PRIVATE (a_this)->sac_handler,
+                                 property, css_expression, important);
+                }
+                ENSURE_PARSING_COND (css_expression && property);
+        }
+        /*free the data structures allocated during last parsing. */
+        if (property) {
+                cr_string_destroy (property);
+                property = NULL;
+        }
+        if (css_expression) {
+                cr_term_unref (css_expression);
+                css_expression = NULL;
+        }
+        for (;;) {
+                PEEK_NEXT_CHAR (a_this, &next_char);
+                if (next_char == ';') {
+                        READ_NEXT_CHAR (a_this, &cur_char);
+                } else {
+                        break;
+                }
+                cr_parser_try_to_skip_spaces_and_comments (a_this);
+                status = cr_parser_parse_declaration (a_this, 
+                                                      &property,
+                                                      &css_expression,
+                                                      &important);
+                if (status != CR_OK)
+                        break;
+                /*
+                 *here, call the relevant SAC handler.
+                 */
+                cr_term_ref (css_expression);
+                if (PRIVATE (a_this)->sac_handler->property) {
+                        PRIVATE (a_this)->sac_handler->property
+                                (PRIVATE (a_this)->sac_handler,
+                                 property, css_expression, important);
+                }
+                /*
+                 *Then, free the data structures allocated during 
+                 *last parsing.
+                 */
+                if (property) {
+                        cr_string_destroy (property);
+                        property = NULL;
+                }
+                if (css_expression) {
+                        cr_term_unref (css_expression);
+                        css_expression = NULL;
+                }
+        }
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+        READ_NEXT_CHAR (a_this, &cur_char);
+        ENSURE_PARSING_COND (cur_char == '}');
+        /*
+         *here, call the relevant SAC handler.
+         */
+        if (PRIVATE (a_this)->sac_handler->end_font_face) {
+                PRIVATE (a_this)->sac_handler->end_font_face
+                        (PRIVATE (a_this)->sac_handler);
+        }
+        cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+        cr_parser_clear_errors (a_this);
+        PRIVATE (a_this)->state = FONT_FACE_PARSED_STATE;
+        return CR_OK;
+
+      error:
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+        if (property) {
+                cr_string_destroy (property);
+                property = NULL;
+        }
+        if (css_expression) {
+                cr_term_destroy (css_expression);
+                css_expression = NULL;
+        }
+        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+        return status;
+}
+
+/**
+ * cr_parser_parse:
+ *@a_this: the current instance of #CRParser.
+ *
+ *Parses the data that comes from the
+ *input previously associated to the current instance of
+ *#CRParser.
+ *
+ *Returns CR_OK upon succesful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse (CRParser * a_this)
+{
+        enum CRStatus status = CR_ERROR;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR);
+
+        if (PRIVATE (a_this)->use_core_grammar == FALSE) {
+                status = cr_parser_parse_stylesheet (a_this);
+        } else {
+                status = cr_parser_parse_stylesheet_core (a_this);
+        }
+
+        return status;
+}
+
+/**
+ * cr_parser_set_tknzr:
+ * @a_this: the current instance of #CRParser;
+ * @a_tknzr: the new tokenizer.
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_set_tknzr (CRParser * a_this, CRTknzr * a_tknzr)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        if (PRIVATE (a_this)->tknzr) {
+                cr_tknzr_unref (PRIVATE (a_this)->tknzr);
+        }
+
+        PRIVATE (a_this)->tknzr = a_tknzr;
+
+        if (a_tknzr)
+                cr_tknzr_ref (a_tknzr);
+
+        return CR_OK;
+}
+
+/**
+ * cr_parser_get_tknzr:
+ *@a_this: the current instance of #CRParser
+ *@a_tknzr: out parameter. The returned tokenizer
+ *
+ *Getter of the parser's underlying tokenizer
+ * 
+ *Returns CR_OK upon succesful completion, an error code
+ *otherwise
+ */
+enum CRStatus
+cr_parser_get_tknzr (CRParser * a_this, CRTknzr ** a_tknzr)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_tknzr, CR_BAD_PARAM_ERROR);
+
+        *a_tknzr = PRIVATE (a_this)->tknzr;
+        return CR_OK;
+}
+
+/**
+ * cr_parser_get_parsing_location:
+ *@a_this: the current instance of #CRParser
+ *@a_loc: the parsing location to get.
+ *
+ *Gets the current parsing location.
+ *
+ *Returns CR_OK upon succesful completion, an error code
+ *otherwise.
+ */
+enum CRStatus 
+cr_parser_get_parsing_location (CRParser const *a_this,
+                                CRParsingLocation *a_loc)
+{
+        g_return_val_if_fail (a_this 
+                              && PRIVATE (a_this)
+                              && a_loc, CR_BAD_PARAM_ERROR) ;
+
+        return cr_tknzr_get_parsing_location 
+                (PRIVATE (a_this)->tknzr, a_loc) ;
+}
+
+/**
+ * cr_parser_parse_buf:
+ *@a_this: the current instance of #CRparser
+ *@a_buf: the input buffer
+ *@a_len: the length of the input buffer
+ *@a_enc: the encoding of the buffer
+ *
+ *Parses a stylesheet from a buffer
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_buf (CRParser * a_this,
+                     const guchar * a_buf,
+                     gulong a_len, enum CREncoding a_enc)
+{
+        enum CRStatus status = CR_ERROR;
+        CRTknzr *tknzr = NULL;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_buf, CR_BAD_PARAM_ERROR);
+
+        tknzr = cr_tknzr_new_from_buf ((guchar*)a_buf, a_len, a_enc, FALSE);
+
+        g_return_val_if_fail (tknzr != NULL, CR_ERROR);
+
+        status = cr_parser_set_tknzr (a_this, tknzr);
+        g_return_val_if_fail (status == CR_OK, CR_ERROR);
+
+        status = cr_parser_parse (a_this);
+
+        return status;
+}
+
+/**
+ * cr_parser_destroy:
+ *@a_this: the current instance of #CRParser to
+ *destroy.
+ *
+ *Destroys the current instance
+ *of #CRParser.
+ */
+void
+cr_parser_destroy (CRParser * a_this)
+{
+        g_return_if_fail (a_this && PRIVATE (a_this));
+
+        if (PRIVATE (a_this)->tknzr) {
+                if (cr_tknzr_unref (PRIVATE (a_this)->tknzr) == TRUE)
+                        PRIVATE (a_this)->tknzr = NULL;
+        }
+
+        if (PRIVATE (a_this)->sac_handler) {
+                cr_doc_handler_unref (PRIVATE (a_this)->sac_handler);
+                PRIVATE (a_this)->sac_handler = NULL;
+        }
+
+        if (PRIVATE (a_this)->err_stack) {
+                cr_parser_clear_errors (a_this);
+                PRIVATE (a_this)->err_stack = NULL;
+        }
+
+        if (PRIVATE (a_this)) {
+                g_free (PRIVATE (a_this));
+                PRIVATE (a_this) = NULL;
+        }
+
+        if (a_this) {
+                g_free (a_this);
+                a_this = NULL;  /*useless. Just for the sake of coherence */
+        }
+}
diff --git a/src/st/croco/cr-parser.h b/src/st/croco/cr-parser.h
new file mode 100644
index 000000000..6dce9439e
--- /dev/null
+++ b/src/st/croco/cr-parser.h
@@ -0,0 +1,128 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyrights information.
+ */
+
+#ifndef __CR_PARSER_H__
+#define  __CR_PARSER_H__
+
+#include <glib.h>
+#include "cr-input.h"
+#include "cr-tknzr.h"
+#include "cr-utils.h"
+#include "cr-doc-handler.h"
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *The declaration file
+ *of the #CRParser class.
+ */
+typedef struct _CRParser CRParser ;
+typedef struct _CRParserPriv CRParserPriv ;
+
+
+/**
+ *The implementation of
+ *the SAC parser.
+ *The Class is opaque
+ *and must be manipulated through
+ *the provided methods.
+ */
+struct _CRParser  {
+        CRParserPriv *priv ;
+} ;
+
+
+CRParser * cr_parser_new (CRTknzr *a_tknzr) ;
+
+CRParser * cr_parser_new_from_buf (guchar *a_buf, gulong a_len,
+                        enum CREncoding a_enc, 
+                        gboolean a_free_buf) ;
+
+CRParser * cr_parser_new_from_file (const guchar *a_file_uri, 
+                                    enum CREncoding a_enc) ;
+
+CRParser * cr_parser_new_from_input (CRInput *a_input) ;
+
+enum CRStatus cr_parser_set_tknzr (CRParser *a_this, CRTknzr *a_tknzr) ;
+
+enum CRStatus cr_parser_get_tknzr (CRParser *a_this, CRTknzr **a_tknzr) ;
+
+enum CRStatus cr_parser_get_parsing_location (CRParser const *a_this, CRParsingLocation *a_loc) ;
+
+enum CRStatus cr_parser_try_to_skip_spaces_and_comments (CRParser *a_this) ;
+
+
+enum CRStatus cr_parser_set_sac_handler (CRParser *a_this, 
+                                         CRDocHandler *a_handler) ;
+
+enum CRStatus cr_parser_get_sac_handler (CRParser *a_this, 
+                                         CRDocHandler **a_handler) ;
+
+enum CRStatus cr_parser_set_use_core_grammar (CRParser *a_this,
+                                              gboolean a_use_core_grammar) ;
+enum CRStatus cr_parser_get_use_core_grammar (CRParser const *a_this,
+                                              gboolean *a_use_core_grammar) ;
+
+enum CRStatus cr_parser_parse (CRParser *a_this) ;
+        
+enum CRStatus cr_parser_parse_file (CRParser *a_this, 
+                                    const guchar *a_file_uri, 
+                                    enum CREncoding a_enc) ;
+
+enum CRStatus cr_parser_parse_buf (CRParser *a_this, const guchar *a_buf, 
+                                   gulong a_len, enum CREncoding a_enc) ;
+
+enum CRStatus cr_parser_set_default_sac_handler (CRParser *a_this) ;
+
+enum CRStatus cr_parser_parse_term (CRParser *a_this, CRTerm **a_term) ;
+
+enum CRStatus cr_parser_parse_expr (CRParser *a_this, CRTerm **a_expr) ;
+
+enum CRStatus cr_parser_parse_prio (CRParser *a_this, CRString **a_prio) ;
+
+enum CRStatus cr_parser_parse_declaration (CRParser *a_this, CRString **a_property,
+                                           CRTerm **a_expr, gboolean *a_important) ;
+
+enum CRStatus cr_parser_parse_statement_core (CRParser *a_this) ;
+
+enum CRStatus cr_parser_parse_ruleset (CRParser *a_this) ;
+
+enum CRStatus cr_parser_parse_import (CRParser *a_this, GList ** a_media_list,
+                                      CRString **a_import_string,
+                                      CRParsingLocation *a_location) ;
+
+enum CRStatus cr_parser_parse_media (CRParser *a_this) ;
+
+enum CRStatus cr_parser_parse_page (CRParser *a_this) ;
+
+enum CRStatus cr_parser_parse_charset (CRParser *a_this, CRString **a_value,
+                                       CRParsingLocation *a_charset_sym_location) ;
+
+enum CRStatus cr_parser_parse_font_face (CRParser *a_this) ;
+
+void cr_parser_destroy (CRParser *a_this) ;
+        
+G_END_DECLS
+
+#endif /*__CR_PARSER_H__*/
diff --git a/src/st/croco/cr-parsing-location.c b/src/st/croco/cr-parsing-location.c
new file mode 100644
index 000000000..4fe4acc30
--- /dev/null
+++ b/src/st/croco/cr-parsing-location.c
@@ -0,0 +1,172 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli.
+ * See the COPYRIGHTS file for copyright information.
+ */
+
+#include <string.h>
+#include "cr-parsing-location.h"
+
+/**
+ *@CRParsingLocation:
+ *
+ *Definition of the #CRparsingLocation class.
+ */
+
+
+/**
+ * cr_parsing_location_new:
+ *Instanciates a new parsing location.
+ *
+ *Returns the newly instanciated #CRParsingLocation.
+ *Must be freed by cr_parsing_location_destroy()
+ */
+CRParsingLocation * 
+cr_parsing_location_new (void)
+{
+	CRParsingLocation * result = NULL ;
+
+	result = g_try_malloc (sizeof (CRParsingLocation)) ;
+	if (!result) {
+		cr_utils_trace_info ("Out of memory error") ;
+		return NULL ;
+	}
+	cr_parsing_location_init (result) ;
+	return result ;
+}
+
+/**
+ * cr_parsing_location_init:
+ *@a_this: the current instance of #CRParsingLocation.
+ *
+ *Initializes the an instance of #CRparsingLocation.
+ *
+ *Returns CR_OK upon succesful completion, an error code otherwise.
+ */
+enum CRStatus 
+cr_parsing_location_init (CRParsingLocation *a_this)
+{
+	g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+	memset (a_this, 0, sizeof (CRParsingLocation)) ;
+	return CR_OK ;
+}
+
+/**
+ * cr_parsing_location_copy:
+ *@a_to: the destination of the copy. 
+ *Must be allocated by the caller.
+ *@a_from: the source of the copy.
+ *
+ *Copies an instance of CRParsingLocation into another one.
+ *
+ *Returns CR_OK upon succesful completion, an error code
+ *otherwise.
+ */
+enum CRStatus 
+cr_parsing_location_copy (CRParsingLocation *a_to,
+			  CRParsingLocation const *a_from)
+{
+	g_return_val_if_fail (a_to && a_from, CR_BAD_PARAM_ERROR) ;
+
+	memcpy (a_to, a_from, sizeof (CRParsingLocation)) ;
+	return CR_OK ;
+}
+
+/**
+ * cr_parsing_location_to_string:
+ *@a_this: the current instance of #CRParsingLocation.
+ *@a_mask: a bitmap that defines which parts of the
+ *parsing location are to be serialized (line, column or byte offset)
+ *
+ *Returns the serialized string or NULL in case of an error.
+ */
+gchar * 
+cr_parsing_location_to_string (CRParsingLocation const *a_this,
+			       enum CRParsingLocationSerialisationMask a_mask)
+{
+	GString *result = NULL ;
+	gchar *str = NULL ;
+
+	g_return_val_if_fail (a_this, NULL) ;
+
+	if (!a_mask) {
+		a_mask = DUMP_LINE | DUMP_COLUMN | DUMP_BYTE_OFFSET ;
+	}
+	result =g_string_new (NULL) ;
+	if (!result)
+		return NULL ;
+	if (a_mask & DUMP_LINE) {
+		g_string_append_printf (result, "line:%d ", 
+					a_this->line) ;
+	}
+	if (a_mask & DUMP_COLUMN) {
+		g_string_append_printf (result, "column:%d ", 
+					a_this->column) ;
+	}
+	if (a_mask & DUMP_BYTE_OFFSET) {
+		g_string_append_printf (result, "byte offset:%d ", 
+					a_this->byte_offset) ;
+	}
+	if (result->len) {
+		str = result->str ;
+		g_string_free (result, FALSE) ;
+	} else {
+		g_string_free (result, TRUE) ;
+	}
+	return str ;
+}
+
+/**
+ * cr_parsing_location_dump:
+ * @a_this: current instance of #CRParsingLocation
+ * @a_mask: the serialization mask.
+ * @a_fp: the file pointer to dump the parsing location to.
+ */
+void
+cr_parsing_location_dump (CRParsingLocation const *a_this,
+			  enum CRParsingLocationSerialisationMask a_mask,
+			  FILE *a_fp)
+{
+	gchar *str = NULL ;
+
+	g_return_if_fail (a_this && a_fp) ;
+	str = cr_parsing_location_to_string (a_this, a_mask) ;
+	if (str) {
+		fprintf (a_fp, "%s", str) ;
+		g_free (str) ;
+		str = NULL ;
+	}
+}
+
+/**
+ * cr_parsing_location_destroy:
+ *@a_this: the current instance of #CRParsingLocation. Must
+ *have been allocated with cr_parsing_location_new().
+ *
+ *Destroys the current instance of #CRParsingLocation
+ */
+void 
+cr_parsing_location_destroy (CRParsingLocation *a_this)
+{
+	g_return_if_fail (a_this) ;
+	g_free (a_this) ;
+}
+
diff --git a/src/st/croco/cr-parsing-location.h b/src/st/croco/cr-parsing-location.h
new file mode 100644
index 000000000..b8064a560
--- /dev/null
+++ b/src/st/croco/cr-parsing-location.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli.
+ * See the COPYRIGHTS file for copyright information.
+ */
+
+#ifndef __CR_PARSING_LOCATION_H__
+#define __CR_PARSING_LOCATION_H__
+
+#include "cr-utils.h"
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *The declaration of the CRParsingLocation
+ *object. This object keeps track of line/column/byte offset/
+ *at which the parsing of a given CSS construction appears.
+ */
+
+typedef struct _CRParsingLocation CRParsingLocation;
+struct _CRParsingLocation {
+	guint line ;
+	guint column ;
+	guint byte_offset ;
+} ;
+
+
+enum CRParsingLocationSerialisationMask {
+	DUMP_LINE = 1,
+	DUMP_COLUMN = 1 << 1,
+	DUMP_BYTE_OFFSET = 1 << 2
+} ;
+
+CRParsingLocation * cr_parsing_location_new (void) ;
+
+enum CRStatus cr_parsing_location_init (CRParsingLocation *a_this) ;
+
+enum CRStatus cr_parsing_location_copy (CRParsingLocation *a_to,
+					CRParsingLocation const *a_from) ;
+
+gchar * cr_parsing_location_to_string (CRParsingLocation const *a_this,
+				       enum CRParsingLocationSerialisationMask a_mask) ;
+void cr_parsing_location_dump (CRParsingLocation const *a_this,
+			       enum CRParsingLocationSerialisationMask a_mask,
+			       FILE *a_fp) ;
+
+void cr_parsing_location_destroy (CRParsingLocation *a_this) ;
+
+
+
+G_END_DECLS
+#endif
diff --git a/src/st/croco/cr-prop-list.c b/src/st/croco/cr-prop-list.c
new file mode 100644
index 000000000..70a04f337
--- /dev/null
+++ b/src/st/croco/cr-prop-list.c
@@ -0,0 +1,404 @@
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyrights information.
+ */
+
+#include <string.h>
+#include "cr-prop-list.h"
+
+#define PRIVATE(a_obj) (a_obj)->priv
+
+struct _CRPropListPriv {
+        CRString *prop;
+        CRDeclaration *decl;
+        CRPropList *next;
+        CRPropList *prev;
+};
+
+static CRPropList *cr_prop_list_allocate (void);
+
+/**
+ *Default allocator of CRPropList
+ *@return the newly allocated CRPropList or NULL
+ *if an error arises.
+ */
+static CRPropList *
+cr_prop_list_allocate (void)
+{
+        CRPropList *result = NULL;
+
+        result = g_try_malloc (sizeof (CRPropList));
+        if (!result) {
+                cr_utils_trace_info ("could not allocate CRPropList");
+                return NULL;
+        }
+        memset (result, 0, sizeof (CRPropList));
+        PRIVATE (result) = g_try_malloc (sizeof (CRPropListPriv));
+        if (!result) {
+                cr_utils_trace_info ("could not allocate CRPropListPriv");
+                g_free (result);
+                return NULL;
+        }
+        memset (PRIVATE (result), 0, sizeof (CRPropListPriv));
+        return result;
+}
+
+/****************
+ *public methods
+ ***************/
+
+/**
+ * cr_prop_list_append:
+ *@a_this: the current instance of #CRPropList
+ *@a_to_append: the property list to append
+ *
+ *Appends a property list to the current one.
+ *
+ *Returns the resulting prop list, or NULL if an error
+ *occurred
+ */
+CRPropList *
+cr_prop_list_append (CRPropList * a_this, CRPropList * a_to_append)
+{
+        CRPropList *cur = NULL;
+
+        g_return_val_if_fail (a_to_append, NULL);
+
+        if (!a_this)
+                return a_to_append;
+
+        /*go fetch the last element of the list */
+        for (cur = a_this;
+             cur && PRIVATE (cur) && PRIVATE (cur)->next;
+             cur = PRIVATE (cur)->next) ;
+        g_return_val_if_fail (cur, NULL);
+        PRIVATE (cur)->next = a_to_append;
+        PRIVATE (a_to_append)->prev = cur;
+        return a_this;
+}
+
+/**
+ * cr_prop_list_append2:
+ *Appends a pair of prop/declaration to
+ *the current prop list.
+ *@a_this: the current instance of #CRPropList
+ *@a_prop: the property to consider
+ *@a_decl: the declaration to consider
+ *
+ *Returns the resulting property list, or NULL in case
+ *of an error.
+ */
+CRPropList *
+cr_prop_list_append2 (CRPropList * a_this,
+                      CRString * a_prop, 
+		      CRDeclaration * a_decl)
+{
+        CRPropList *list = NULL,
+                *result = NULL;
+
+        g_return_val_if_fail (a_prop && a_decl, NULL);
+
+        list = cr_prop_list_allocate ();
+        g_return_val_if_fail (list && PRIVATE (list), NULL);
+
+        PRIVATE (list)->prop = a_prop;
+        PRIVATE (list)->decl = a_decl;
+
+        result = cr_prop_list_append (a_this, list);
+        return result;
+}
+
+/**
+ * cr_prop_list_prepend:
+ *@a_this: the current instance of #CRPropList
+ *@a_to_prepend: the new list to prepend.
+ *
+ *Prepends a list to the current list
+ *Returns the new properties list.
+ */
+CRPropList *
+cr_prop_list_prepend (CRPropList * a_this, CRPropList * a_to_prepend)
+{
+        CRPropList *cur = NULL;
+
+        g_return_val_if_fail (a_to_prepend, NULL);
+
+        if (!a_this)
+                return a_to_prepend;
+
+        for (cur = a_to_prepend; cur && PRIVATE (cur)->next;
+             cur = PRIVATE (cur)->next) ;
+        g_return_val_if_fail (cur, NULL);
+        PRIVATE (cur)->next = a_this;
+        PRIVATE (a_this)->prev = cur;
+        return a_to_prepend;
+}
+
+/**
+ * cr_prop_list_prepend2:
+ *@a_this: the current instance of #CRPropList
+ *@a_prop_name: property name to append
+ *@a_decl: the property value to append.
+ *
+ *Prepends a propertie to a list of properties 
+ *
+ *Returns the new property list.
+ */
+CRPropList *
+cr_prop_list_prepend2 (CRPropList * a_this,
+                       CRString * a_prop_name, CRDeclaration * a_decl)
+{
+        CRPropList *list = NULL,
+                *result = NULL;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_prop_name && a_decl, NULL);
+
+        list = cr_prop_list_allocate ();
+        g_return_val_if_fail (list, NULL);
+        PRIVATE (list)->prop = a_prop_name;
+        PRIVATE (list)->decl = a_decl;
+        result = cr_prop_list_prepend (a_this, list);
+        return result;
+}
+
+/**
+ * cr_prop_list_set_prop:
+ *@a_this: the current instance of #CRPropList
+ *@a_prop: the property to set
+ *
+ *Sets the property of a CRPropList
+ */
+enum CRStatus
+cr_prop_list_set_prop (CRPropList * a_this, CRString * a_prop)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_prop, CR_BAD_PARAM_ERROR);
+
+        PRIVATE (a_this)->prop = a_prop;
+        return CR_OK;
+}
+
+/**
+ * cr_prop_list_get_prop:
+ *@a_this: the current instance of #CRPropList
+ *@a_prop: out parameter. The returned property
+ *
+ *Getter of the property associated to the current instance
+ *of #CRPropList
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_prop_list_get_prop (CRPropList const * a_this, CRString ** a_prop)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_prop, CR_BAD_PARAM_ERROR);
+
+        *a_prop = PRIVATE (a_this)->prop;
+        return CR_OK;
+}
+
+/**
+ * cr_prop_list_set_decl:
+ * @a_this: the current instance of #CRPropList
+ * @a_decl: the new property value.
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_prop_list_set_decl (CRPropList * a_this, CRDeclaration * a_decl)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_decl, CR_BAD_PARAM_ERROR);
+
+        PRIVATE (a_this)->decl = a_decl;
+        return CR_OK;
+}
+
+/**
+ * cr_prop_list_get_decl:
+ * @a_this: the current instance of #CRPropList
+ * @a_decl: out parameter. The property value
+ *
+ * Returns CR_OK upon successful completion.
+ */
+enum CRStatus
+cr_prop_list_get_decl (CRPropList const * a_this, CRDeclaration ** a_decl)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_decl, CR_BAD_PARAM_ERROR);
+
+        *a_decl = PRIVATE (a_this)->decl;
+        return CR_OK;
+}
+
+/**
+ * cr_prop_list_lookup_prop:
+ *@a_this: the current instance of #CRPropList
+ *@a_prop: the property to lookup
+ *@a_prop_list: out parameter. The property/declaration
+ *pair found (if and only if the function returned code if CR_OK)
+ *
+ *Lookup a given property/declaration pair
+ *
+ *Returns CR_OK if a prop/decl pair has been found,
+ *CR_VALUE_NOT_FOUND_ERROR if not, or an error code if something
+ *bad happens.
+ */
+enum CRStatus
+cr_prop_list_lookup_prop (CRPropList * a_this,
+                          CRString * a_prop, CRPropList ** a_pair)
+{
+        CRPropList *cur = NULL;
+
+        g_return_val_if_fail (a_prop && a_pair, CR_BAD_PARAM_ERROR);
+
+        if (!a_this)
+                return CR_VALUE_NOT_FOUND_ERROR;
+
+        g_return_val_if_fail (PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        for (cur = a_this; cur; cur = PRIVATE (cur)->next) {
+                if (PRIVATE (cur)->prop
+		    && PRIVATE (cur)->prop->stryng
+                    && PRIVATE (cur)->prop->stryng->str
+		    && a_prop->stryng
+                    && a_prop->stryng->str
+                    && !strcmp (PRIVATE (cur)->prop->stryng->str, 
+				a_prop->stryng->str))
+                        break;
+        }
+
+        if (cur) {
+                *a_pair = cur;
+                return CR_OK;
+        }
+
+        return CR_VALUE_NOT_FOUND_ERROR;
+}
+
+/**
+ * cr_prop_list_get_next:
+ *@a_this: the current instance of CRPropList
+ *
+ *Gets the next prop/decl pair in the list
+ *
+ *Returns the next prop/declaration pair of the list, 
+ *or NULL if we reached end of list (or if an error occurs)
+ */
+CRPropList *
+cr_prop_list_get_next (CRPropList * a_this)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this), NULL);
+
+        return PRIVATE (a_this)->next;
+}
+
+/**
+ * cr_prop_list_get_prev:
+ *@a_this: the current instance of CRPropList
+ *
+ *Gets the previous prop/decl pair in the list
+ *
+ *Returns the previous prop/declaration pair of the list, 
+ *or NULL if we reached end of list (or if an error occurs)
+ */
+CRPropList *
+cr_prop_list_get_prev (CRPropList * a_this)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this), NULL);
+
+        return PRIVATE (a_this)->prev;
+}
+
+/**
+ * cr_prop_list_unlink:
+ *@a_this: the current list of prop/decl pairs
+ *@a_pair: the prop/decl pair to unlink.
+ *
+ *Unlinks a prop/decl pair from the list
+ *
+ *Returns the new list or NULL in case of an error.
+ */
+CRPropList *
+cr_prop_list_unlink (CRPropList * a_this, CRPropList * a_pair)
+{
+        CRPropList *prev = NULL,
+                *next = NULL;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pair, NULL);
+
+        /*some sanity checks */
+        if (PRIVATE (a_pair)->next) {
+                next = PRIVATE (a_pair)->next;
+                g_return_val_if_fail (PRIVATE (next), NULL);
+                g_return_val_if_fail (PRIVATE (next)->prev == a_pair, NULL);
+        }
+        if (PRIVATE (a_pair)->prev) {
+                prev = PRIVATE (a_pair)->prev;
+                g_return_val_if_fail (PRIVATE (prev), NULL);
+                g_return_val_if_fail (PRIVATE (prev)->next == a_pair, NULL);
+        }
+        if (prev) {
+                PRIVATE (prev)->next = next;
+        }
+        if (next) {
+                PRIVATE (next)->prev = prev;
+        }
+        PRIVATE (a_pair)->prev = PRIVATE (a_pair)->next = NULL;
+        if (a_this == a_pair) {
+                if (next)
+                        return next;
+                return NULL;
+        }
+        return a_this;
+}
+
+/**
+ * cr_prop_list_destroy:
+ * @a_this: the current instance of #CRPropList
+ */
+void
+cr_prop_list_destroy (CRPropList * a_this)
+{
+        CRPropList *tail = NULL,
+                *cur = NULL;
+
+        g_return_if_fail (a_this && PRIVATE (a_this));
+
+        for (tail = a_this;
+             tail && PRIVATE (tail) && PRIVATE (tail)->next;
+             tail = cr_prop_list_get_next (tail)) ;
+        g_return_if_fail (tail);
+
+        cur = tail;
+
+        while (cur) {
+                tail = PRIVATE (cur)->prev;
+                if (tail && PRIVATE (tail))
+                        PRIVATE (tail)->next = NULL;
+                PRIVATE (cur)->prev = NULL;
+                g_free (PRIVATE (cur));
+                PRIVATE (cur) = NULL;
+                g_free (cur);
+                cur = tail;
+        }
+}
diff --git a/src/st/croco/cr-prop-list.h b/src/st/croco/cr-prop-list.h
new file mode 100644
index 000000000..797ba43ea
--- /dev/null
+++ b/src/st/croco/cr-prop-list.h
@@ -0,0 +1,80 @@
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyrights information.
+ */
+
+#ifndef __CR_PROP_LIST_H__
+#define __CR_PROP_LIST_H__
+
+#include "cr-utils.h"
+#include "cr-declaration.h"
+#include "cr-string.h"
+
+G_BEGIN_DECLS
+
+typedef struct _CRPropList CRPropList ;
+typedef struct _CRPropListPriv CRPropListPriv ;
+
+struct _CRPropList 
+{
+	CRPropListPriv * priv;
+} ;
+
+CRPropList * cr_prop_list_append (CRPropList *a_this,
+				  CRPropList *a_to_append) ;
+
+CRPropList * cr_prop_list_append2 (CRPropList *a_this,
+				   CRString *a_prop,
+				   CRDeclaration *a_decl) ;
+
+CRPropList * cr_prop_list_prepend (CRPropList *a_this,
+				   CRPropList *a_to_append) ;
+
+CRPropList *  cr_prop_list_prepend2 (CRPropList *a_this,
+				     CRString *a_prop,
+				     CRDeclaration *a_decl) ;
+
+enum CRStatus cr_prop_list_set_prop (CRPropList *a_this,
+				     CRString *a_prop) ;
+
+enum CRStatus cr_prop_list_get_prop (CRPropList const *a_this,
+				     CRString **a_prop) ;
+
+enum CRStatus cr_prop_list_lookup_prop (CRPropList *a_this,
+					CRString *a_prop,
+					CRPropList**a_pair) ;
+
+CRPropList * cr_prop_list_get_next (CRPropList *a_this) ;
+
+CRPropList * cr_prop_list_get_prev (CRPropList *a_this) ;
+
+enum CRStatus cr_prop_list_set_decl (CRPropList *a_this,
+				     CRDeclaration *a_decl);
+
+enum CRStatus cr_prop_list_get_decl (CRPropList const *a_this,
+				     CRDeclaration **a_decl) ;
+
+CRPropList * cr_prop_list_unlink (CRPropList *a_this, 
+				  CRPropList *a_pair) ;
+
+void cr_prop_list_destroy (CRPropList *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_PROP_LIST_H__*/
diff --git a/src/st/croco/cr-pseudo.c b/src/st/croco/cr-pseudo.c
new file mode 100644
index 000000000..cee3fc869
--- /dev/null
+++ b/src/st/croco/cr-pseudo.c
@@ -0,0 +1,167 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include "cr-pseudo.h"
+
+/**
+ *@CRPseudo:
+ *The definition of the #CRPseudo class.
+ */
+
+/**
+ * cr_pseudo_new:
+ *Constructor of the #CRPseudo class.
+ *
+ *Returns the newly build instance.
+ */
+CRPseudo *
+cr_pseudo_new (void)
+{
+        CRPseudo *result = NULL;
+
+        result = g_malloc0 (sizeof (CRPseudo));
+
+        return result;
+}
+
+/**
+ * cr_pseudo_to_string:
+ * @a_this: the current instance of #CRPseud.
+ *
+ * Returns the serialized pseudo. Caller must free the returned
+ * string using g_free().
+ */
+guchar *
+cr_pseudo_to_string (CRPseudo const * a_this)
+{
+        guchar *result = NULL;
+        GString *str_buf = NULL;
+
+        g_return_val_if_fail (a_this, NULL);
+
+        str_buf = g_string_new (NULL);
+
+        if (a_this->type == IDENT_PSEUDO) {
+                guchar *name = NULL;
+
+                if (a_this->name == NULL) {
+                        goto error;
+                }
+
+                name = (guchar *) g_strndup (a_this->name->stryng->str, 
+                                  a_this->name->stryng->len);
+
+                if (name) {
+                        g_string_append (str_buf, (const gchar *) name);
+                        g_free (name);
+                        name = NULL;
+                }
+        } else if (a_this->type == FUNCTION_PSEUDO) {
+                guchar *name = NULL,
+                        *arg = NULL;
+
+                if (a_this->name == NULL)
+                        goto error;
+
+                name = (guchar *) g_strndup (a_this->name->stryng->str, 
+                                  a_this->name->stryng->len);
+
+                if (a_this->extra) {
+                        arg = (guchar *) g_strndup (a_this->extra->stryng->str,
+                                         a_this->extra->stryng->len);
+                }
+
+                if (name) {
+                        g_string_append_printf (str_buf, "%s(", name);
+                        g_free (name);
+                        name = NULL;
+
+                        if (arg) {
+                                g_string_append (str_buf, (const gchar *) arg);
+                                g_free (arg);
+                                arg = NULL;
+                        }
+
+                        g_string_append_c (str_buf, ')');
+                }
+        }
+
+        if (str_buf) {
+                result = (guchar *) str_buf->str;
+                g_string_free (str_buf, FALSE);
+                str_buf = NULL;
+        }
+
+        return result;
+
+      error:
+        g_string_free (str_buf, TRUE);
+        return NULL;
+}
+
+/**
+ * cr_pseudo_dump:
+ *@a_this: the current instance of pseudo
+ *@a_fp: the destination file pointer.
+ *
+ *Dumps the pseudo to a file.
+ *
+ */
+void
+cr_pseudo_dump (CRPseudo const * a_this, FILE * a_fp)
+{
+        guchar *tmp_str = NULL;
+
+        if (a_this) {
+                tmp_str = cr_pseudo_to_string (a_this);
+                if (tmp_str) {
+                        fprintf (a_fp, "%s", tmp_str);
+                        g_free (tmp_str);
+                        tmp_str = NULL;
+                }
+        }
+}
+
+/**
+ * cr_pseudo_destroy:
+ *@a_this: the current instance to destroy.
+ *
+ *destructor of the #CRPseudo class.
+ */
+void
+cr_pseudo_destroy (CRPseudo * a_this)
+{
+        g_return_if_fail (a_this);
+
+        if (a_this->name) {
+                cr_string_destroy (a_this->name);
+                a_this->name = NULL;
+        }
+
+        if (a_this->extra) {
+                cr_string_destroy (a_this->extra);
+                a_this->extra = NULL;
+        }
+
+        g_free (a_this);
+}
diff --git a/src/st/croco/cr-pseudo.h b/src/st/croco/cr-pseudo.h
new file mode 100644
index 000000000..8917da45e
--- /dev/null
+++ b/src/st/croco/cr-pseudo.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ * 
+ * See COPYRIGHTS file for copyright information
+ */
+
+#ifndef __CR_PSEUDO_H__
+#define __CR_PSEUDO_H__
+
+#include <stdio.h>
+#include <glib.h>
+#include "cr-attr-sel.h"
+#include "cr-parsing-location.h"
+
+G_BEGIN_DECLS
+
+enum CRPseudoType
+{
+        IDENT_PSEUDO = 0,
+        FUNCTION_PSEUDO
+} ;
+
+typedef struct _CRPseudo CRPseudo ;
+
+/**
+ *The CRPseudo Class.
+ *Abstract a "pseudo" as defined by the css2 spec
+ *in appendix D.1 .
+ */
+struct _CRPseudo
+{
+        enum CRPseudoType type ;
+        CRString *name ;
+        CRString *extra ;
+        CRParsingLocation location ;
+} ;
+
+CRPseudo * cr_pseudo_new (void) ;
+
+guchar * cr_pseudo_to_string (CRPseudo const *a_this) ;
+
+void cr_pseudo_dump (CRPseudo const *a_this, FILE *a_fp) ;
+
+void cr_pseudo_destroy (CRPseudo *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_PSEUDO_H__*/
diff --git a/src/st/croco/cr-rgb.c b/src/st/croco/cr-rgb.c
new file mode 100644
index 000000000..1b8b66256
--- /dev/null
+++ b/src/st/croco/cr-rgb.c
@@ -0,0 +1,687 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ * 
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyrights information.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "cr-rgb.h"
+#include "cr-term.h"
+#include "cr-parser.h"
+
+static const CRRgb gv_standard_colors[] = {
+        {(const guchar*)"aliceblue",   240, 248, 255, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"antiquewhite",        250, 235, 215, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"aqua",          0, 255, 255, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"aquamarine",  127, 255, 212, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"azure",       240, 255, 255, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"beige",       245, 245, 220, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"bisque",      255, 228, 196, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"black",         0,   0,   0, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"blanchedalmond",      255, 235, 205, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"blue",          0,   0, 255, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"blueviolet",  138,  43, 226, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"brown",       165,  42,  42, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"burlywood",   222, 184, 135, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"cadetblue",    95, 158, 160, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"chartreuse",  127, 255,   0, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"chocolate",   210, 105,  30, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"coral",       255, 127,  80, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"cornflowerblue",      100, 149, 237, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"cornsilk",    255, 248, 220, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"crimson",     220,  20,  60, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"cyan",          0, 255, 255, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"darkblue",      0,   0, 139, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"darkcyan",      0, 139, 139, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"darkgoldenrod",       184, 134,  11, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"darkgray",    169, 169, 169, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"darkgreen",     0, 100,   0, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"darkgrey",    169, 169, 169, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"darkkhaki",   189, 183, 107, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"darkmagenta", 139,   0, 139, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"darkolivegreen",       85, 107,  47, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"darkorange",  255, 140,   0, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"darkorchid",  153,  50, 204, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"darkred",     139,   0,   0, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"darksalmon",  233, 150, 122, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"darkseagreen",        143, 188, 143, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"darkslateblue",        72,  61, 139, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"darkslategray",        47,  79,  79, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"darkslategrey",        47,  79,  79, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"darkturquoise",         0, 206, 209, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"darkviolet",  148,   0, 211, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"deeppink",    255,  20, 147, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"deepskyblue",   0, 191, 255, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"dimgray",     105, 105, 105, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"dimgrey",     105, 105, 105, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"dodgerblue",   30, 144, 255, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"firebrick",   178,  34,  34, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"floralwhite", 255, 250, 240, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"forestgreen",  34, 139,  34, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"fuchsia",     255,   0, 255, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"gainsboro",   220, 220, 220, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"ghostwhite",  248, 248, 255, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"gold",        255, 215,   0, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"goldenrod",   218, 165,  32, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"gray",        128, 128, 128, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"green",         0, 128,   0, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"greenyellow", 173, 255,  47, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"grey",        128, 128, 128, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"honeydew",    240, 255, 240, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"hotpink",     255, 105, 180, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"indianred",   205,  92,  92, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"indigo",       75,   0, 130, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"ivory",       255, 255, 240, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"khaki",       240, 230, 140, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lavender",    230, 230, 250, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lavenderblush",       255, 240, 245, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lawngreen",   124, 252,   0, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lemonchiffon",        255, 250, 205, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lightblue",   173, 216, 230, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lightcoral",  240, 128, 128, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lightcyan",   224, 255, 255, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lightgoldenrodyellow",        250, 250, 210, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lightgray",   211, 211, 211, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lightgreen",  144, 238, 144, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lightgrey",   211, 211, 211, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lightpink",   255, 182, 193, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lightsalmon", 255, 160, 122, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lightseagreen",        32, 178, 170, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lightskyblue",        135, 206, 250, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lightslategray",      119, 136, 153, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lightslategrey",      119, 136, 153, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lightsteelblue",      176, 196, 222, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lightyellow", 255, 255, 224, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"lime",          0, 255,   0, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"limegreen",    50, 205,  50, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"linen",       250, 240, 230, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"magenta",     255,   0, 255, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"maroon",      128,   0,   0, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"mediumaquamarine",    102, 205, 170, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"mediumblue",    0,   0, 205, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"mediumorchid",        186,  85, 211, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"mediumpurple",        147, 112, 219, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"mediumseagreen",       60, 179, 113, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"mediumslateblue",     123, 104, 238, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"mediumspringgreen",     0, 250, 154, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"mediumturquoise",      72, 209, 204, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"mediumvioletred",     199,  21, 133, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"midnightblue",         25,  25, 112, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"mintcream",   245, 255, 250, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"mistyrose",   255, 228, 225, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"moccasin",    255, 228, 181, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"navajowhite", 255, 222, 173, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"navy",          0,   0, 128, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"oldlace",     253, 245, 230, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"olive",       128, 128,   0, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"olivedrab",   107, 142,  35, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"orange",      255, 165,   0, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"orangered",   255,  69,   0, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"orchid",      218, 112, 214, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"palegoldenrod",       238, 232, 170, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"palegreen",   152, 251, 152, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"paleturquoise",       175, 238, 238, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"palevioletred",       219, 112, 147, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"papayawhip",  255, 239, 213, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"peachpuff",   255, 218, 185, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"peru",        205, 133,  63, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"pink",        255, 192, 203, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"plum",        221, 160, 221, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"powderblue",  176, 224, 230, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"purple",      128,   0, 128, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"red",         255,   0,   0, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"rosybrown",   188, 143, 143, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"royalblue",    65, 105, 225, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"saddlebrown", 139,  69,  19, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"salmon",      250, 128, 114, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"sandybrown",  244, 164,  96, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"seagreen",     46, 139,  87, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"seashell",    255, 245, 238, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"sienna",      160,  82,  45, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"silver",      192, 192, 192, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"skyblue",     135, 206, 235, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"slateblue",   106,  90, 205, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"slategray",   112, 128, 144, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"slategrey",   112, 128, 144, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"snow",        255, 250, 250, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"springgreen",   0, 255, 127, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"steelblue",    70, 130, 180, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"tan",         210, 180, 140, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"teal",          0, 128, 128, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"thistle",     216, 191, 216, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"tomato",      255,  99,  71, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"transparent", 255, 255, 255, FALSE, FALSE, TRUE, {0,0,0}},
+        {(const guchar*)"turquoise",    64, 224, 208, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"violet",      238, 130, 238, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"wheat",       245, 222, 179, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"white",       255, 255, 255, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"whitesmoke",  245, 245, 245, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"yellow",      255, 255,   0, FALSE, FALSE, FALSE, {0,0,0}},
+        {(const guchar*)"yellowgreen", 154, 205,  50, FALSE, FALSE, FALSE, {0,0,0}}
+};
+
+/**
+ * cr_rgb_new:
+ *
+ *The default constructor of #CRRgb.
+ *
+ *Returns the newly built instance of #CRRgb
+ */
+CRRgb *
+cr_rgb_new (void)
+{
+        CRRgb *result = NULL;
+
+        result = g_try_malloc (sizeof (CRRgb));
+
+        if (result == NULL) {
+                cr_utils_trace_info ("No more memory");
+                return NULL;
+        }
+
+        memset (result, 0, sizeof (CRRgb));
+
+        return result;
+}
+
+/**
+ * cr_rgb_new_with_vals:
+ *@a_red: the red component of the color.
+ *@a_green: the green component of the color.
+ *@a_blue: the blue component of the color.
+ *@a_unit: the unit of the rgb values.
+ *(either percentage or integer values)
+ *
+ *A constructor of #CRRgb.
+ *
+ *Returns the newly built instance of #CRRgb.
+ */
+CRRgb *
+cr_rgb_new_with_vals (gulong a_red, gulong a_green,
+                      gulong a_blue, gboolean a_is_percentage)
+{
+        CRRgb *result = NULL;
+
+        result = cr_rgb_new ();
+
+        g_return_val_if_fail (result, NULL);
+
+        result->red = a_red;
+        result->green = a_green;
+        result->blue = a_blue;
+        result->is_percentage = a_is_percentage;
+
+        return result;
+}
+
+/**
+ * cr_rgb_to_string:
+ *@a_this: the instance of #CRRgb to serialize.
+ *
+ *Serializes the rgb into a zero terminated string.
+ *
+ *Returns the zero terminated string containing the serialized
+ *rgb. MUST BE FREED by the caller using g_free().
+ */
+guchar *
+cr_rgb_to_string (CRRgb const * a_this)
+{
+        guchar *result = NULL;
+        GString *str_buf = NULL;
+
+        str_buf = g_string_new (NULL);
+        g_return_val_if_fail (str_buf, NULL);
+
+        if (a_this->is_percentage == 1) {
+                g_string_append_printf (str_buf, "%ld", a_this->red);
+
+                g_string_append (str_buf, "%, ");
+
+                g_string_append_printf (str_buf, "%ld", a_this->green);
+                g_string_append (str_buf, "%, ");
+
+                g_string_append_printf (str_buf, "%ld", a_this->blue);
+                g_string_append_c (str_buf, '%');
+        } else {
+                g_string_append_printf (str_buf, "%ld", a_this->red);
+                g_string_append (str_buf, ", ");
+
+                g_string_append_printf (str_buf, "%ld", a_this->green);
+                g_string_append (str_buf, ", ");
+
+                g_string_append_printf (str_buf, "%ld", a_this->blue);
+        }
+
+        if (str_buf) {
+                result = (guchar *) str_buf->str;
+                g_string_free (str_buf, FALSE);
+        }
+
+        return result;
+}
+
+/**
+ * cr_rgb_dump:
+ *@a_this: the "this pointer" of
+ *the current instance of #CRRgb.
+ *@a_fp: the destination file pointer.
+ *
+ *Dumps the current instance of #CRRgb
+ *to a file.
+ */
+void
+cr_rgb_dump (CRRgb const * a_this, FILE * a_fp)
+{
+        guchar *str = NULL;
+
+        g_return_if_fail (a_this);
+
+        str = cr_rgb_to_string (a_this);
+
+        if (str) {
+                fprintf (a_fp, "%s", str);
+                g_free (str);
+                str = NULL;
+        }
+}
+
+/**
+ * cr_rgb_compute_from_percentage:
+ *@a_this: the current instance of #CRRgb
+ *
+ *If the rgb values are expressed in percentage,
+ *compute their real value.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_rgb_compute_from_percentage (CRRgb * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        if (a_this->is_percentage == FALSE)
+                return CR_OK;
+        a_this->red = a_this->red * 255 / 100;
+        a_this->green = a_this->green * 255 / 100;
+        a_this->blue = a_this->blue * 255 / 100;
+        a_this->is_percentage = FALSE;
+        return CR_OK;
+}
+
+/**
+ * cr_rgb_set:
+ *@a_this: the current instance of #CRRgb.
+ *@a_red: the red value.
+ *@a_green: the green value.
+ *@a_blue: the blue value.
+ *
+ *Sets rgb values to the RGB.
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_rgb_set (CRRgb * a_this, gulong a_red,
+            gulong a_green, gulong a_blue, gboolean a_is_percentage)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+        if (a_is_percentage != FALSE) {
+                g_return_val_if_fail (a_red <= 100
+                                      && a_green <= 100
+                                      && a_blue <= 100, CR_BAD_PARAM_ERROR);
+        }
+
+        a_this->is_percentage = a_is_percentage;
+
+        a_this->red = a_red;
+        a_this->green = a_green;
+        a_this->blue = a_blue;
+        a_this->inherit = FALSE ;
+        a_this->is_transparent = FALSE ;
+        return CR_OK;
+}
+
+/**
+ * cr_rgb_set_to_inherit:
+ *@a_this: the current instance of #CRRgb
+ *
+ *sets the value of the rgb to inherit.
+ *Look at the css spec from chapter 6.1 to 6.2 to understand
+ *the meaning of "inherit".
+ *
+ * Returns CR_OK upon succesful completion, an error code otherwise.
+ */
+enum CRStatus 
+cr_rgb_set_to_inherit (CRRgb *a_this, gboolean a_inherit)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+        a_this->inherit = a_inherit ;
+
+        return CR_OK ;
+}
+
+/**
+ * cr_rgb_is_set_to_inherit:
+ *
+ * @a_this: the current instance of #CRRgb.
+ *
+ * Returns TRUE if the rgb is set to the value "inherit", FALSE otherwise.
+ */
+gboolean
+cr_rgb_is_set_to_inherit (CRRgb const *a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+        return a_this->inherit ;
+}
+
+/**
+ * cr_rgb_is_set_to_transparent:
+ *@a_this: the current instance of
+ *#CRRgb
+ *
+ *Tests if the the rgb is set to the
+ *value "transparent" or not.
+ *
+ *Returns TRUE if the rgb has been set to
+ *transparent, FALSE otherwise.
+ */
+gboolean 
+cr_rgb_is_set_to_transparent (CRRgb const *a_this)
+{
+        g_return_val_if_fail (a_this, FALSE) ;
+        return a_this->is_transparent ;
+}
+
+
+/**
+ * cr_rgb_set_to_transparent:
+ *@a_this: the current instance of #CRRgb
+ *@a_is_transparent: set to transparent or not.
+ *
+ *Sets the rgb to the "transparent" value (or not)
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus 
+cr_rgb_set_to_transparent (CRRgb *a_this, 
+                           gboolean a_is_transparent)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;        
+        a_this->is_transparent = a_is_transparent ;
+        return CR_OK ;
+}
+
+/**
+ * cr_rgb_set_from_rgb:
+ *@a_this: the current instance of #CRRgb.
+ *@a_rgb: the rgb to "copy"
+ *
+ *Sets the rgb from an other one.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_rgb_set_from_rgb (CRRgb * a_this, CRRgb const * a_rgb)
+{
+        g_return_val_if_fail (a_this && a_rgb, CR_BAD_PARAM_ERROR);
+
+        cr_rgb_copy (a_this, a_rgb) ;
+
+        return CR_OK;
+}
+
+static int
+cr_rgb_color_name_compare (const void *a,
+                           const void *b)
+{
+        const char *a_color_name = a;
+        const CRRgb *rgb = b;
+
+        return g_ascii_strcasecmp (a_color_name, (const char *) rgb->name);
+}
+
+/**
+ * cr_rgb_set_from_name:
+ * @a_this: the current instance of #CRRgb
+ * @a_color_name: the color name
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_rgb_set_from_name (CRRgb * a_this, const guchar * a_color_name)
+{
+        enum CRStatus status = CR_OK;
+        CRRgb *result;
+
+        g_return_val_if_fail (a_this && a_color_name, CR_BAD_PARAM_ERROR);
+
+        result = bsearch (a_color_name,
+                          gv_standard_colors,
+                          G_N_ELEMENTS (gv_standard_colors),
+                          sizeof (gv_standard_colors[0]),
+                          cr_rgb_color_name_compare);
+        if (result != NULL)
+                cr_rgb_set_from_rgb (a_this, result);
+        else
+               status = CR_UNKNOWN_TYPE_ERROR;
+
+        return status;
+}
+
+/**
+ * cr_rgb_set_from_hex_str:
+ * @a_this: the current instance of #CRRgb
+ * @a_hex: the hexadecimal value to set.
+ *
+ * Returns CR_OK upon successful completion.
+ */
+enum CRStatus
+cr_rgb_set_from_hex_str (CRRgb * a_this, const guchar * a_hex)
+{
+        enum CRStatus status = CR_OK;
+        gulong i = 0;
+        guchar colors[3] = { 0 };
+
+        g_return_val_if_fail (a_this && a_hex, CR_BAD_PARAM_ERROR);
+
+        if (strlen ((const char *) a_hex) == 3) {
+                for (i = 0; i < 3; i++) {
+                        if (a_hex[i] >= '0' && a_hex[i] <= '9') {
+                                colors[i] = a_hex[i] - '0';
+                                colors[i] = (colors[i] << 4) | colors[i];
+                        } else if (a_hex[i] >= 'a' && a_hex[i] <= 'z') {
+                                colors[i] = 10 + a_hex[i] - 'a';
+                                colors[i] = (colors[i] << 4) | colors[i];
+                        } else if (a_hex[i] >= 'A' && a_hex[i] <= 'Z') {
+                                colors[i] = 10 + a_hex[i] - 'A';
+                                colors[i] = (colors[i] << 4) | colors[i];
+                        } else {
+                                status = CR_UNKNOWN_TYPE_ERROR;
+                        }
+                }
+        } else if (strlen ((const char *) a_hex) == 6) {
+                for (i = 0; i < 6; i++) {
+                        if (a_hex[i] >= '0' && a_hex[i] <= '9') {
+                                colors[i / 2] <<= 4;
+                                colors[i / 2] |= a_hex[i] - '0';
+                                status = CR_OK;
+                        } else if (a_hex[i] >= 'a' && a_hex[i] <= 'z') {
+                                colors[i / 2] <<= 4;
+                                colors[i / 2] |= 10 + a_hex[i] - 'a';
+                                status = CR_OK;
+                        } else if (a_hex[i] >= 'A' && a_hex[i] <= 'Z') {
+                                colors[i / 2] <<= 4;
+                                colors[i / 2] |= 10 + a_hex[i] - 'A';
+                                status = CR_OK;
+                        } else {
+                                status = CR_UNKNOWN_TYPE_ERROR;
+                        }
+                }
+        } else {
+                status = CR_UNKNOWN_TYPE_ERROR;
+        }
+
+        if (status == CR_OK) {
+                status = cr_rgb_set (a_this, colors[0],
+                                     colors[1], colors[2], FALSE);
+                cr_rgb_set_to_transparent (a_this, FALSE) ;
+        }
+        return status;
+}
+
+/**
+ * cr_rgb_set_from_term:
+ *@a_this: the instance of #CRRgb to set
+ *@a_value: the terminal from which to set
+ *
+ *Set the rgb from a terminal symbol
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_rgb_set_from_term (CRRgb *a_this, const struct _CRTerm *a_value)
+{
+        enum CRStatus status = CR_OK ;
+        g_return_val_if_fail (a_this && a_value,
+                              CR_BAD_PARAM_ERROR) ;
+
+	switch(a_value->type) {
+	case TERM_RGB:
+                if (a_value->content.rgb) {
+                        cr_rgb_set_from_rgb
+                                (a_this, a_value->content.rgb) ;
+                }
+		break ;
+	case TERM_IDENT:
+                if (a_value->content.str
+                    && a_value->content.str->stryng
+                    && a_value->content.str->stryng->str) {
+			if (!strncmp ("inherit",
+                                      a_value->content.str->stryng->str,
+                                      sizeof ("inherit")-1)) {
+				a_this->inherit = TRUE;
+                                a_this->is_transparent = FALSE ;
+			} else  {
+                        	status = cr_rgb_set_from_name
+                                        (a_this,
+                                         (const guchar *) a_value->content.str->stryng->str) ;
+			}
+                } else {
+                        cr_utils_trace_info 
+                                ("a_value has NULL string value") ;
+                }
+		break ;
+	case TERM_HASH:
+                if (a_value->content.str
+                    && a_value->content.str->stryng
+                    && a_value->content.str->stryng->str) {
+                        status = cr_rgb_set_from_hex_str
+                                (a_this, 
+                                 (const guchar *) a_value->content.str->stryng->str) ;
+                } else {
+                        cr_utils_trace_info
+                                ("a_value has NULL string value") ;
+                }
+                break ;
+	default:
+                status =  CR_UNKNOWN_TYPE_ERROR ;
+	}
+        return status ;
+}
+
+enum CRStatus 
+cr_rgb_copy (CRRgb *a_dest, CRRgb const *a_src)
+{
+        g_return_val_if_fail (a_dest && a_src,
+                              CR_BAD_PARAM_ERROR) ;
+
+        memcpy (a_dest, a_src, sizeof (CRRgb)) ;
+        return CR_OK ;
+}
+
+/**
+ * cr_rgb_destroy:
+ *@a_this: the "this pointer" of the
+ *current instance of #CRRgb.
+ *
+ *Destructor of #CRRgb.
+ */
+void
+cr_rgb_destroy (CRRgb * a_this)
+{
+        g_return_if_fail (a_this);
+        g_free (a_this);
+}
+
+/**
+ * cr_rgb_parse_from_buf:
+ *@a_str: a string that contains a color description
+ *@a_enc: the encoding of a_str
+ *
+ *Parses a text buffer that contains a rgb color
+ *
+ *Returns the parsed color, or NULL in case of error
+ */
+CRRgb *
+cr_rgb_parse_from_buf (const guchar *a_str,
+                              enum CREncoding a_enc)
+{
+	enum CRStatus status = CR_OK ;
+	CRTerm *value = NULL ;
+	CRParser * parser = NULL;
+	CRRgb *result = NULL;
+	
+	g_return_val_if_fail (a_str, NULL);
+	
+	parser = cr_parser_new_from_buf ((guchar *) a_str, strlen ((const char *) a_str), a_enc, FALSE);
+
+	g_return_val_if_fail (parser, NULL);
+
+	status = cr_parser_try_to_skip_spaces_and_comments (parser) ;
+	if (status != CR_OK)
+	    	goto cleanup;
+
+	status = cr_parser_parse_term (parser, &value);
+	if (status != CR_OK)
+	    	goto cleanup;
+
+	result = cr_rgb_new ();
+	if (!result)
+	    	goto cleanup;
+
+	status = cr_rgb_set_from_term (result, value);
+
+cleanup:
+	if (parser) {
+	    	cr_parser_destroy (parser);
+		parser = NULL;
+	}
+	if (value) {
+	    	cr_term_destroy(value);
+		value = NULL;
+	}
+	return result ;
+}
+
diff --git a/src/st/croco/cr-rgb.h b/src/st/croco/cr-rgb.h
new file mode 100644
index 000000000..a127a440e
--- /dev/null
+++ b/src/st/croco/cr-rgb.h
@@ -0,0 +1,94 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ * 
+ * see COPYRIGHTS file for copyright information.
+ */
+
+#ifndef __CR_RGB_H__
+#define __CR_RGB_H__
+
+#include <stdio.h>
+#include <glib.h>
+#include "cr-utils.h"
+#include "cr-parsing-location.h"
+
+G_BEGIN_DECLS
+
+
+typedef struct _CRRgb CRRgb ;
+struct _CRRgb
+{
+        /*
+         *the unit of the rgb.
+         *Either NO_UNIT (integer) or 
+         *UNIT_PERCENTAGE (percentage).
+         */
+        const guchar *name ;
+        glong red ;
+        glong green ;
+        glong blue ;
+        gboolean is_percentage ;
+	gboolean inherit ;
+        gboolean is_transparent ;
+        CRParsingLocation location ;
+} ;
+
+CRRgb * cr_rgb_new (void) ;
+
+CRRgb * cr_rgb_new_with_vals (gulong a_red, gulong a_green, 
+                              gulong a_blue, gboolean a_is_percentage) ;
+
+CRRgb *cr_rgb_parse_from_buf(const guchar *a_str,
+                             enum CREncoding a_enc);
+
+enum CRStatus cr_rgb_compute_from_percentage (CRRgb *a_this) ;
+
+enum CRStatus cr_rgb_set (CRRgb *a_this, gulong a_red,
+                          gulong a_green, gulong a_blue,
+                          gboolean a_is_percentage) ;
+
+enum CRStatus cr_rgb_copy (CRRgb *a_dest, CRRgb const *a_src) ;
+
+enum CRStatus  cr_rgb_set_to_inherit (CRRgb *a_this, gboolean a_inherit) ;
+
+gboolean cr_rgb_is_set_to_inherit (CRRgb const *a_this) ;
+
+gboolean cr_rgb_is_set_to_transparent (CRRgb const *a_this) ;
+
+enum CRStatus cr_rgb_set_to_transparent (CRRgb *a_this, 
+                                         gboolean a_is_transparent) ;
+enum CRStatus cr_rgb_set_from_rgb (CRRgb *a_this, CRRgb const *a_rgb) ;
+
+enum CRStatus cr_rgb_set_from_name (CRRgb *a_this, const guchar *a_color_name) ;
+
+enum CRStatus cr_rgb_set_from_hex_str (CRRgb *a_this, const guchar * a_hex_value) ;
+
+struct _CRTerm;
+
+enum CRStatus cr_rgb_set_from_term (CRRgb *a_this, const struct _CRTerm *a_value);
+
+guchar * cr_rgb_to_string (CRRgb const *a_this) ;
+
+void cr_rgb_dump (CRRgb const *a_this, FILE *a_fp) ;
+
+void cr_rgb_destroy (CRRgb *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_RGB_H__*/
diff --git a/src/st/croco/cr-selector.c b/src/st/croco/cr-selector.c
new file mode 100644
index 000000000..8902e1c0f
--- /dev/null
+++ b/src/st/croco/cr-selector.c
@@ -0,0 +1,306 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include <string.h>
+#include "cr-selector.h"
+#include "cr-parser.h"
+
+/**
+ * cr_selector_new:
+ *
+ *@a_simple_sel: the initial simple selector list
+ *of the current instance of #CRSelector.
+ *
+ *Creates a new instance of #CRSelector.
+ *
+ *Returns the newly built instance of #CRSelector, or
+ *NULL in case of failure.
+ */
+CRSelector *
+cr_selector_new (CRSimpleSel * a_simple_sel)
+{
+        CRSelector *result = NULL;
+
+        result = g_try_malloc (sizeof (CRSelector));
+        if (!result) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+        memset (result, 0, sizeof (CRSelector));
+        result->simple_sel = a_simple_sel;
+        return result;
+}
+
+CRSelector *
+cr_selector_parse_from_buf (const guchar * a_char_buf, enum CREncoding a_enc)
+{
+        CRParser *parser = NULL;
+
+        g_return_val_if_fail (a_char_buf, NULL);
+
+        parser = cr_parser_new_from_buf ((guchar*)a_char_buf, strlen ((const char *) a_char_buf),
+                                         a_enc, FALSE);
+        g_return_val_if_fail (parser, NULL);
+
+        return NULL;
+}
+
+/**
+ * cr_selector_append:
+ *
+ *@a_this: the current instance of #CRSelector.
+ *@a_new: the instance of #CRSelector to be appended.
+ *
+ *Appends a new instance of #CRSelector to the current selector list.
+ *
+ *Returns the new list.
+ */
+CRSelector *
+cr_selector_append (CRSelector * a_this, CRSelector * a_new)
+{
+        CRSelector *cur = NULL;
+
+        if (!a_this) {
+                return a_new;
+        }
+
+        /*walk forward the list headed by a_this to get the list tail */
+        for (cur = a_this; cur && cur->next; cur = cur->next) ;
+
+        cur->next = a_new;
+        a_new->prev = cur;
+
+        return a_this;
+}
+
+/**
+ * cr_selector_prepend:
+ *
+ *@a_this: the current instance of #CRSelector list.
+ *@a_new: the instance of #CRSelector.
+ *
+ *Prepends an element to the #CRSelector list.
+ * 
+ *Returns the new list.
+ */
+CRSelector *
+cr_selector_prepend (CRSelector * a_this, CRSelector * a_new)
+{
+        CRSelector *cur = NULL;
+
+        a_new->next = a_this;
+        a_this->prev = a_new;
+
+        for (cur = a_new; cur && cur->prev; cur = cur->prev) ;
+
+        return cur;
+}
+
+/**
+ * cr_selector_append_simple_sel:
+ *
+ *@a_this: the current instance of #CRSelector.
+ *@a_simple_sel: the simple selector to append.
+ *
+ *append a simple selector to the current #CRSelector list.
+ *
+ *Returns the new list or NULL in case of failure.
+ */
+CRSelector *
+cr_selector_append_simple_sel (CRSelector * a_this,
+                               CRSimpleSel * a_simple_sel)
+{
+        CRSelector *selector = NULL;
+
+        selector = cr_selector_new (a_simple_sel);
+        g_return_val_if_fail (selector, NULL);
+
+        return cr_selector_append (a_this, selector);
+}
+
+guchar *
+cr_selector_to_string (CRSelector const * a_this)
+{
+        guchar *result = NULL;
+        GString *str_buf = NULL;
+
+        str_buf = g_string_new (NULL);
+        g_return_val_if_fail (str_buf, NULL);
+
+        if (a_this) {
+                CRSelector const *cur = NULL;
+
+                for (cur = a_this; cur; cur = cur->next) {
+                        if (cur->simple_sel) {
+                                guchar *tmp_str = NULL;
+
+                                tmp_str = cr_simple_sel_to_string
+                                        (cur->simple_sel);
+
+                                if (tmp_str) {
+                                        if (cur->prev)
+                                                g_string_append (str_buf, 
+								 ", ");
+
+                                        g_string_append (str_buf, (const gchar *) tmp_str);
+
+                                        g_free (tmp_str);
+                                        tmp_str = NULL;
+                                }
+                        }
+                }
+        }
+
+        if (str_buf) {
+                result = (guchar *) str_buf->str;
+                g_string_free (str_buf, FALSE);
+                str_buf = NULL;
+        }
+
+        return result;
+}
+
+/**
+ * cr_selector_dump:
+ *
+ *@a_this: the current instance of #CRSelector.
+ *@a_fp: the destination file.
+ *
+ *Serializes the current instance of #CRSelector to a file.
+ */
+void
+cr_selector_dump (CRSelector const * a_this, FILE * a_fp)
+{
+        guchar *tmp_buf = NULL;
+
+        if (a_this) {
+                tmp_buf = cr_selector_to_string (a_this);
+                if (tmp_buf) {
+                        fprintf (a_fp, "%s", tmp_buf);
+                        g_free (tmp_buf);
+                        tmp_buf = NULL;
+                }
+        }
+}
+
+/**
+ * cr_selector_ref:
+ *
+ *@a_this: the current instance of #CRSelector.
+ *
+ *Increments the ref count of the current instance
+ *of #CRSelector.
+ */
+void
+cr_selector_ref (CRSelector * a_this)
+{
+        g_return_if_fail (a_this);
+
+        a_this->ref_count++;
+}
+
+/**
+ * cr_selector_unref:
+ *
+ *@a_this: the current instance of #CRSelector.
+ *
+ *Decrements the ref count of the current instance of
+ *#CRSelector.
+ *If the ref count reaches zero, the current instance of
+ *#CRSelector is destroyed.
+ *
+ *Returns TRUE if this function destroyed the current instance
+ *of #CRSelector, FALSE otherwise.
+ */
+gboolean
+cr_selector_unref (CRSelector * a_this)
+{
+        g_return_val_if_fail (a_this, FALSE);
+
+        if (a_this->ref_count) {
+                a_this->ref_count--;
+        }
+
+        if (a_this->ref_count == 0) {
+                cr_selector_destroy (a_this);
+                return TRUE;
+        }
+
+        return FALSE;
+}
+
+/**
+ * cr_selector_destroy:
+ *
+ *@a_this: the current instance of #CRSelector.
+ *
+ *Destroys the selector list.
+ */
+void
+cr_selector_destroy (CRSelector * a_this)
+{
+        CRSelector *cur = NULL;
+
+        g_return_if_fail (a_this);
+
+        /*
+         *go and get the list tail. In the same time, free
+         *all the simple selectors contained in the list.
+         */
+        for (cur = a_this; cur && cur->next; cur = cur->next) {
+                if (cur->simple_sel) {
+                        cr_simple_sel_destroy (cur->simple_sel);
+                        cur->simple_sel = NULL;
+                }
+        }
+
+        if (cur) {
+                if (cur->simple_sel) {
+                        cr_simple_sel_destroy (cur->simple_sel);
+                        cur->simple_sel = NULL;
+                }
+        }
+
+        /*in case the list has only one element */
+        if (cur && !cur->prev) {
+                g_free (cur);
+                return;
+        }
+
+        /*walk backward the list and free each "next element" */
+        for (cur = cur->prev; cur && cur->prev; cur = cur->prev) {
+                if (cur->next) {
+                        g_free (cur->next);
+                        cur->next = NULL;
+                }
+        }
+
+        if (!cur)
+                return;
+
+        if (cur->next) {
+                g_free (cur->next);
+                cur->next = NULL;
+        }
+
+        g_free (cur);
+}
diff --git a/src/st/croco/cr-selector.h b/src/st/croco/cr-selector.h
new file mode 100644
index 000000000..dd6a7f786
--- /dev/null
+++ b/src/st/croco/cr-selector.h
@@ -0,0 +1,95 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#ifndef __CR_SELECTOR_H__
+#define __CR_SELECTOR_H__
+
+#include <stdio.h>
+#include "cr-utils.h"
+#include "cr-simple-sel.h"
+#include "cr-parsing-location.h"
+
+/**
+ *@file
+ *The declaration file of the #CRSelector file.
+ */
+
+G_BEGIN_DECLS
+
+typedef struct _CRSelector CRSelector ;
+
+/**
+ *Abstracts a CSS2 selector as defined in the right part
+ *of the 'ruleset" production in the appendix D.1 of the
+ *css2 spec.
+ *It is actually the abstraction of a comma separated list
+ *of simple selectors list.
+ *In a css2 file, a selector is a list of simple selectors
+ *separated by a comma.
+ *e.g: sel0, sel1, sel2 ...
+ *Each seln is a simple selector
+ */
+struct _CRSelector
+{
+	/**
+	 *A Selection expression.
+	 *It is a list of basic selectors.
+	 *Each basic selector can be either an element
+	 *selector, an id selector, a class selector, an
+	 *attribute selector, an universal selector etc ...
+	 */
+	CRSimpleSel *simple_sel ;
+
+	/**The next selector list element*/
+	CRSelector *next ;
+	CRSelector *prev ;
+	CRParsingLocation location ;
+	glong ref_count ;
+};
+
+CRSelector* cr_selector_new (CRSimpleSel *a_sel_expr) ;
+
+CRSelector * cr_selector_parse_from_buf (const guchar * a_char_buf,
+					 enum CREncoding a_enc) ;
+
+CRSelector* cr_selector_append (CRSelector *a_this, CRSelector *a_new) ;
+
+CRSelector* cr_selector_append_simple_sel (CRSelector *a_this,
+					   CRSimpleSel *a_simple_sel) ;
+
+CRSelector* cr_selector_prepend (CRSelector *a_this, CRSelector *a_new) ;
+
+guchar * cr_selector_to_string (CRSelector const *a_this) ;
+
+void cr_selector_dump (CRSelector const *a_this, FILE *a_fp) ;
+
+void cr_selector_ref (CRSelector *a_this) ;
+
+gboolean cr_selector_unref (CRSelector *a_this) ;
+
+void cr_selector_destroy (CRSelector *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_SELECTOR_H__*/
diff --git a/src/st/croco/cr-simple-sel.c b/src/st/croco/cr-simple-sel.c
new file mode 100644
index 000000000..ac906858d
--- /dev/null
+++ b/src/st/croco/cr-simple-sel.c
@@ -0,0 +1,325 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include <string.h>
+#include <glib.h>
+#include "cr-simple-sel.h"
+
+/**
+ * cr_simple_sel_new:
+ *
+ *The constructor of #CRSimpleSel.
+ *
+ *Returns the new instance of #CRSimpleSel.
+ */
+CRSimpleSel *
+cr_simple_sel_new (void)
+{
+        CRSimpleSel *result = NULL;
+
+        result = g_try_malloc (sizeof (CRSimpleSel));
+        if (!result) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+        memset (result, 0, sizeof (CRSimpleSel));
+
+        return result;
+}
+
+/**
+ * cr_simple_sel_append_simple_sel:
+ *
+ *Appends a simpe selector to the current list of simple selector.
+ *
+ *@a_this: the this pointer of the current instance of #CRSimpleSel.
+ *@a_sel: the simple selector to append.
+ *
+ *Returns: the new list upon successfull completion, an error code otherwise.
+ */
+CRSimpleSel *
+cr_simple_sel_append_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel)
+{
+        CRSimpleSel *cur = NULL;
+
+        g_return_val_if_fail (a_sel, NULL);
+
+        if (a_this == NULL)
+                return a_sel;
+
+        for (cur = a_this; cur->next; cur = cur->next) ;
+
+        cur->next = a_sel;
+        a_sel->prev = cur;
+
+        return a_this;
+}
+
+/**
+ * cr_simple_sel_prepend_simple_sel:
+ *
+ *@a_this: the this pointer of the current instance of #CRSimpleSel.
+ *@a_sel: the simple selector to prepend.
+ *
+ *Prepends a simple selector to the current list of simple selectors.
+ *
+ *Returns the new list upon successfull completion, an error code otherwise.
+ */
+CRSimpleSel *
+cr_simple_sel_prepend_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel)
+{
+        g_return_val_if_fail (a_sel, NULL);
+
+        if (a_this == NULL)
+                return a_sel;
+
+        a_sel->next = a_this;
+        a_this->prev = a_sel;
+
+        return a_sel;
+}
+
+guchar *
+cr_simple_sel_to_string (CRSimpleSel const * a_this)
+{
+        GString *str_buf = NULL;
+        guchar *result = NULL;
+
+        CRSimpleSel const *cur = NULL;
+
+        g_return_val_if_fail (a_this, NULL);
+
+        str_buf = g_string_new (NULL);
+        for (cur = a_this; cur; cur = cur->next) {
+                if (cur->name) {
+                        guchar *str = (guchar *) g_strndup (cur->name->stryng->str,
+                                                 cur->name->stryng->len);
+
+                        if (str) {
+                                switch (cur->combinator) {
+                                case COMB_WS:
+                                        g_string_append (str_buf, " ");
+                                        break;
+
+                                case COMB_PLUS:
+                                        g_string_append (str_buf, "+");
+                                        break;
+
+                                case COMB_GT:
+                                        g_string_append (str_buf, ">");
+                                        break;
+
+                                default:
+                                        break;
+                                }
+
+                                g_string_append (str_buf, (const gchar *) str);
+                                g_free (str);
+                                str = NULL;
+                        }
+                }
+
+                if (cur->add_sel) {
+                        guchar *tmp_str = NULL;
+
+                        tmp_str = cr_additional_sel_to_string (cur->add_sel);
+                        if (tmp_str) {
+                                g_string_append (str_buf, (const gchar *) tmp_str);
+                                g_free (tmp_str);
+                                tmp_str = NULL;
+                        }
+                }
+        }
+
+        if (str_buf) {
+                result = (guchar *) str_buf->str;
+                g_string_free (str_buf, FALSE);
+                str_buf = NULL;
+        }
+
+        return result;
+}
+
+
+guchar *
+cr_simple_sel_one_to_string (CRSimpleSel const * a_this)
+{
+        GString *str_buf = NULL;
+        guchar *result = NULL;
+
+        g_return_val_if_fail (a_this, NULL);
+
+        str_buf = g_string_new (NULL);
+        if (a_this->name) {
+                guchar *str = (guchar *) g_strndup (a_this->name->stryng->str,
+                                         a_this->name->stryng->len);
+
+                if (str) {
+                        g_string_append_printf (str_buf, "%s", str);
+                        g_free (str);
+                        str = NULL;
+                }
+        }
+
+        if (a_this->add_sel) {
+                guchar *tmp_str = NULL;
+
+                tmp_str = cr_additional_sel_to_string (a_this->add_sel);
+                if (tmp_str) {
+                        g_string_append_printf
+                                (str_buf, "%s", tmp_str);
+                        g_free (tmp_str);
+                        tmp_str = NULL;
+                }
+        }
+
+        if (str_buf) {
+                result = (guchar *) str_buf->str;
+                g_string_free (str_buf, FALSE);
+                str_buf = NULL;
+        }
+
+        return result;
+}
+
+/**
+ * cr_simple_sel_dump:
+ *@a_this: the current instance of #CRSimpleSel.
+ *@a_fp: the destination file pointer.
+ *
+ *Dumps the selector to a file.
+ *TODO: add the support of unicode in the dump.
+ *
+ *Returns CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_simple_sel_dump (CRSimpleSel const * a_this, FILE * a_fp)
+{
+        guchar *tmp_str = NULL;
+
+        g_return_val_if_fail (a_fp, CR_BAD_PARAM_ERROR);
+
+        if (a_this) {
+                tmp_str = cr_simple_sel_to_string (a_this);
+                if (tmp_str) {
+                        fprintf (a_fp, "%s", tmp_str);
+                        g_free (tmp_str);
+                        tmp_str = NULL;
+                }
+        }
+
+        return CR_OK;
+}
+
+/**
+ * cr_simple_sel_compute_specificity:
+ *
+ *@a_this: the current instance of #CRSimpleSel
+ *
+ *Computes the selector (combinator separated list of simple selectors)
+ *as defined in the css2 spec in chapter 6.4.3
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_simple_sel_compute_specificity (CRSimpleSel * a_this)
+{
+        CRAdditionalSel const *cur_add_sel = NULL;
+        CRSimpleSel const *cur_sel = NULL;
+        gulong a = 0,
+                b = 0,
+                c = 0;
+
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        for (cur_sel = a_this; cur_sel; cur_sel = cur_sel->next) {
+                if (cur_sel->type_mask & TYPE_SELECTOR) {
+                        c++;    /*hmmh, is this a new language ? */
+                } else if (!cur_sel->name 
+                           || !cur_sel->name->stryng
+                           || !cur_sel->name->stryng->str) {
+                        if (cur_sel->add_sel->type ==
+                            PSEUDO_CLASS_ADD_SELECTOR) {
+                                /*
+                                 *this is a pseudo element, and
+                                 *the spec says, "ignore pseudo elements".
+                                 */
+                                continue;
+                        }
+                }
+
+                for (cur_add_sel = cur_sel->add_sel;
+                     cur_add_sel; cur_add_sel = cur_add_sel->next) {
+                        switch (cur_add_sel->type) {
+                        case ID_ADD_SELECTOR:
+                                a++;
+                                break;
+
+                        case NO_ADD_SELECTOR:
+                                continue;
+
+                        default:
+                                b++;
+                                break;
+                        }
+                }
+        }
+
+        /*we suppose a, b and c have 1 to 3 digits */
+        a_this->specificity = a * 1000000 + b * 1000 + c;
+
+        return CR_OK;
+}
+
+/**
+ * cr_simple_sel_destroy:
+ *
+ *@a_this: the this pointer of the current instance of #CRSimpleSel.
+ *
+ *The destructor of the current instance of
+ *#CRSimpleSel.
+ */
+void
+cr_simple_sel_destroy (CRSimpleSel * a_this)
+{
+        g_return_if_fail (a_this);
+
+        if (a_this->name) {
+                cr_string_destroy (a_this->name);
+                a_this->name = NULL;
+        }
+
+        if (a_this->add_sel) {
+                cr_additional_sel_destroy (a_this->add_sel);
+                a_this->add_sel = NULL;
+        }
+
+        if (a_this->next) {
+                cr_simple_sel_destroy (a_this->next);
+        }
+
+        if (a_this) {
+                g_free (a_this);
+        }
+}
diff --git a/src/st/croco/cr-simple-sel.h b/src/st/croco/cr-simple-sel.h
new file mode 100644
index 000000000..d8edc0025
--- /dev/null
+++ b/src/st/croco/cr-simple-sel.h
@@ -0,0 +1,130 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+
+#ifndef __CR_SEL_H__
+#define __CR_SEL_H__
+
+#include <stdio.h>
+#include <glib.h>
+#include "cr-additional-sel.h"
+#include "cr-parsing-location.h"
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *the declaration of the #CRSimpleSel class.
+ *
+ */
+enum Combinator
+{
+        NO_COMBINATOR,
+        COMB_WS,/*whitespace: descendent*/
+        COMB_PLUS,/*'+': preceded by*/
+        COMB_GT/*greater than ('>'): child*/
+} ;
+
+enum SimpleSelectorType
+{
+        NO_SELECTOR_TYPE = 0,
+        UNIVERSAL_SELECTOR = 1,
+        TYPE_SELECTOR = 1 << 1
+} ;
+
+typedef struct _CRSimpleSel CRSimpleSel ;
+
+/**
+ *The abstraction of a css2 simple selection list
+ *as defined by the right part of the "selector" production in the 
+ *appendix D.1 of the css2 spec.
+ *It is basically a list of simple selector, each
+ *simple selector being separated by a combinator.
+ *
+ *In the libcroco's implementation, each simple selector 
+ *is made of at most two parts:
+ *
+ *1/An element name or 'type selector' (which can hold a '*' and
+ *then been called 'universal selector')
+ *
+ *2/An additional selector that "specializes" the preceding type or
+ *universal selector. The additionnal selector can be either
+ *an id selector, or a class selector, or an attribute selector.
+ */
+struct _CRSimpleSel
+{
+        enum SimpleSelectorType type_mask ;
+        gboolean is_case_sentive ;
+        CRString * name ;
+        /**
+         *The combinator that separates
+         *this simple selector from the previous
+         *one.
+         */
+        enum Combinator combinator ;
+
+        /**
+         *The additional selector list of the
+         *current simple selector.
+         *An additional selector may
+         *be a class selector, an id selector,
+         *or an attribute selector.
+         *Note that this field is a linked list.
+         */
+        CRAdditionalSel *add_sel ;
+
+        /*
+         *the specificity as specified by
+         *chapter 6.4.3 of the spec.
+         */
+        gulong specificity ;
+
+        CRSimpleSel *next ;
+        CRSimpleSel *prev ;
+        CRParsingLocation location ;
+} ;
+
+CRSimpleSel * cr_simple_sel_new (void) ;
+
+CRSimpleSel * cr_simple_sel_append_simple_sel (CRSimpleSel *a_this, 
+                                               CRSimpleSel *a_sel) ;
+
+CRSimpleSel * cr_simple_sel_prepend_simple_sel (CRSimpleSel *a_this, 
+                                                CRSimpleSel *a_sel) ;
+
+guchar * cr_simple_sel_to_string (CRSimpleSel const *a_this) ;
+
+guchar * cr_simple_sel_one_to_string (CRSimpleSel const * a_this) ;
+
+enum CRStatus cr_simple_sel_dump (CRSimpleSel const *a_this, FILE *a_fp) ;
+
+enum CRStatus cr_simple_sel_dump_attr_sel_list (CRSimpleSel const *a_this) ;
+
+enum CRStatus cr_simple_sel_compute_specificity (CRSimpleSel *a_this) ;
+
+void cr_simple_sel_destroy (CRSimpleSel *a_this) ;
+
+G_END_DECLS
+
+
+#endif /*__CR_SIMPLE_SEL_H__*/
diff --git a/src/st/croco/cr-statement.c b/src/st/croco/cr-statement.c
new file mode 100644
index 000000000..241fa5f3b
--- /dev/null
+++ b/src/st/croco/cr-statement.c
@@ -0,0 +1,2794 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli.
+ * See COPYRIGHTS files for copyrights information.
+ */
+
+#include <string.h>
+#include "cr-statement.h"
+#include "cr-parser.h"
+
+/**
+ *@file
+ *Definition of the #CRStatement class.
+ */
+
+#define DECLARATION_INDENT_NB 2
+
+static void cr_statement_clear (CRStatement * a_this);
+
+static void  
+parse_font_face_start_font_face_cb (CRDocHandler * a_this,
+                                    CRParsingLocation *a_location)
+{
+        CRStatement *stmt = NULL;
+        enum CRStatus status = CR_OK;
+
+        stmt = cr_statement_new_at_font_face_rule (NULL, NULL);
+        g_return_if_fail (stmt);
+
+        status = cr_doc_handler_set_ctxt (a_this, stmt);
+        g_return_if_fail (status == CR_OK);
+}
+
+static void
+parse_font_face_unrecoverable_error_cb (CRDocHandler * a_this)
+{
+        CRStatement *stmt = NULL;
+	CRStatement **stmtptr = NULL;
+        enum CRStatus status = CR_OK;
+
+        g_return_if_fail (a_this);
+
+	stmtptr = &stmt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
+        if (status != CR_OK) {
+                cr_utils_trace_info ("Couldn't get parsing context. "
+                                     "This may lead to some memory leaks.");
+                return;
+        }
+        if (stmt) {
+                cr_statement_destroy (stmt);
+                cr_doc_handler_set_ctxt (a_this, NULL);
+                return;
+        }
+}
+
+static void
+parse_font_face_property_cb (CRDocHandler * a_this,
+                             CRString * a_name,
+                             CRTerm * a_value, gboolean a_important)
+{
+        enum CRStatus status = CR_OK;
+        CRString *name = NULL;
+        CRDeclaration *decl = NULL;
+        CRStatement *stmt = NULL;
+        CRStatement **stmtptr = NULL;
+
+        g_return_if_fail (a_this && a_name);
+
+	stmtptr = &stmt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
+        g_return_if_fail (status == CR_OK && stmt);
+        g_return_if_fail (stmt->type == AT_FONT_FACE_RULE_STMT);
+
+        name = cr_string_dup (a_name) ;
+        g_return_if_fail (name);
+        decl = cr_declaration_new (stmt, name, a_value);
+        if (!decl) {
+                cr_utils_trace_info ("cr_declaration_new () failed.");
+                goto error;
+        }
+        name = NULL;
+
+        stmt->kind.font_face_rule->decl_list =
+                cr_declaration_append (stmt->kind.font_face_rule->decl_list,
+                                       decl);
+        if (!stmt->kind.font_face_rule->decl_list)
+                goto error;
+        decl = NULL;
+
+      error:
+        if (decl) {
+                cr_declaration_unref (decl);
+                decl = NULL;
+        }
+        if (name) {
+                cr_string_destroy (name);
+                name = NULL;
+        }
+}
+
+static void
+parse_font_face_end_font_face_cb (CRDocHandler * a_this)
+{
+        CRStatement *result = NULL;
+        CRStatement **resultptr = NULL;
+        enum CRStatus status = CR_OK;
+
+        g_return_if_fail (a_this);
+
+	resultptr = &result;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) resultptr);
+        g_return_if_fail (status == CR_OK && result);
+        g_return_if_fail (result->type == AT_FONT_FACE_RULE_STMT);
+
+        status = cr_doc_handler_set_result (a_this, result);
+        g_return_if_fail (status == CR_OK);
+}
+
+static void
+parse_page_start_page_cb (CRDocHandler * a_this,
+                          CRString * a_name, 
+                          CRString * a_pseudo_page,
+                          CRParsingLocation *a_location)
+{
+        CRStatement *stmt = NULL;
+        enum CRStatus status = CR_OK;
+        CRString *page_name = NULL, *pseudo_name = NULL ;
+
+        if (a_name)
+                page_name = cr_string_dup (a_name) ;
+        if (a_pseudo_page)
+                pseudo_name = cr_string_dup (a_pseudo_page) ;
+
+        stmt = cr_statement_new_at_page_rule (NULL, NULL, 
+                                              page_name,
+                                              pseudo_name);
+        page_name = NULL ;
+        pseudo_name = NULL ;
+        g_return_if_fail (stmt);
+        status = cr_doc_handler_set_ctxt (a_this, stmt);
+        g_return_if_fail (status == CR_OK);
+}
+
+static void
+parse_page_unrecoverable_error_cb (CRDocHandler * a_this)
+{
+        CRStatement *stmt = NULL;
+        CRStatement **stmtptr = NULL;
+        enum CRStatus status = CR_OK;
+
+        g_return_if_fail (a_this);
+
+	stmtptr = &stmt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
+        if (status != CR_OK) {
+                cr_utils_trace_info ("Couldn't get parsing context. "
+                                     "This may lead to some memory leaks.");
+                return;
+        }
+        if (stmt) {
+                cr_statement_destroy (stmt);
+                stmt = NULL;
+                cr_doc_handler_set_ctxt (a_this, NULL);
+        }
+}
+
+static void
+parse_page_property_cb (CRDocHandler * a_this,
+                        CRString * a_name,
+                        CRTerm * a_expression, gboolean a_important)
+{
+        CRString *name = NULL;
+        CRStatement *stmt = NULL;
+        CRStatement **stmtptr = NULL;
+        CRDeclaration *decl = NULL;
+        enum CRStatus status = CR_OK;
+
+	stmtptr = &stmt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
+        g_return_if_fail (status == CR_OK && stmt->type == AT_PAGE_RULE_STMT);
+
+        name = cr_string_dup (a_name);
+        g_return_if_fail (name);
+
+        decl = cr_declaration_new (stmt, name, a_expression);
+        g_return_if_fail (decl);
+        decl->important = a_important;
+        stmt->kind.page_rule->decl_list =
+                cr_declaration_append (stmt->kind.page_rule->decl_list, decl);
+        g_return_if_fail (stmt->kind.page_rule->decl_list);
+}
+
+static void
+parse_page_end_page_cb (CRDocHandler * a_this,
+                        CRString * a_name, 
+                        CRString * a_pseudo_page)
+{
+        enum CRStatus status = CR_OK;
+        CRStatement *stmt = NULL;
+        CRStatement **stmtptr = NULL;
+
+	stmtptr = &stmt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
+        g_return_if_fail (status == CR_OK && stmt);
+        g_return_if_fail (stmt->type == AT_PAGE_RULE_STMT);
+
+        status = cr_doc_handler_set_result (a_this, stmt);
+        g_return_if_fail (status == CR_OK);
+}
+
+static void
+parse_at_media_start_media_cb (CRDocHandler * a_this, 
+                               GList * a_media_list,
+                               CRParsingLocation *a_location)
+{
+        enum CRStatus status = CR_OK;
+        CRStatement *at_media = NULL;
+        GList *media_list = NULL;
+
+        g_return_if_fail (a_this && a_this->priv);
+
+        if (a_media_list) {
+                /*duplicate media list */
+                media_list = cr_utils_dup_glist_of_cr_string 
+                        (a_media_list);
+        }
+
+        g_return_if_fail (media_list);
+
+        /*make sure cr_statement_new_at_media_rule works in this case. */
+        at_media = cr_statement_new_at_media_rule (NULL, NULL, media_list);
+
+        status = cr_doc_handler_set_ctxt (a_this, at_media);
+        g_return_if_fail (status == CR_OK);
+        status = cr_doc_handler_set_result (a_this, at_media);
+        g_return_if_fail (status == CR_OK);
+}
+
+static void
+parse_at_media_unrecoverable_error_cb (CRDocHandler * a_this)
+{
+        enum CRStatus status = CR_OK;
+        CRStatement *stmt = NULL;
+        CRStatement **stmtptr = NULL;
+
+        g_return_if_fail (a_this);
+
+	stmtptr = &stmt;
+        status = cr_doc_handler_get_result (a_this, (gpointer *) stmtptr);
+        if (status != CR_OK) {
+                cr_utils_trace_info ("Couldn't get parsing context. "
+                                     "This may lead to some memory leaks.");
+                return;
+        }
+        if (stmt) {
+                cr_statement_destroy (stmt);
+                stmt = NULL;
+                cr_doc_handler_set_ctxt (a_this, NULL);
+                cr_doc_handler_set_result (a_this, NULL);
+        }
+}
+
+static void
+parse_at_media_start_selector_cb (CRDocHandler * a_this,
+                                  CRSelector * a_sellist)
+{
+        enum CRStatus status = CR_OK;
+        CRStatement *at_media = NULL;
+        CRStatement **at_media_ptr = NULL;
+	CRStatement *ruleset = NULL;
+
+        g_return_if_fail (a_this && a_this->priv && a_sellist);
+
+	at_media_ptr = &at_media;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) at_media_ptr);
+        g_return_if_fail (status == CR_OK && at_media);
+        g_return_if_fail (at_media->type == AT_MEDIA_RULE_STMT);
+        ruleset = cr_statement_new_ruleset (NULL, a_sellist, NULL, at_media);
+        g_return_if_fail (ruleset);
+        status = cr_doc_handler_set_ctxt (a_this, ruleset);
+        g_return_if_fail (status == CR_OK);
+}
+
+static void
+parse_at_media_property_cb (CRDocHandler * a_this,
+                            CRString * a_name, CRTerm * a_value,
+                            gboolean a_important)
+{
+        enum CRStatus status = CR_OK;
+
+        /*
+         *the current ruleset stmt, child of the 
+         *current at-media being parsed.
+         */
+        CRStatement *stmt = NULL;
+        CRStatement **stmtptr = NULL;
+        CRDeclaration *decl = NULL;
+        CRString *name = NULL;
+
+        g_return_if_fail (a_this && a_name);
+
+        name = cr_string_dup (a_name) ;
+        g_return_if_fail (name);
+
+	stmtptr = &stmt;
+        status = cr_doc_handler_get_ctxt (a_this, 
+                                          (gpointer *) stmtptr);
+        g_return_if_fail (status == CR_OK && stmt);
+        g_return_if_fail (stmt->type == RULESET_STMT);
+
+        decl = cr_declaration_new (stmt, name, a_value);
+        g_return_if_fail (decl);
+        decl->important = a_important;
+        status = cr_statement_ruleset_append_decl (stmt, decl);
+        g_return_if_fail (status == CR_OK);
+}
+
+static void
+parse_at_media_end_selector_cb (CRDocHandler * a_this, 
+                                CRSelector * a_sellist)
+{
+        enum CRStatus status = CR_OK;
+
+        /*
+         *the current ruleset stmt, child of the 
+         *current at-media being parsed.
+         */
+        CRStatement *stmt = NULL;
+        CRStatement **stmtptr = NULL;
+
+        g_return_if_fail (a_this && a_sellist);
+
+	stmtptr = &stmt;
+        status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
+        g_return_if_fail (status == CR_OK && stmt
+                          && stmt->type == RULESET_STMT);
+        g_return_if_fail (stmt->kind.ruleset->parent_media_rule);
+
+        status = cr_doc_handler_set_ctxt
+                (a_this, stmt->kind.ruleset->parent_media_rule);
+        g_return_if_fail (status == CR_OK);
+}
+
+static void
+parse_at_media_end_media_cb (CRDocHandler * a_this, 
+                             GList * a_media_list)
+{
+        enum CRStatus status = CR_OK;
+        CRStatement *at_media = NULL;
+        CRStatement **at_media_ptr = NULL;
+
+        g_return_if_fail (a_this && a_this->priv);
+
+	at_media_ptr = &at_media;
+        status = cr_doc_handler_get_ctxt (a_this, 
+                                          (gpointer *) at_media_ptr);
+        g_return_if_fail (status == CR_OK && at_media);
+        status = cr_doc_handler_set_result (a_this, at_media);
+}
+
+static void
+parse_ruleset_start_selector_cb (CRDocHandler * a_this,
+                                 CRSelector * a_sellist)
+{
+        CRStatement *ruleset = NULL;
+
+        g_return_if_fail (a_this && a_this->priv && a_sellist);
+
+        ruleset = cr_statement_new_ruleset (NULL, a_sellist, NULL, NULL);
+        g_return_if_fail (ruleset);
+
+        cr_doc_handler_set_result (a_this, ruleset);
+}
+
+static void
+parse_ruleset_unrecoverable_error_cb (CRDocHandler * a_this)
+{
+        CRStatement *stmt = NULL;
+        CRStatement **stmtptr = NULL;
+        enum CRStatus status = CR_OK;
+
+	stmtptr = &stmt;
+        status = cr_doc_handler_get_result (a_this, (gpointer *) stmtptr);
+        if (status != CR_OK) {
+                cr_utils_trace_info ("Couldn't get parsing context. "
+                                     "This may lead to some memory leaks.");
+                return;
+        }
+        if (stmt) {
+                cr_statement_destroy (stmt);
+                stmt = NULL;
+                cr_doc_handler_set_result (a_this, NULL);
+        }
+}
+
+static void
+parse_ruleset_property_cb (CRDocHandler * a_this,
+                           CRString * a_name,
+                           CRTerm * a_value, gboolean a_important)
+{
+        enum CRStatus status = CR_OK;
+        CRStatement *ruleset = NULL;
+        CRStatement **rulesetptr = NULL;
+        CRDeclaration *decl = NULL;
+        CRString *stringue = NULL;
+
+        g_return_if_fail (a_this && a_this->priv && a_name);
+
+        stringue = cr_string_dup (a_name);
+        g_return_if_fail (stringue);
+
+	rulesetptr = &ruleset;
+        status = cr_doc_handler_get_result (a_this, (gpointer *) rulesetptr);
+        g_return_if_fail (status == CR_OK
+                          && ruleset 
+                          && ruleset->type == RULESET_STMT);
+
+        decl = cr_declaration_new (ruleset, stringue, a_value);
+        g_return_if_fail (decl);
+        decl->important = a_important;
+        status = cr_statement_ruleset_append_decl (ruleset, decl);
+        g_return_if_fail (status == CR_OK);
+}
+
+static void
+parse_ruleset_end_selector_cb (CRDocHandler * a_this, 
+                               CRSelector * a_sellist)
+{
+        CRStatement *result = NULL;
+        CRStatement **resultptr = NULL;
+        enum CRStatus status = CR_OK;
+
+        g_return_if_fail (a_this && a_sellist);
+
+	resultptr = &result;
+        status = cr_doc_handler_get_result (a_this, (gpointer *) resultptr);
+
+        g_return_if_fail (status == CR_OK
+                          && result 
+                          && result->type == RULESET_STMT);
+}
+
+static void
+cr_statement_clear (CRStatement * a_this)
+{
+        g_return_if_fail (a_this);
+
+        switch (a_this->type) {
+        case AT_RULE_STMT:
+                break;
+        case RULESET_STMT:
+                if (!a_this->kind.ruleset)
+                        return;
+                if (a_this->kind.ruleset->sel_list) {
+                        cr_selector_unref (a_this->kind.ruleset->sel_list);
+                        a_this->kind.ruleset->sel_list = NULL;
+                }
+                if (a_this->kind.ruleset->decl_list) {
+                        cr_declaration_destroy
+                                (a_this->kind.ruleset->decl_list);
+                        a_this->kind.ruleset->decl_list = NULL;
+                }
+                g_free (a_this->kind.ruleset);
+                a_this->kind.ruleset = NULL;
+                break;
+
+        case AT_IMPORT_RULE_STMT:
+                if (!a_this->kind.import_rule)
+                        return;
+                if (a_this->kind.import_rule->url) {
+                        cr_string_destroy 
+                                (a_this->kind.import_rule->url) ;
+                        a_this->kind.import_rule->url = NULL;
+                }
+                g_free (a_this->kind.import_rule);
+                a_this->kind.import_rule = NULL;
+                break;
+
+        case AT_MEDIA_RULE_STMT:
+                if (!a_this->kind.media_rule)
+                        return;
+                if (a_this->kind.media_rule->rulesets) {
+                        cr_statement_destroy
+                                (a_this->kind.media_rule->rulesets);
+                        a_this->kind.media_rule->rulesets = NULL;
+                }
+                if (a_this->kind.media_rule->media_list) {
+                        GList *cur = NULL;
+
+                        for (cur = a_this->kind.media_rule->media_list;
+                             cur; cur = cur->next) {
+                                if (cur->data) {
+                                        cr_string_destroy ((CRString *) cur->data);
+                                        cur->data = NULL;
+                                }
+
+                        }
+                        g_list_free (a_this->kind.media_rule->media_list);
+                        a_this->kind.media_rule->media_list = NULL;
+                }
+                g_free (a_this->kind.media_rule);
+                a_this->kind.media_rule = NULL;
+                break;
+
+        case AT_PAGE_RULE_STMT:
+                if (!a_this->kind.page_rule)
+                        return;
+
+                if (a_this->kind.page_rule->decl_list) {
+                        cr_declaration_destroy
+                                (a_this->kind.page_rule->decl_list);
+                        a_this->kind.page_rule->decl_list = NULL;
+                }
+                if (a_this->kind.page_rule->name) {
+                        cr_string_destroy 
+                                (a_this->kind.page_rule->name);
+                        a_this->kind.page_rule->name = NULL;
+                }
+                if (a_this->kind.page_rule->pseudo) {
+                        cr_string_destroy
+                                (a_this->kind.page_rule->pseudo);
+                        a_this->kind.page_rule->pseudo = NULL;
+                }
+                g_free (a_this->kind.page_rule);
+                a_this->kind.page_rule = NULL;
+                break;
+
+        case AT_CHARSET_RULE_STMT:
+                if (!a_this->kind.charset_rule)
+                        return;
+
+                if (a_this->kind.charset_rule->charset) {
+                        cr_string_destroy
+                                (a_this->kind.charset_rule->charset);
+                        a_this->kind.charset_rule->charset = NULL;
+                }
+                g_free (a_this->kind.charset_rule);
+                a_this->kind.charset_rule = NULL;
+                break;
+
+        case AT_FONT_FACE_RULE_STMT:
+                if (!a_this->kind.font_face_rule)
+                        return;
+
+                if (a_this->kind.font_face_rule->decl_list) {
+                        cr_declaration_unref
+                                (a_this->kind.font_face_rule->decl_list);
+                        a_this->kind.font_face_rule->decl_list = NULL;
+                }
+                g_free (a_this->kind.font_face_rule);
+                a_this->kind.font_face_rule = NULL;
+                break;
+
+        default:
+                break;
+        }
+}
+
+/**
+ * cr_statement_ruleset_to_string:
+ *
+ *@a_this: the current instance of #CRStatement
+ *@a_indent: the number of whitespace to use for indentation
+ *
+ *Serializes the ruleset statement into a string
+ *
+ *Returns the newly allocated serialised string. Must be freed
+ *by the caller, using g_free().
+ */
+static gchar *
+cr_statement_ruleset_to_string (CRStatement const * a_this, glong a_indent)
+{
+        GString *stringue = NULL;
+        gchar *tmp_str = NULL,
+                *result = NULL;
+
+        g_return_val_if_fail (a_this && a_this->type == RULESET_STMT, NULL);
+
+        stringue = g_string_new (NULL);
+
+        if (a_this->kind.ruleset->sel_list) {
+                if (a_indent)
+                        cr_utils_dump_n_chars2 (' ', stringue, a_indent);
+
+                tmp_str =
+                        (gchar *) cr_selector_to_string (a_this->kind.ruleset->
+                                               sel_list);
+                if (tmp_str) {
+                        g_string_append (stringue, tmp_str);
+                        g_free (tmp_str);
+                        tmp_str = NULL;
+                }
+        }
+        g_string_append (stringue, " {\n");
+        if (a_this->kind.ruleset->decl_list) {
+                tmp_str = (gchar *) cr_declaration_list_to_string2
+                        (a_this->kind.ruleset->decl_list,
+                         a_indent + DECLARATION_INDENT_NB, TRUE);
+                if (tmp_str) {
+                        g_string_append (stringue, tmp_str);
+                        g_free (tmp_str);
+                        tmp_str = NULL;
+                }
+                g_string_append (stringue, "\n");
+                cr_utils_dump_n_chars2 (' ', stringue, a_indent);
+        }
+        g_string_append (stringue, "}");
+        result = stringue->str;
+
+        if (stringue) {
+                g_string_free (stringue, FALSE);
+                stringue = NULL;
+        }
+        if (tmp_str) {
+                g_free (tmp_str);
+                tmp_str = NULL;
+        }
+        return result;
+}
+
+
+/**
+ * cr_statement_font_face_rule_to_string:
+ *
+ *@a_this: the current instance of #CRStatement to consider
+ *It must be a font face rule statement.
+ *@a_indent: the number of white spaces of indentation.
+ *
+ *Serializes a font face rule statement into a string.
+ *
+ *Returns the serialized string. Must be deallocated by the caller
+ *using g_free().
+ */
+static gchar *
+cr_statement_font_face_rule_to_string (CRStatement const * a_this,
+                                       glong a_indent)
+{
+        gchar *result = NULL, *tmp_str = NULL ;
+        GString *stringue = NULL ;
+
+        g_return_val_if_fail (a_this 
+                              && a_this->type == AT_FONT_FACE_RULE_STMT,
+                              NULL);
+
+        if (a_this->kind.font_face_rule->decl_list) {
+                stringue = g_string_new (NULL) ;
+                g_return_val_if_fail (stringue, NULL) ;
+                if (a_indent)
+                        cr_utils_dump_n_chars2 (' ', stringue, 
+                                        a_indent);
+                g_string_append (stringue, "@font-face {\n");
+                tmp_str = (gchar *) cr_declaration_list_to_string2 
+                        (a_this->kind.font_face_rule->decl_list,
+                         a_indent + DECLARATION_INDENT_NB, TRUE) ;
+                if (tmp_str) {
+                        g_string_append (stringue,
+                                         tmp_str) ;
+                        g_free (tmp_str) ;
+                        tmp_str = NULL ;
+                }
+                g_string_append (stringue, "\n}");
+        }
+        if (stringue) {
+                result = stringue->str ;
+                g_string_free (stringue, FALSE) ;
+                stringue = NULL ;
+        }
+        return result ;
+}
+
+
+/**
+ * cr_statement_charset_to_string:
+ *
+ *Serialises an \@charset statement into a string.
+ *@a_this: the statement to serialize.
+ *@a_indent: the number of indentation spaces
+ *
+ *Returns the serialized charset statement. Must be
+ *freed by the caller using g_free().
+ */
+static gchar *
+cr_statement_charset_to_string (CRStatement const *a_this,
+                                gulong a_indent)
+{
+        gchar *str = NULL ;
+        GString *stringue = NULL ;
+
+        g_return_val_if_fail (a_this
+                              && a_this->type == AT_CHARSET_RULE_STMT,
+                              NULL) ;
+
+        if (a_this->kind.charset_rule
+            && a_this->kind.charset_rule->charset
+            && a_this->kind.charset_rule->charset->stryng
+            && a_this->kind.charset_rule->charset->stryng->str) {
+                str = g_strndup (a_this->kind.charset_rule->charset->stryng->str,
+                                 a_this->kind.charset_rule->charset->stryng->len);
+                g_return_val_if_fail (str, NULL);
+                stringue = g_string_new (NULL) ;
+                g_return_val_if_fail (stringue, NULL) ;
+                cr_utils_dump_n_chars2 (' ', stringue, a_indent);
+                g_string_append_printf (stringue, 
+                                        "@charset \"%s\" ;", str);
+                if (str) {
+                        g_free (str);
+                        str = NULL;
+                }
+        }
+        if (stringue) {
+                str = stringue->str ;
+                g_string_free (stringue, FALSE) ;
+        }
+        return str ;
+}
+
+
+/**
+ * cr_statement_at_page_rule_to_string:
+ *
+ *Serialises the at page rule statement into a string
+ *@a_this: the current instance of #CRStatement. Must
+ *be an "\@page" rule statement.
+ *
+ *Returns the serialized string. Must be freed by the caller
+ */
+static gchar *
+cr_statement_at_page_rule_to_string (CRStatement const *a_this,
+                                     gulong a_indent)
+{
+        GString *stringue = NULL;
+        gchar *result = NULL ;
+
+        stringue = g_string_new (NULL) ;
+
+        cr_utils_dump_n_chars2 (' ', stringue, a_indent) ;
+        g_string_append (stringue, "@page");
+	if (a_this->kind.page_rule->name
+	    && a_this->kind.page_rule->name->stryng) {
+		g_string_append_printf 
+		  (stringue, " %s",
+		   a_this->kind.page_rule->name->stryng->str) ;
+        } else {
+                g_string_append (stringue, " ");
+        }
+	if (a_this->kind.page_rule->pseudo
+	    && a_this->kind.page_rule->pseudo->stryng) {
+		g_string_append_printf 
+		  (stringue,  " :%s",
+		   a_this->kind.page_rule->pseudo->stryng->str) ;
+        }
+        if (a_this->kind.page_rule->decl_list) {
+                gchar *str = NULL ;
+                g_string_append (stringue, " {\n");
+                str = (gchar *) cr_declaration_list_to_string2
+                        (a_this->kind.page_rule->decl_list,
+                         a_indent + DECLARATION_INDENT_NB, TRUE) ;
+                if (str) {
+                        g_string_append (stringue, str) ;
+                        g_free (str) ;
+                        str = NULL ;
+                }
+                g_string_append (stringue, "\n}\n");
+        }
+        result = stringue->str ;
+        g_string_free (stringue, FALSE) ;
+        stringue = NULL ;
+        return result ;
+}
+
+
+/**
+ *Serializes an \@media statement.
+ *@param a_this the current instance of #CRStatement
+ *@param a_indent the number of spaces of indentation.
+ *@return the serialized \@media statement. Must be freed
+ *by the caller using g_free().
+ */
+static gchar *
+cr_statement_media_rule_to_string (CRStatement const *a_this,
+                                   gulong a_indent)
+{
+        gchar *str = NULL ;
+        GString *stringue = NULL ;
+        GList const *cur = NULL;
+
+        g_return_val_if_fail (a_this->type == AT_MEDIA_RULE_STMT,
+                              NULL);
+
+        if (a_this->kind.media_rule) {
+                stringue = g_string_new (NULL) ;                
+                cr_utils_dump_n_chars2 (' ', stringue, a_indent);
+                g_string_append (stringue, "@media");
+
+                for (cur = a_this->kind.media_rule->media_list; cur;
+                     cur = cur->next) {
+                        if (cur->data) {
+                                gchar *str2 = cr_string_dup2
+                                        ((CRString const *) cur->data);
+
+                                if (str2) {
+                                        if (cur->prev) {
+                                                g_string_append
+                                                        (stringue, 
+                                                         ",");
+                                        }
+                                        g_string_append_printf 
+                                                (stringue, 
+                                                 " %s", str2);
+                                        g_free (str2);
+                                        str2 = NULL;
+                                }
+                        }
+                }
+                g_string_append (stringue, " {\n");
+                str = cr_statement_list_to_string
+                        (a_this->kind.media_rule->rulesets,
+                         a_indent + DECLARATION_INDENT_NB) ;
+                if (str) {
+                        g_string_append (stringue, str) ;
+                        g_free (str) ;
+                        str = NULL ;
+                }
+                g_string_append (stringue, "\n}");
+        }
+        if (stringue) {
+                str = stringue->str ;
+                g_string_free (stringue, FALSE) ;
+        }
+        return str ;
+}
+
+
+static gchar *
+cr_statement_import_rule_to_string (CRStatement const *a_this,
+                                    gulong a_indent)
+{
+        GString *stringue = NULL ;
+        gchar *str = NULL;
+
+        g_return_val_if_fail (a_this
+                              && a_this->type == AT_IMPORT_RULE_STMT
+                              && a_this->kind.import_rule,
+                              NULL) ;
+
+        if (a_this->kind.import_rule->url
+            && a_this->kind.import_rule->url->stryng) { 
+                stringue = g_string_new (NULL) ;
+                g_return_val_if_fail (stringue, NULL) ;
+                str = g_strndup (a_this->kind.import_rule->url->stryng->str,
+                                 a_this->kind.import_rule->url->stryng->len);
+                cr_utils_dump_n_chars2 (' ', stringue, a_indent);
+                if (str) {
+                        g_string_append_printf (stringue,
+                                                "@import url(\"%s\")", 
+                                                str);
+                        g_free (str);
+                        str = NULL ;
+                } else          /*there is no url, so no import rule, get out! */
+                        return NULL;
+
+                if (a_this->kind.import_rule->media_list) {
+                        GList const *cur = NULL;
+
+                        for (cur = a_this->kind.import_rule->media_list;
+                             cur; cur = cur->next) {
+                                if (cur->data) {
+                                        CRString const *crstr = cur->data;
+
+                                        if (cur->prev) {
+                                                g_string_append 
+                                                        (stringue, ", ");
+                                        }
+                                        if (crstr 
+                                            && crstr->stryng
+                                            && crstr->stryng->str) {
+                                                g_string_append_len 
+                                                        (stringue,
+                                                         crstr->stryng->str,
+                                                         crstr->stryng->len) ;
+                                        }
+                                }
+                        }
+                }
+                g_string_append (stringue, " ;");
+        }
+        if (stringue) {
+                str = stringue->str ;
+                g_string_free (stringue, FALSE) ;
+                stringue = NULL ;
+        }
+        return str ;
+}
+
+
+/*******************
+ *public functions
+ ******************/
+
+/**
+ * cr_statement_does_buf_parses_against_core:
+ *
+ *@a_buf: the buffer to parse.
+ *@a_encoding: the character encoding of a_buf.
+ *
+ *Tries to parse a buffer and says whether if the content of the buffer
+ *is a css statement as defined by the "Core CSS Grammar" (chapter 4 of the
+ *css spec) or not.
+ *
+ *Returns TRUE if the buffer parses against the core grammar, false otherwise.
+ */
+gboolean
+cr_statement_does_buf_parses_against_core (const guchar * a_buf,
+                                           enum CREncoding a_encoding)
+{
+        CRParser *parser = NULL;
+        enum CRStatus status = CR_OK;
+        gboolean result = FALSE;
+
+        parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
+                                         a_encoding, FALSE);
+        g_return_val_if_fail (parser, FALSE);
+
+        status = cr_parser_set_use_core_grammar (parser, TRUE);
+        if (status != CR_OK) {
+                goto cleanup;
+        }
+
+        status = cr_parser_parse_statement_core (parser);
+        if (status == CR_OK) {
+                result = TRUE;
+        }
+
+      cleanup:
+        if (parser) {
+                cr_parser_destroy (parser);
+        }
+
+        return result;
+}
+
+/**
+ * cr_statement_parse_from_buf:
+ *
+ *@a_buf: the buffer to parse.
+ *@a_encoding: the character encoding of a_buf.
+ *
+ *Parses a buffer that contains a css statement and returns 
+ *an instance of #CRStatement in case of successful parsing.
+ *TODO: at support of "\@import" rules.
+ *
+ *Returns the newly built instance of #CRStatement in case
+ *of successful parsing, NULL otherwise.
+ */
+CRStatement *
+cr_statement_parse_from_buf (const guchar * a_buf, enum CREncoding a_encoding)
+{
+        CRStatement *result = NULL;
+
+        /*
+         *The strategy of this function is "brute force".
+         *It tries to parse all the types of CRStatement it knows about.
+         *I could do this a smarter way but I don't have the time now.
+         *I think I will revisit this when time of performances and
+         *pull based incremental parsing comes.
+         */
+
+        result = cr_statement_ruleset_parse_from_buf (a_buf, a_encoding);
+        if (!result) {
+                result = cr_statement_at_charset_rule_parse_from_buf
+                        (a_buf, a_encoding);
+        } else {
+                goto out;
+        }
+
+        if (!result) {
+                result = cr_statement_at_media_rule_parse_from_buf
+                        (a_buf, a_encoding);
+        } else {
+                goto out;
+        }
+
+        if (!result) {
+                result = cr_statement_at_charset_rule_parse_from_buf
+                        (a_buf, a_encoding);
+        } else {
+                goto out;
+        }
+
+        if (!result) {
+                result = cr_statement_font_face_rule_parse_from_buf
+                        (a_buf, a_encoding);
+
+        } else {
+                goto out;
+        }
+
+        if (!result) {
+                result = cr_statement_at_page_rule_parse_from_buf
+                        (a_buf, a_encoding);
+        } else {
+                goto out;
+        }
+
+        if (!result) {
+                result = cr_statement_at_import_rule_parse_from_buf
+                        (a_buf, a_encoding);
+        } else {
+                goto out;
+        }
+
+      out:
+        return result;
+}
+
+/**
+ * cr_statement_ruleset_parse_from_buf:
+ *
+ *@a_buf: the buffer to parse.
+ *@a_enc: the character encoding of a_buf.
+ *
+ *Parses a buffer that contains a ruleset statement an instanciates
+ *a #CRStatement of type RULESET_STMT.
+ *
+ *Returns the newly built instance of #CRStatement in case of successful parsing,
+ *NULL otherwise.
+ */
+CRStatement *
+cr_statement_ruleset_parse_from_buf (const guchar * a_buf,
+                                     enum CREncoding a_enc)
+{
+        enum CRStatus status = CR_OK;
+        CRStatement *result = NULL;
+        CRStatement **resultptr = NULL;
+        CRParser *parser = NULL;
+        CRDocHandler *sac_handler = NULL;
+
+        g_return_val_if_fail (a_buf, NULL);
+
+        parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), 
+                                         a_enc, FALSE);
+
+        g_return_val_if_fail (parser, NULL);
+
+        sac_handler = cr_doc_handler_new ();
+        g_return_val_if_fail (parser, NULL);
+
+        sac_handler->start_selector = parse_ruleset_start_selector_cb;
+        sac_handler->end_selector = parse_ruleset_end_selector_cb;
+        sac_handler->property = parse_ruleset_property_cb;
+        sac_handler->unrecoverable_error =
+                parse_ruleset_unrecoverable_error_cb;
+
+        cr_parser_set_sac_handler (parser, sac_handler);
+        cr_parser_try_to_skip_spaces_and_comments (parser);
+        status = cr_parser_parse_ruleset (parser);
+        if (status != CR_OK) {
+                goto cleanup;
+        }
+
+	resultptr = &result;
+        status = cr_doc_handler_get_result (sac_handler,
+                                            (gpointer *) resultptr);
+        if (!((status == CR_OK) && result)) {
+                if (result) {
+                        cr_statement_destroy (result);
+                        result = NULL;
+                }
+        }
+
+      cleanup:
+        if (parser) {
+                cr_parser_destroy (parser);
+                parser = NULL;
+                sac_handler = NULL ;
+        }
+        if (sac_handler) {
+                cr_doc_handler_unref (sac_handler);
+                sac_handler = NULL;
+        }
+        return result;
+}
+
+/**
+ * cr_statement_new_ruleset:
+ *
+ *@a_sel_list: the list of #CRSimpleSel (selectors)
+ *the rule applies to.
+ *@a_decl_list: the list of instances of #CRDeclaration
+ *that composes the ruleset.
+ *@a_media_types: a list of instances of GString that
+ *describe the media list this ruleset applies to.
+ *
+ *Creates a new instance of #CRStatement of type
+ *#CRRulSet.
+ *
+ *Returns the new instance of #CRStatement or NULL if something
+ *went wrong.
+ */
+CRStatement *
+cr_statement_new_ruleset (CRStyleSheet * a_sheet,
+                          CRSelector * a_sel_list,
+                          CRDeclaration * a_decl_list,
+                          CRStatement * a_parent_media_rule)
+{
+        CRStatement *result = NULL;
+
+        g_return_val_if_fail (a_sel_list, NULL);
+
+        if (a_parent_media_rule) {
+                g_return_val_if_fail
+                        (a_parent_media_rule->type == AT_MEDIA_RULE_STMT,
+                         NULL);
+                g_return_val_if_fail (a_parent_media_rule->kind.media_rule,
+                                      NULL);
+        }
+
+        result = g_try_malloc (sizeof (CRStatement));
+
+        if (!result) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+
+        memset (result, 0, sizeof (CRStatement));
+        result->type = RULESET_STMT;
+        result->kind.ruleset = g_try_malloc (sizeof (CRRuleSet));
+
+        if (!result->kind.ruleset) {
+                cr_utils_trace_info ("Out of memory");
+                if (result)
+                        g_free (result);
+                return NULL;
+        }
+
+        memset (result->kind.ruleset, 0, sizeof (CRRuleSet));
+        result->kind.ruleset->sel_list = a_sel_list;
+        if (a_sel_list)
+                cr_selector_ref (a_sel_list);
+        result->kind.ruleset->decl_list = a_decl_list;
+
+        if (a_parent_media_rule) {
+                result->kind.ruleset->parent_media_rule = a_parent_media_rule;
+                a_parent_media_rule->kind.media_rule->rulesets =
+                        cr_statement_append
+                        (a_parent_media_rule->kind.media_rule->rulesets,
+                         result);
+        }
+
+        cr_statement_set_parent_sheet (result, a_sheet);
+
+        return result;
+}
+
+/**
+ * cr_statement_at_media_rule_parse_from_buf:
+ *
+ *@a_buf: the input to parse.
+ *@a_enc: the encoding of the buffer.
+ *
+ *Parses a buffer that contains an "\@media" declaration
+ *and builds an \@media css statement.
+ *
+ *Returns the \@media statement, or NULL if the buffer could not
+ *be successfully parsed.
+ */
+CRStatement *
+cr_statement_at_media_rule_parse_from_buf (const guchar * a_buf,
+                                           enum CREncoding a_enc)
+{
+        CRParser *parser = NULL;
+        CRStatement *result = NULL;
+        CRStatement **resultptr = NULL;
+        CRDocHandler *sac_handler = NULL;
+        enum CRStatus status = CR_OK;
+
+        parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), 
+                                         a_enc, FALSE);
+        if (!parser) {
+                cr_utils_trace_info ("Instantiation of the parser failed");
+                goto cleanup;
+        }
+
+        sac_handler = cr_doc_handler_new ();
+        if (!sac_handler) {
+                cr_utils_trace_info
+                        ("Instantiation of the sac handler failed");
+                goto cleanup;
+        }
+
+        sac_handler->start_media = parse_at_media_start_media_cb;
+        sac_handler->start_selector = parse_at_media_start_selector_cb;
+        sac_handler->property = parse_at_media_property_cb;
+        sac_handler->end_selector = parse_at_media_end_selector_cb;
+        sac_handler->end_media = parse_at_media_end_media_cb;
+        sac_handler->unrecoverable_error =
+                parse_at_media_unrecoverable_error_cb;
+
+        status = cr_parser_set_sac_handler (parser, sac_handler);
+        if (status != CR_OK)
+                goto cleanup;
+
+        status = cr_parser_try_to_skip_spaces_and_comments (parser);
+        if (status != CR_OK)
+                goto cleanup;
+
+        status = cr_parser_parse_media (parser);
+        if (status != CR_OK)
+                goto cleanup;
+
+	resultptr = &result;
+        status = cr_doc_handler_get_result (sac_handler,
+                                            (gpointer *) resultptr);
+        if (status != CR_OK)
+                goto cleanup;
+
+      cleanup:
+
+        if (parser) {
+                cr_parser_destroy (parser);
+                parser = NULL;
+                sac_handler = NULL ;
+        }
+        if (sac_handler) {
+                cr_doc_handler_unref (sac_handler);
+                sac_handler = NULL;
+        }
+
+        return result;
+}
+
+/**
+ * cr_statement_new_at_media_rule:
+ *
+ *@a_ruleset: the ruleset statements contained
+ *in the \@media rule.
+ *@a_media: the media string list. A list of GString pointers.
+ *
+ *Instanciates an instance of #CRStatement of type
+ *AT_MEDIA_RULE_STMT (\@media ruleset).
+ *
+ */
+CRStatement *
+cr_statement_new_at_media_rule (CRStyleSheet * a_sheet,
+                                CRStatement * a_rulesets, GList * a_media)
+{
+        CRStatement *result = NULL,
+                *cur = NULL;
+
+        if (a_rulesets)
+                g_return_val_if_fail (a_rulesets->type == RULESET_STMT, NULL);
+
+        result = g_try_malloc (sizeof (CRStatement));
+
+        if (!result) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+
+        memset (result, 0, sizeof (CRStatement));
+        result->type = AT_MEDIA_RULE_STMT;
+
+        result->kind.media_rule = g_try_malloc (sizeof (CRAtMediaRule));
+        if (!result->kind.media_rule) {
+                cr_utils_trace_info ("Out of memory");
+                g_free (result);
+                return NULL;
+        }
+        memset (result->kind.media_rule, 0, sizeof (CRAtMediaRule));
+        result->kind.media_rule->rulesets = a_rulesets;
+        for (cur = a_rulesets; cur; cur = cur->next) {
+                if (cur->type != RULESET_STMT || !cur->kind.ruleset) {
+                        cr_utils_trace_info ("Bad parameter a_rulesets. "
+                                             "It should be a list of "
+                                             "correct ruleset statement only !");
+                        goto error;
+                }
+                cur->kind.ruleset->parent_media_rule = result;
+        }
+
+        result->kind.media_rule->media_list = a_media;
+        if (a_sheet) {
+                cr_statement_set_parent_sheet (result, a_sheet);
+        }
+
+        return result;
+
+      error:
+        return NULL;
+}
+
+/**
+ * cr_statement_new_at_import_rule:
+ *
+ *@a_url: the url to connect to the get the file
+ *to be imported.
+ *@a_sheet: the imported parsed stylesheet.
+ *
+ *Creates a new instance of #CRStatment of type
+ *#CRAtImportRule.
+ *
+ *Returns the newly built instance of #CRStatement.
+ */
+CRStatement *
+cr_statement_new_at_import_rule (CRStyleSheet * a_container_sheet,
+                                 CRString * a_url,
+                                 GList * a_media_list,
+                                 CRStyleSheet * a_imported_sheet)
+{
+        CRStatement *result = NULL;
+
+        result = g_try_malloc (sizeof (CRStatement));
+
+        if (!result) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+
+        memset (result, 0, sizeof (CRStatement));
+        result->type = AT_IMPORT_RULE_STMT;
+
+        result->kind.import_rule = g_try_malloc (sizeof (CRAtImportRule));
+
+        if (!result->kind.import_rule) {
+                cr_utils_trace_info ("Out of memory");
+                g_free (result);
+                return NULL;
+        }
+
+        memset (result->kind.import_rule, 0, sizeof (CRAtImportRule));
+        result->kind.import_rule->url = a_url;
+        result->kind.import_rule->media_list = a_media_list;
+        result->kind.import_rule->sheet = a_imported_sheet;
+        if (a_container_sheet)
+                cr_statement_set_parent_sheet (result, a_container_sheet);
+
+        return result;
+}
+
+/**
+ * cr_statement_at_import_rule_parse_from_buf:
+ *
+ *@a_buf: the buffer to parse.
+ *@a_encoding: the encoding of a_buf.
+ *
+ *Parses a buffer that contains an "\@import" rule and
+ *instanciate a #CRStatement of type AT_IMPORT_RULE_STMT
+ *
+ *Returns the newly built instance of #CRStatement in case of 
+ *a successful parsing, NULL otherwise.
+ */
+CRStatement *
+cr_statement_at_import_rule_parse_from_buf (const guchar * a_buf,
+                                            enum CREncoding a_encoding)
+{
+        enum CRStatus status = CR_OK;
+        CRParser *parser = NULL;
+        CRStatement *result = NULL;
+        GList *media_list = NULL;
+        CRString *import_string = NULL;
+        CRParsingLocation location = {0} ;
+
+        parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
+                                         a_encoding, FALSE);
+        if (!parser) {
+                cr_utils_trace_info ("Instantiation of parser failed.");
+                goto cleanup;
+        }
+
+        status = cr_parser_try_to_skip_spaces_and_comments (parser);
+        if (status != CR_OK)
+                goto cleanup;
+
+        status = cr_parser_parse_import (parser,
+                                         &media_list, 
+                                         &import_string,
+                                         &location);
+        if (status != CR_OK || !import_string)
+                goto cleanup;
+
+        result = cr_statement_new_at_import_rule (NULL, import_string,
+                                                  media_list, NULL);
+        if (result) {
+                cr_parsing_location_copy (&result->location,
+                                          &location) ;
+                import_string = NULL;
+                media_list = NULL;
+        }
+
+ cleanup:
+        if (parser) {
+                cr_parser_destroy (parser);
+                parser = NULL;
+        }
+        if (media_list) {
+                for (; media_list;
+                     media_list = g_list_next (media_list)) {
+                        if (media_list->data) {
+                                cr_string_destroy ((CRString*)media_list->data);
+                                media_list->data = NULL;
+                        }
+                }
+                g_list_free (media_list);
+                media_list = NULL;
+        }
+        if (import_string) {
+                cr_string_destroy (import_string);
+                import_string = NULL;
+        }
+
+        return result;
+}
+
+/**
+ * cr_statement_new_at_page_rule:
+ *
+ *@a_decl_list: a list of instances of #CRDeclarations
+ *which is actually the list of declarations that applies to
+ *this page rule.
+ *@a_selector: the page rule selector.
+ *
+ *Creates a new instance of #CRStatement of type
+ *#CRAtPageRule.
+ *
+ *Returns the newly built instance of #CRStatement or NULL
+ *in case of error.
+ */
+CRStatement *
+cr_statement_new_at_page_rule (CRStyleSheet * a_sheet,
+                               CRDeclaration * a_decl_list,
+                               CRString * a_name, CRString * a_pseudo)
+{
+        CRStatement *result = NULL;
+
+        result = g_try_malloc (sizeof (CRStatement));
+
+        if (!result) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+
+        memset (result, 0, sizeof (CRStatement));
+        result->type = AT_PAGE_RULE_STMT;
+
+        result->kind.page_rule = g_try_malloc (sizeof (CRAtPageRule));
+
+        if (!result->kind.page_rule) {
+                cr_utils_trace_info ("Out of memory");
+                g_free (result);
+                return NULL;
+        }
+
+        memset (result->kind.page_rule, 0, sizeof (CRAtPageRule));
+        if (a_decl_list) {
+                result->kind.page_rule->decl_list = a_decl_list;
+                cr_declaration_ref (a_decl_list);
+        }
+        result->kind.page_rule->name = a_name;
+        result->kind.page_rule->pseudo = a_pseudo;
+        if (a_sheet)
+                cr_statement_set_parent_sheet (result, a_sheet);
+
+        return result;
+}
+
+/**
+ * cr_statement_at_page_rule_parse_from_buf:
+ *
+ *@a_buf: the character buffer to parse.
+ *@a_encoding: the character encoding of a_buf.
+ *
+ *Parses a buffer that contains an "\@page" production and,
+ *if the parsing succeeds, builds the page statement.
+ *
+ *Returns the newly built at page statement in case of successful parsing,
+ *NULL otherwise.
+ */
+CRStatement *
+cr_statement_at_page_rule_parse_from_buf (const guchar * a_buf,
+                                          enum CREncoding a_encoding)
+{
+        enum CRStatus status = CR_OK;
+        CRParser *parser = NULL;
+        CRDocHandler *sac_handler = NULL;
+        CRStatement *result = NULL;
+        CRStatement **resultptr = NULL;
+
+        g_return_val_if_fail (a_buf, NULL);
+
+        parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
+                                         a_encoding, FALSE);
+        if (!parser) {
+                cr_utils_trace_info ("Instantiation of the parser failed.");
+                goto cleanup;
+        }
+
+        sac_handler = cr_doc_handler_new ();
+        if (!sac_handler) {
+                cr_utils_trace_info
+                        ("Instantiation of the sac handler failed.");
+                goto cleanup;
+        }
+
+        sac_handler->start_page = parse_page_start_page_cb;
+        sac_handler->property = parse_page_property_cb;
+        sac_handler->end_page = parse_page_end_page_cb;
+        sac_handler->unrecoverable_error = parse_page_unrecoverable_error_cb;
+
+        status = cr_parser_set_sac_handler (parser, sac_handler);
+        if (status != CR_OK)
+                goto cleanup;
+
+        /*Now, invoke the parser to parse the "@page production" */
+        cr_parser_try_to_skip_spaces_and_comments (parser);
+        if (status != CR_OK)
+                goto cleanup;
+        status = cr_parser_parse_page (parser);
+        if (status != CR_OK)
+                goto cleanup;
+
+	resultptr = &result;
+        status = cr_doc_handler_get_result (sac_handler,
+                                            (gpointer *) resultptr);
+
+      cleanup:
+
+        if (parser) {
+                cr_parser_destroy (parser);
+                parser = NULL;
+                sac_handler = NULL ;
+        }
+        if (sac_handler) {
+                cr_doc_handler_unref (sac_handler);
+                sac_handler = NULL;
+        }
+        return result;
+}
+
+/**
+ * cr_statement_new_at_charset_rule:
+ *
+ *@a_charset: the string representing the charset.
+ *Note that the newly built instance of #CRStatement becomes
+ *the owner of a_charset. The caller must not free a_charset !!!.
+ *
+ *Creates a new instance of #CRStatement of type
+ *#CRAtCharsetRule.
+ *
+ *Returns the newly built instance of #CRStatement or NULL
+ *if an error arises.
+ */
+CRStatement *
+cr_statement_new_at_charset_rule (CRStyleSheet * a_sheet, 
+                                  CRString * a_charset)
+{
+        CRStatement *result = NULL;
+
+        g_return_val_if_fail (a_charset, NULL);
+
+        result = g_try_malloc (sizeof (CRStatement));
+
+        if (!result) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+
+        memset (result, 0, sizeof (CRStatement));
+        result->type = AT_CHARSET_RULE_STMT;
+
+        result->kind.charset_rule = g_try_malloc (sizeof (CRAtCharsetRule));
+
+        if (!result->kind.charset_rule) {
+                cr_utils_trace_info ("Out of memory");
+                g_free (result);
+                return NULL;
+        }
+        memset (result->kind.charset_rule, 0, sizeof (CRAtCharsetRule));
+        result->kind.charset_rule->charset = a_charset;
+        cr_statement_set_parent_sheet (result, a_sheet);
+
+        return result;
+}
+
+/**
+ * cr_statement_at_charset_rule_parse_from_buf:
+ *
+ *@a_buf: the buffer to parse.
+ *@a_encoding: the character encoding of the buffer.
+ *
+ *Parses a buffer that contains an '\@charset' rule and
+ *creates an instance of #CRStatement of type AT_CHARSET_RULE_STMT.
+ *
+ *Returns the newly built instance of #CRStatement.
+ */
+CRStatement *
+cr_statement_at_charset_rule_parse_from_buf (const guchar * a_buf,
+                                             enum CREncoding a_encoding)
+{
+        enum CRStatus status = CR_OK;
+        CRParser *parser = NULL;
+        CRStatement *result = NULL;
+        CRString *charset = NULL;
+
+        g_return_val_if_fail (a_buf, NULL);
+
+        parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
+                                         a_encoding, FALSE);
+        if (!parser) {
+                cr_utils_trace_info ("Instantiation of the parser failed.");
+                goto cleanup;
+        }
+
+        /*Now, invoke the parser to parse the "@charset production" */
+        cr_parser_try_to_skip_spaces_and_comments (parser);
+        if (status != CR_OK)
+                goto cleanup;
+        status = cr_parser_parse_charset (parser, &charset, NULL);
+        if (status != CR_OK || !charset)
+                goto cleanup;
+
+        result = cr_statement_new_at_charset_rule (NULL, charset);
+        if (result)
+                charset = NULL;
+
+      cleanup:
+
+        if (parser) {
+                cr_parser_destroy (parser);
+                parser = NULL;
+        }
+        if (charset) {
+                cr_string_destroy (charset);
+        }
+
+        return result;
+}
+
+/**
+ * cr_statement_new_at_font_face_rule:
+ *
+ *@a_font_decls: a list of instances of #CRDeclaration. Each declaration
+ *is actually a font declaration.
+ *
+ *Creates an instance of #CRStatement of type #CRAtFontFaceRule.
+ *
+ *Returns the newly built instance of #CRStatement.
+ */
+CRStatement *
+cr_statement_new_at_font_face_rule (CRStyleSheet * a_sheet,
+                                    CRDeclaration * a_font_decls)
+{
+        CRStatement *result = NULL;
+
+        result = g_try_malloc (sizeof (CRStatement));
+
+        if (!result) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+        memset (result, 0, sizeof (CRStatement));
+        result->type = AT_FONT_FACE_RULE_STMT;
+
+        result->kind.font_face_rule = g_try_malloc
+                (sizeof (CRAtFontFaceRule));
+
+        if (!result->kind.font_face_rule) {
+                cr_utils_trace_info ("Out of memory");
+                g_free (result);
+                return NULL;
+        }
+        memset (result->kind.font_face_rule, 0, sizeof (CRAtFontFaceRule));
+
+        result->kind.font_face_rule->decl_list = a_font_decls;
+        if (a_sheet)
+                cr_statement_set_parent_sheet (result, a_sheet);
+
+        return result;
+}
+
+/**
+ * cr_statement_font_face_rule_parse_from_buf:
+ *
+ *
+ *@a_buf: the buffer to parse.
+ *@a_encoding: the character encoding of a_buf.
+ *
+ *Parses a buffer that contains an "\@font-face" rule and builds
+ *an instance of #CRStatement of type AT_FONT_FACE_RULE_STMT out of it.
+ *
+ *Returns the newly built instance of #CRStatement in case of successufull
+ *parsing, NULL otherwise.
+ */
+CRStatement *
+cr_statement_font_face_rule_parse_from_buf (const guchar * a_buf,
+                                            enum CREncoding a_encoding)
+{
+        CRStatement *result = NULL;
+        CRStatement **resultptr = NULL;
+        CRParser *parser = NULL;
+        CRDocHandler *sac_handler = NULL;
+        enum CRStatus status = CR_OK;
+
+        parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
+                                         a_encoding, FALSE);
+        if (!parser)
+                goto cleanup;
+
+        sac_handler = cr_doc_handler_new ();
+        if (!sac_handler)
+                goto cleanup;
+
+        /*
+         *set sac callbacks here
+         */
+        sac_handler->start_font_face = parse_font_face_start_font_face_cb;
+        sac_handler->property = parse_font_face_property_cb;
+        sac_handler->end_font_face = parse_font_face_end_font_face_cb;
+        sac_handler->unrecoverable_error =
+                parse_font_face_unrecoverable_error_cb;
+
+        status = cr_parser_set_sac_handler (parser, sac_handler);
+        if (status != CR_OK)
+                goto cleanup;
+
+        /*
+         *cleanup spaces of comment that may be there before the real
+         *"@font-face" thing.
+         */
+        status = cr_parser_try_to_skip_spaces_and_comments (parser);
+        if (status != CR_OK)
+                goto cleanup;
+
+        status = cr_parser_parse_font_face (parser);
+        if (status != CR_OK)
+                goto cleanup;
+
+	resultptr = &result;
+        status = cr_doc_handler_get_result (sac_handler,
+                                            (gpointer *) resultptr);
+        if (status != CR_OK || !result)
+                goto cleanup;
+
+      cleanup:
+        if (parser) {
+                cr_parser_destroy (parser);
+                parser = NULL;
+                sac_handler = NULL ;
+        }
+        if (sac_handler) {
+                cr_doc_handler_unref (sac_handler);
+                sac_handler = NULL;
+        }
+        return result;
+}
+
+/**
+ * cr_statement_set_parent_sheet:
+ *
+ *@a_this: the current instance of #CRStatement.
+ *@a_sheet: the sheet that contains the current statement.
+ *
+ *Sets the container stylesheet.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_set_parent_sheet (CRStatement * a_this, CRStyleSheet * a_sheet)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+        a_this->parent_sheet = a_sheet;
+        return CR_OK;
+}
+
+/**
+ * cr_statement_get_parent_sheet:
+ *
+ *@a_this: the current #CRStatement.
+ *@a_sheet: out parameter. A pointer to the sheets that
+ *
+ *Gets the sheets that contains the current statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_get_parent_sheet (CRStatement * a_this, CRStyleSheet ** a_sheet)
+{
+        g_return_val_if_fail (a_this && a_sheet, CR_BAD_PARAM_ERROR);
+        *a_sheet = a_this->parent_sheet;
+        return CR_OK;
+}
+
+/**
+ * cr_statement_append:
+ *
+ *@a_this: the current instance of the statement list.
+ *@a_new: a_new the new instance of #CRStatement to append.
+ *
+ *Appends a new statement to the statement list.
+ *
+ *Returns the new list statement list, or NULL in cas of failure.
+ */
+CRStatement *
+cr_statement_append (CRStatement * a_this, CRStatement * a_new)
+{
+        CRStatement *cur = NULL;
+
+        g_return_val_if_fail (a_new, NULL);
+
+        if (!a_this) {
+                return a_new;
+        }
+
+        /*walk forward in the current list to find the tail list element */
+        for (cur = a_this; cur && cur->next; cur = cur->next) ;
+
+        cur->next = a_new;
+        a_new->prev = cur;
+
+        return a_this;
+}
+
+/**
+ * cr_statement_prepend:
+ *
+ *@a_this: the current instance of #CRStatement.
+ *@a_new: the new statement to prepend.
+ *
+ *Prepends the an instance of #CRStatement to
+ *the current statement list.
+ *
+ *Returns the new list with the new statement prepended,
+ *or NULL in case of an error.
+ */
+CRStatement *
+cr_statement_prepend (CRStatement * a_this, CRStatement * a_new)
+{
+        CRStatement *cur = NULL;
+
+        g_return_val_if_fail (a_new, NULL);
+
+        if (!a_this)
+                return a_new;
+
+        a_new->next = a_this;
+        a_this->prev = a_new;
+
+        /*walk backward in the prepended list to find the head list element */
+        for (cur = a_new; cur && cur->prev; cur = cur->prev) ;
+
+        return cur;
+}
+
+/**
+ * cr_statement_unlink:
+ *
+ *@a_this: the current statements list.
+ *@a_to_unlink: the statement to unlink from the list.
+ *
+ *Unlinks a statement from the statements list.
+ *
+ *Returns the new list where a_to_unlink has been unlinked
+ *from, or NULL in case of error.
+ */
+CRStatement *
+cr_statement_unlink (CRStatement * a_stmt)
+{
+        CRStatement *result = a_stmt;
+
+        g_return_val_if_fail (result, NULL);
+
+        /**
+         *Some sanity checks first
+         */
+        if (a_stmt->next) {
+                g_return_val_if_fail (a_stmt->next->prev == a_stmt, NULL);
+        }
+        if (a_stmt->prev) {
+                g_return_val_if_fail (a_stmt->prev->next == a_stmt, NULL);
+        }
+
+        /**
+         *Now, the real unlinking job.
+         */
+        if (a_stmt->next) {
+                a_stmt->next->prev = a_stmt->prev;
+        }
+        if (a_stmt->prev) {
+                a_stmt->prev->next = a_stmt->next;
+        }
+
+        if (a_stmt->parent_sheet
+            && a_stmt->parent_sheet->statements == a_stmt) {
+                a_stmt->parent_sheet->statements =
+                        a_stmt->parent_sheet->statements->next;
+        }
+
+        a_stmt->next = NULL;
+        a_stmt->prev = NULL;
+        a_stmt->parent_sheet = NULL;
+
+        return result;
+}
+
+/**
+ * cr_statement_nr_rules:
+ *
+ *@a_this: the current instance of #CRStatement.
+ *
+ *Gets the number of rules in the statement list;
+ *
+ *Returns number of rules in the statement list.
+ */
+gint
+cr_statement_nr_rules (CRStatement const * a_this)
+{
+        CRStatement const *cur = NULL;
+        int nr = 0;
+
+        g_return_val_if_fail (a_this, -1);
+
+        for (cur = a_this; cur; cur = cur->next)
+                nr++;
+        return nr;
+}
+
+/**
+ * cr_statement_get_from_list:
+ *
+ *@a_this: the current instance of #CRStatement.
+ *@itemnr: the index into the statement list.
+ *
+ *Use an index to get a CRStatement from the statement list.
+ *
+ *Returns CRStatement at position itemnr, if itemnr > number of statements - 1,
+ *it will return NULL.
+ */
+CRStatement *
+cr_statement_get_from_list (CRStatement * a_this, int itemnr)
+{
+        CRStatement *cur = NULL;
+        int nr = 0;
+
+        g_return_val_if_fail (a_this, NULL);
+
+        for (cur = a_this; cur; cur = cur->next)
+                if (nr++ == itemnr)
+                        return cur;
+        return NULL;
+}
+
+/**
+ * cr_statement_ruleset_set_sel_list:
+ *
+ *@a_this: the current ruleset statement.
+ *@a_sel_list: the selector list to set. Note
+ *that this function increments the ref count of a_sel_list.
+ *The sel list will be destroyed at the destruction of the
+ *current instance of #CRStatement.
+ *
+ *Sets a selector list to a ruleset statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_ruleset_set_sel_list (CRStatement * a_this,
+                                   CRSelector * a_sel_list)
+{
+        g_return_val_if_fail (a_this && a_this->type == RULESET_STMT,
+                              CR_BAD_PARAM_ERROR);
+
+        if (a_this->kind.ruleset->sel_list)
+                cr_selector_unref (a_this->kind.ruleset->sel_list);
+
+        a_this->kind.ruleset->sel_list = a_sel_list;
+
+        if (a_sel_list)
+                cr_selector_ref (a_sel_list);
+
+        return CR_OK;
+}
+
+/**
+ * cr_statement_ruleset_get_declarations:
+ *
+ *@a_this: the current instance of #CRStatement.
+ *@a_decl_list: out parameter. A pointer to the the returned
+ *list of declaration. Must not be NULL.
+ *
+ *Gets a pointer to the list of declaration contained
+ *in the ruleset statement.
+ *
+ *Returns CR_OK upon successful completion, an error code if something
+ *bad happened.
+ */
+enum CRStatus
+cr_statement_ruleset_get_declarations (CRStatement * a_this,
+                                       CRDeclaration ** a_decl_list)
+{
+        g_return_val_if_fail (a_this
+                              && a_this->type == RULESET_STMT
+                              && a_this->kind.ruleset
+                              && a_decl_list, CR_BAD_PARAM_ERROR);
+
+        *a_decl_list = a_this->kind.ruleset->decl_list;
+
+        return CR_OK;
+}
+
+/**
+ * cr_statement_ruleset_get_sel_list:
+ *
+ *@a_this: the current ruleset statement.
+ *@a_list: out parameter. The returned selector list,
+ *if and only if the function returned CR_OK.
+ *
+ *Gets a pointer to the selector list contained in
+ *the current ruleset statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_ruleset_get_sel_list (CRStatement const * a_this, CRSelector ** a_list)
+{
+        g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
+                              && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
+
+        *a_list = a_this->kind.ruleset->sel_list;
+
+        return CR_OK;
+}
+
+/**
+ * cr_statement_ruleset_set_decl_list:
+ *
+ *@a_this: the current ruleset statement.
+ *@a_list: the declaration list to be added to the current
+ *ruleset statement.
+ *
+ *Sets a declaration list to the current ruleset statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_ruleset_set_decl_list (CRStatement * a_this,
+                                    CRDeclaration * a_list)
+{
+        g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
+                              && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
+
+        if (a_this->kind.ruleset->decl_list == a_list)
+                return CR_OK;
+
+        if (a_this->kind.ruleset->sel_list) {
+                cr_declaration_destroy (a_this->kind.ruleset->decl_list);
+        }
+
+        a_this->kind.ruleset->sel_list = NULL;
+
+        return CR_OK;
+}
+
+/**
+ * cr_statement_ruleset_append_decl2:
+ *
+ *@a_this: the current statement.
+ *@a_prop: the property of the declaration.
+ *@a_value: the value of the declaration.
+ *
+ *Appends a declaration to the current ruleset statement.
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_statement_ruleset_append_decl2 (CRStatement * a_this,
+                                   CRString * a_prop, 
+                                   CRTerm * a_value)
+{
+        CRDeclaration *new_decls = NULL;
+
+        g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
+                              && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
+
+        new_decls = cr_declaration_append2
+                (a_this->kind.ruleset->decl_list, 
+                 a_prop, a_value);
+        g_return_val_if_fail (new_decls, CR_ERROR);
+        a_this->kind.ruleset->decl_list = new_decls;
+
+        return CR_OK;
+}
+
+/**
+ * cr_statement_ruleset_append_decl:
+ *
+ *Appends a declaration to the current statement.
+ *
+ *@a_this: the current statement.
+ *@a_declaration: the declaration to append.
+ *
+ *Returns CR_OK upon sucessful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_statement_ruleset_append_decl (CRStatement * a_this,
+                                  CRDeclaration * a_decl)
+{
+        CRDeclaration *new_decls = NULL;
+
+        g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
+                              && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
+
+        new_decls = cr_declaration_append
+                (a_this->kind.ruleset->decl_list, a_decl);
+        g_return_val_if_fail (new_decls, CR_ERROR);
+        a_this->kind.ruleset->decl_list = new_decls;
+
+        return CR_OK;
+}
+
+/**
+ * cr_statement_at_import_rule_set_imported_sheet:
+ *
+ *Sets a stylesheet to the current \@import rule.
+ *@a_this: the current \@import rule.
+ *@a_sheet: the stylesheet. The stylesheet is owned
+ *by the current instance of #CRStatement, that is, the 
+ *stylesheet will be destroyed when the current instance
+ *of #CRStatement is destroyed.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_import_rule_set_imported_sheet (CRStatement * a_this,
+                                                CRStyleSheet * a_sheet)
+{
+        g_return_val_if_fail (a_this
+                              && a_this->type == AT_IMPORT_RULE_STMT
+                              && a_this->kind.import_rule,
+                              CR_BAD_PARAM_ERROR);
+
+        a_this->kind.import_rule->sheet = a_sheet;
+
+        return CR_OK;
+}
+
+/**
+ * cr_statement_at_import_rule_get_imported_sheet:
+ *
+ *@a_this: the current \@import rule statement.
+ *@a_sheet: out parameter. The returned stylesheet if and
+ *only if the function returns CR_OK.
+ *
+ *Gets the stylesheet contained by the \@import rule statement.
+ *Returns CR_OK upon sucessful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_import_rule_get_imported_sheet (CRStatement * a_this,
+                                                CRStyleSheet ** a_sheet)
+{
+        g_return_val_if_fail (a_this
+                              && a_this->type == AT_IMPORT_RULE_STMT
+                              && a_this->kind.import_rule,
+                              CR_BAD_PARAM_ERROR);
+        *a_sheet = a_this->kind.import_rule->sheet;
+        return CR_OK;
+
+}
+
+/**
+ * cr_statement_at_import_rule_set_url:
+ *
+ *@a_this: the current \@import rule statement.
+ *@a_url: the url to set.
+ *
+ *Sets an url to the current \@import rule statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_import_rule_set_url (CRStatement * a_this, 
+                                     CRString * a_url)
+{
+        g_return_val_if_fail (a_this
+                              && a_this->type == AT_IMPORT_RULE_STMT
+                              && a_this->kind.import_rule,
+                              CR_BAD_PARAM_ERROR);
+
+        if (a_this->kind.import_rule->url) {
+                cr_string_destroy (a_this->kind.import_rule->url);
+        }
+
+        a_this->kind.import_rule->url = a_url;
+
+        return CR_OK;
+}
+
+/**
+ * cr_statement_at_import_rule_get_url:
+ *
+ *@a_this: the current \@import rule statement.
+ *@a_url: out parameter. The returned url if
+ *and only if the function returned CR_OK.
+ *
+ *Gets the url of the \@import rule statement.
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_import_rule_get_url (CRStatement const * a_this,
+                                     CRString ** a_url)
+{
+        g_return_val_if_fail (a_this
+                              && a_this->type == AT_IMPORT_RULE_STMT
+                              && a_this->kind.import_rule,
+                              CR_BAD_PARAM_ERROR);
+
+        *a_url = a_this->kind.import_rule->url;
+
+        return CR_OK;
+}
+
+/**
+ * cr_statement_at_media_nr_rules:
+ *
+ *@a_this: the current instance of #CRStatement.
+ *
+ *Returns the number of rules in the media rule;
+ */
+int
+cr_statement_at_media_nr_rules (CRStatement const * a_this)
+{
+        g_return_val_if_fail (a_this
+                              && a_this->type == AT_MEDIA_RULE_STMT
+                              && a_this->kind.media_rule, CR_BAD_PARAM_ERROR);
+
+        return cr_statement_nr_rules (a_this->kind.media_rule->rulesets);
+}
+
+/**
+ * cr_statement_at_media_get_from_list:
+ *
+ *@a_this: the current instance of #CRStatement.
+ *@itemnr: the index into the media rule list of rules.
+ *
+ *Use an index to get a CRStatement from the media rule list of rules.
+ *
+ *Returns CRStatement at position itemnr, if itemnr > number of rules - 1,
+ *it will return NULL.
+ */
+CRStatement *
+cr_statement_at_media_get_from_list (CRStatement * a_this, int itemnr)
+{
+        g_return_val_if_fail (a_this
+                              && a_this->type == AT_MEDIA_RULE_STMT
+                              && a_this->kind.media_rule, NULL);
+
+        return cr_statement_get_from_list (a_this->kind.media_rule->rulesets,
+                                           itemnr);
+}
+
+/**
+ * cr_statement_at_page_rule_set_declarations:
+ *
+ *@a_this: the current \@page rule statement.
+ *@a_decl_list: the declaration list to add. Will be freed
+ *by the current instance of #CRStatement when it is destroyed.
+ *
+ *Sets a declaration list to the current \@page rule statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_page_rule_set_declarations (CRStatement * a_this,
+                                            CRDeclaration * a_decl_list)
+{
+        g_return_val_if_fail (a_this
+                              && a_this->type == AT_PAGE_RULE_STMT
+                              && a_this->kind.page_rule, CR_BAD_PARAM_ERROR);
+
+        if (a_this->kind.page_rule->decl_list) {
+                cr_declaration_unref (a_this->kind.page_rule->decl_list);
+        }
+
+        a_this->kind.page_rule->decl_list = a_decl_list;
+
+        if (a_decl_list) {
+                cr_declaration_ref (a_decl_list);
+        }
+
+        return CR_OK;
+}
+
+/**
+ * cr_statement_at_page_rule_get_declarations:
+ *
+ *@a_this: the current \@page rule statement.
+ *@a_decl_list: out parameter. The returned declaration list.
+ *
+ *Gets the declaration list associated to the current \@page rule
+ *statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_page_rule_get_declarations (CRStatement * a_this,
+                                            CRDeclaration ** a_decl_list)
+{
+        g_return_val_if_fail (a_this
+                              && a_this->type == AT_PAGE_RULE_STMT
+                              && a_this->kind.page_rule, CR_BAD_PARAM_ERROR);
+
+        *a_decl_list = a_this->kind.page_rule->decl_list;
+
+        return CR_OK;
+}
+
+/**
+ * cr_statement_at_charset_rule_set_charset:
+ *
+ *
+ *@a_this: the current \@charset rule statement.
+ *@a_charset: the charset to set.
+ *
+ *Sets the charset of the current \@charset rule statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_charset_rule_set_charset (CRStatement * a_this,
+                                          CRString * a_charset)
+{
+        g_return_val_if_fail (a_this
+                              && a_this->type == AT_CHARSET_RULE_STMT
+                              && a_this->kind.charset_rule,
+                              CR_BAD_PARAM_ERROR);
+
+        if (a_this->kind.charset_rule->charset) {
+                cr_string_destroy (a_this->kind.charset_rule->charset);
+        }
+        a_this->kind.charset_rule->charset = a_charset;
+        return CR_OK;
+}
+
+/**
+ * cr_statement_at_charset_rule_get_charset:
+ *@a_this: the current \@charset rule statement.
+ *@a_charset: out parameter. The returned charset string if
+ *and only if the function returned CR_OK.
+ *
+ *Gets the charset string associated to the current
+ *\@charset rule statement.
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_charset_rule_get_charset (CRStatement const * a_this,
+                                          CRString ** a_charset)
+{
+        g_return_val_if_fail (a_this
+                              && a_this->type == AT_CHARSET_RULE_STMT
+                              && a_this->kind.charset_rule,
+                              CR_BAD_PARAM_ERROR);
+
+        *a_charset = a_this->kind.charset_rule->charset;
+
+        return CR_OK;
+}
+
+/**
+ * cr_statement_at_font_face_rule_set_decls:
+ *
+ *@a_this: the current \@font-face rule statement.
+ *@a_decls: the declarations list to set.
+ *
+ *Sets a declaration list to the current \@font-face rule statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_font_face_rule_set_decls (CRStatement * a_this,
+                                          CRDeclaration * a_decls)
+{
+        g_return_val_if_fail (a_this
+                              && a_this->type == AT_FONT_FACE_RULE_STMT
+                              && a_this->kind.font_face_rule,
+                              CR_BAD_PARAM_ERROR);
+
+        if (a_this->kind.font_face_rule->decl_list) {
+                cr_declaration_unref (a_this->kind.font_face_rule->decl_list);
+        }
+
+        a_this->kind.font_face_rule->decl_list = a_decls;
+        cr_declaration_ref (a_decls);
+
+        return CR_OK;
+}
+
+/**
+ * cr_statement_at_font_face_rule_get_decls:
+ *
+ *@a_this: the current \@font-face rule statement.
+ *@a_decls: out parameter. The returned declaration list if
+ *and only if this function returns CR_OK.
+ *
+ *Gets the declaration list associated to the current instance
+ *of \@font-face rule statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_font_face_rule_get_decls (CRStatement * a_this,
+                                          CRDeclaration ** a_decls)
+{
+        g_return_val_if_fail (a_this
+                              && a_this->type == AT_FONT_FACE_RULE_STMT
+                              && a_this->kind.font_face_rule,
+                              CR_BAD_PARAM_ERROR);
+
+        *a_decls = a_this->kind.font_face_rule->decl_list;
+
+        return CR_OK;
+}
+
+/**
+ * cr_statement_at_font_face_rule_add_decl:
+ *
+ *@a_this: the current \@font-face rule statement.
+ *@a_prop: the property of the declaration.
+ *@a_value: the value of the declaration.
+ *
+ *Adds a declaration to the current \@font-face rule
+ *statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_font_face_rule_add_decl (CRStatement * a_this,
+                                         CRString * a_prop, CRTerm * a_value)
+{
+        CRDeclaration *decls = NULL;
+
+        g_return_val_if_fail (a_this
+                              && a_this->type == AT_FONT_FACE_RULE_STMT
+                              && a_this->kind.font_face_rule,
+                              CR_BAD_PARAM_ERROR);
+
+        decls = cr_declaration_append2
+                (a_this->kind.font_face_rule->decl_list, 
+                 a_prop, a_value);
+
+        g_return_val_if_fail (decls, CR_ERROR);
+
+        if (a_this->kind.font_face_rule->decl_list == NULL)
+                cr_declaration_ref (decls);
+
+        a_this->kind.font_face_rule->decl_list = decls;
+
+        return CR_OK;
+}
+
+
+/**
+ * cr_statement_to_string:
+ *
+ *@a_this: the current statement to serialize
+ *@a_indent: the number of white space of indentation.
+ *
+ *Serializes a css statement into a string
+ *
+ *Returns the serialized statement. Must be freed by the caller
+ *using g_free().
+ */
+gchar *
+cr_statement_to_string (CRStatement const * a_this, gulong a_indent)
+{
+        gchar *str = NULL ;
+
+        if (!a_this)
+                return NULL;
+
+        switch (a_this->type) {
+        case RULESET_STMT:
+                str = cr_statement_ruleset_to_string 
+                        (a_this, a_indent);
+                break;
+
+        case AT_FONT_FACE_RULE_STMT:
+                str = cr_statement_font_face_rule_to_string 
+                        (a_this, a_indent) ;
+                break;
+
+        case AT_CHARSET_RULE_STMT:
+                str = cr_statement_charset_to_string
+                        (a_this, a_indent);                
+                break;
+
+        case AT_PAGE_RULE_STMT:
+                str = cr_statement_at_page_rule_to_string
+                        (a_this, a_indent);
+                break;
+
+        case AT_MEDIA_RULE_STMT:
+                str = cr_statement_media_rule_to_string
+                        (a_this, a_indent);
+                break;
+
+        case AT_IMPORT_RULE_STMT:
+                str = cr_statement_import_rule_to_string
+                        (a_this, a_indent);
+                break;
+
+        default:
+                cr_utils_trace_info ("Statement unrecognized");
+                break;
+        }
+        return str ;
+}
+
+gchar*
+cr_statement_list_to_string (CRStatement const *a_this, gulong a_indent)
+{
+        CRStatement const *cur_stmt = NULL ;
+        GString *stringue = NULL ;
+        gchar *str = NULL ;
+
+        g_return_val_if_fail (a_this, NULL) ;
+
+        stringue = g_string_new (NULL) ;
+        if (!stringue) {
+                cr_utils_trace_info ("Out of memory") ;
+                return NULL ;
+        }
+        for (cur_stmt = a_this ; cur_stmt;
+             cur_stmt = cur_stmt->next) {
+                str = cr_statement_to_string (cur_stmt, a_indent) ;
+                if (str) {
+                        if (!cur_stmt->prev) {
+                                g_string_append (stringue, str) ;
+                        } else {
+                                g_string_append_printf 
+                                        (stringue, "\n%s", str) ;
+                        }
+                        g_free (str) ;
+                        str = NULL ;
+                }                
+        }
+        str = stringue->str ;
+        g_string_free (stringue, FALSE) ;
+        return str ;
+}
+
+/**
+ * cr_statement_dump:
+ *
+ *@a_this: the current css2 statement.
+ *@a_fp: the destination file pointer.
+ *@a_indent: the number of white space indentation characters.
+ *
+ *Dumps the css2 statement to a file.
+ */
+void
+cr_statement_dump (CRStatement const * a_this, FILE * a_fp, gulong a_indent)
+{
+        gchar *str = NULL ;
+
+        if (!a_this)
+                return;
+
+        str = cr_statement_to_string (a_this, a_indent) ;
+        if (str) {
+                fprintf (a_fp, "%s",str) ;
+                g_free (str) ;
+                str = NULL ;
+        }
+}
+
+/**
+ * cr_statement_dump_ruleset:
+ *
+ *@a_this: the current instance of #CRStatement.
+ *@a_fp: the destination file pointer.
+ *@a_indent: the number of indentation white spaces to add.
+ *
+ *Dumps a ruleset statement to a file.
+ */
+void
+cr_statement_dump_ruleset (CRStatement const * a_this, FILE * a_fp, glong a_indent)
+{
+        gchar *str = NULL;
+
+        g_return_if_fail (a_fp && a_this);
+        str = cr_statement_ruleset_to_string (a_this, a_indent);
+        if (str) {
+                fprintf (a_fp, "%s", str);
+                g_free (str);
+                str = NULL;
+        }
+}
+
+/**
+ * cr_statement_dump_font_face_rule:
+ *
+ *@a_this: the current instance of font face rule statement.
+ *@a_fp: the destination file pointer.
+ *@a_indent: the number of white space indentation.
+ *
+ *Dumps a font face rule statement to a file.
+ */
+void
+cr_statement_dump_font_face_rule (CRStatement const * a_this, FILE * a_fp,
+                                  glong a_indent)
+{
+        gchar *str = NULL ;
+        g_return_if_fail (a_this 
+                          && a_this->type == AT_FONT_FACE_RULE_STMT);
+
+        str = cr_statement_font_face_rule_to_string (a_this,
+                                                     a_indent) ;
+        if (str) {
+                fprintf (a_fp, "%s", str) ;
+                g_free (str) ;
+                str = NULL ;
+        }
+}
+
+/**
+ * cr_statement_dump_charset:
+ *
+ *@a_this: the current instance of the \@charset rule statement.
+ *@a_fp: the destination file pointer.
+ *@a_indent: the number of indentation white spaces.
+ *
+ *Dumps an \@charset rule statement to a file.
+ */
+void
+cr_statement_dump_charset (CRStatement const * a_this, FILE * a_fp, gulong a_indent)
+{
+        gchar *str = NULL;
+
+        g_return_if_fail (a_this && a_this->type == AT_CHARSET_RULE_STMT);
+
+        str = cr_statement_charset_to_string (a_this,
+                                              a_indent) ;
+        if (str) {
+                fprintf (a_fp, "%s", str) ;
+                g_free (str) ;
+                str = NULL ;
+        }
+}
+
+
+/**
+ * cr_statement_dump_page:
+ *
+ *@a_this: the statement to dump on stdout.
+ *@a_fp: the destination file pointer.
+ *@a_indent: the number of indentation white spaces.
+ *
+ *Dumps an \@page rule statement on stdout.
+ */
+void
+cr_statement_dump_page (CRStatement const * a_this, FILE * a_fp, gulong a_indent)
+{
+        gchar *str = NULL;
+
+        g_return_if_fail (a_this
+                          && a_this->type == AT_PAGE_RULE_STMT
+                          && a_this->kind.page_rule);
+
+        str = cr_statement_at_page_rule_to_string (a_this, a_indent) ;
+        if (str) {
+                fprintf (a_fp, "%s", str);
+                g_free (str) ;
+                str = NULL ; 
+        }
+}
+
+
+/**
+ * cr_statement_dump_media_rule:
+ *
+ *@a_this: the statement to dump.
+ *@a_fp: the destination file pointer
+ *@a_indent: the number of white spaces indentation.
+ *
+ *Dumps an \@media rule statement to a file.
+ */
+void
+cr_statement_dump_media_rule (CRStatement const * a_this,
+                              FILE * a_fp,
+                              gulong a_indent)
+{
+        gchar *str = NULL ;
+        g_return_if_fail (a_this->type == AT_MEDIA_RULE_STMT);
+
+        str = cr_statement_media_rule_to_string (a_this, a_indent) ;
+        if (str) {
+                fprintf (a_fp, "%s", str) ;
+                g_free (str) ;
+                str = NULL ;
+        }
+}
+
+/**
+ * cr_statement_dump_import_rule:
+ *
+ *@a_fp: the destination file pointer.
+ *@a_indent: the number of white space indentations.
+ *
+ *Dumps an \@import rule statement to a file.
+ */
+void
+cr_statement_dump_import_rule (CRStatement const * a_this, FILE * a_fp,
+                               gulong a_indent)
+{
+        gchar *str = NULL ;
+        g_return_if_fail (a_this
+                          && a_this->type == AT_IMPORT_RULE_STMT
+                          && a_fp
+                          && a_this->kind.import_rule);
+
+        str = cr_statement_import_rule_to_string (a_this, a_indent) ;
+        if (str) {
+                fprintf (a_fp, "%s", str) ;
+                g_free (str) ;
+                str = NULL ;
+        }
+}
+
+/**
+ * cr_statement_destroy:
+ *
+ * @a_this: the current instance of #CRStatement.
+ *
+ *Destructor of #CRStatement.
+ */
+void
+cr_statement_destroy (CRStatement * a_this)
+{
+        CRStatement *cur = NULL;
+
+        g_return_if_fail (a_this);
+
+        /*go get the tail of the list */
+        for (cur = a_this; cur && cur->next; cur = cur->next) {
+                cr_statement_clear (cur);
+        }
+
+        if (cur)
+                cr_statement_clear (cur);
+
+        if (cur->prev == NULL) {
+                g_free (a_this);
+                return;
+        }
+
+        /*walk backward and free next element */
+        for (cur = cur->prev; cur && cur->prev; cur = cur->prev) {
+                if (cur->next) {
+                        g_free (cur->next);
+                        cur->next = NULL;
+                }
+        }
+
+        if (!cur)
+                return;
+
+        /*free the one remaining list */
+        if (cur->next) {
+                g_free (cur->next);
+                cur->next = NULL;
+        }
+
+        g_free (cur);
+        cur = NULL;
+}
diff --git a/src/st/croco/cr-statement.h b/src/st/croco/cr-statement.h
new file mode 100644
index 000000000..74a233055
--- /dev/null
+++ b/src/st/croco/cr-statement.h
@@ -0,0 +1,440 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ * 
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include <stdio.h>
+#include "cr-utils.h"
+#include "cr-term.h"
+#include "cr-selector.h"
+#include "cr-declaration.h"
+
+#ifndef __CR_STATEMENT_H__
+#define __CR_STATEMENT_H__
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *Declaration of the #CRStatement class.
+ */
+
+/*
+ *forward declaration of CRStyleSheet which is defined in
+ *cr-stylesheet.h
+ */
+
+struct _CRStatement ;
+
+/*
+ *typedef struct _CRStatement CRStatement ; 
+ *this is forward declared in 
+ *cr-declaration.h already.
+ */
+
+struct _CRAtMediaRule ;
+typedef struct _CRAtMediaRule CRAtMediaRule ;
+
+typedef struct _CRRuleSet CRRuleSet ;
+
+/**
+ *The abstraction of a css ruleset.
+ *A ruleset is made of a list of selectors,
+ *followed by a list of declarations.
+ */
+struct _CRRuleSet
+{
+	/**A list of instances of #CRSimpeSel*/
+	CRSelector *sel_list ;
+
+	/**A list of instances of #CRDeclaration*/
+	CRDeclaration *decl_list ;
+	
+	/**
+	 *The parent media rule, or NULL if
+	 *no parent media rule exists.
+	 */
+	CRStatement *parent_media_rule ;
+} ;
+
+/*
+ *a forward declaration of CRStylesheet.
+ *CRStylesheet is actually declared in
+ *cr-stylesheet.h
+ */
+struct _CRStyleSheet ;
+typedef struct _CRStyleSheet CRStyleSheet;
+
+
+/**The \@import rule abstraction.*/
+typedef struct _CRAtImportRule CRAtImportRule ;
+struct _CRAtImportRule
+{
+	/**the url of the import rule*/
+	CRString *url ;
+
+        GList *media_list ;
+
+	/**
+	 *the stylesheet fetched from the url, if any.
+	 *this is not "owned" by #CRAtImportRule which means
+	 *it is not destroyed by the destructor of #CRAtImportRule.
+	 */
+	CRStyleSheet * sheet;
+};
+
+
+/**abstraction of an \@media rule*/
+struct _CRAtMediaRule
+{
+	GList *media_list ;
+	CRStatement *rulesets ;	
+} ;
+
+
+typedef struct _CRAtPageRule CRAtPageRule ;
+/**The \@page rule abstraction*/
+struct _CRAtPageRule
+{
+	/**a list of instances of #CRDeclaration*/
+	CRDeclaration *decl_list ;
+
+	/**page selector. Is a pseudo selector*/
+	CRString *name ;
+	CRString *pseudo ;
+} ;
+
+/**The \@charset rule abstraction*/
+typedef struct _CRAtCharsetRule CRAtCharsetRule ;
+struct _CRAtCharsetRule
+{
+	CRString * charset ;
+};
+
+/**The abstaction of the \@font-face rule.*/
+typedef struct _CRAtFontFaceRule CRAtFontFaceRule ;
+struct _CRAtFontFaceRule
+{
+	/*a list of instanaces of #CRDeclaration*/
+	CRDeclaration *decl_list ;
+} ;
+
+
+/**
+ *The possible types of css2 statements.
+ */
+enum CRStatementType
+{
+	/**
+	 *A generic css at-rule
+	 *each unknown at-rule will
+	 *be of this type.
+	 */
+
+        /**A css at-rule*/
+	AT_RULE_STMT = 0,
+
+	/*A css ruleset*/
+	RULESET_STMT,
+
+	/**A css2 import rule*/
+	AT_IMPORT_RULE_STMT,
+
+	/**A css2 media rule*/
+	AT_MEDIA_RULE_STMT,
+
+	/**A css2 page rule*/
+	AT_PAGE_RULE_STMT,
+
+	/**A css2 charset rule*/
+	AT_CHARSET_RULE_STMT,
+
+	/**A css2 font face rule*/
+	AT_FONT_FACE_RULE_STMT
+} ;
+
+
+/**
+ *The abstraction of css statement as defined
+ *in the chapter 4 and appendix D.1 of the css2 spec.
+ *A statement is actually a double chained list of
+ *statements.A statement can be a ruleset, an \@import
+ *rule, an \@page rule etc ...
+ */
+struct _CRStatement
+{
+	/**
+	 *The type of the statement.
+	 */
+	enum CRStatementType type ;
+
+	union
+	{
+		CRRuleSet *ruleset ;
+		CRAtImportRule *import_rule ;
+		CRAtMediaRule *media_rule ;
+		CRAtPageRule *page_rule ;
+		CRAtCharsetRule *charset_rule ;
+		CRAtFontFaceRule *font_face_rule ;
+	} kind ;
+
+        /*
+         *the specificity of the selector
+         *that matched this statement.
+         *This is only used by the cascading
+         *order determination algorithm.
+         */
+        gulong specificity ;
+
+        /*
+         *the style sheet that contains
+         *this css statement.
+         */
+        CRStyleSheet *parent_sheet ;
+	CRStatement *next ;
+	CRStatement *prev ;
+
+        CRParsingLocation location ;
+
+        /**
+         *a custom pointer useable by
+         *applications that use libcroco.
+         *libcroco itself will never modify
+         *this pointer.
+         */        
+        gpointer app_data ;
+
+        /**
+         *a custom pointer used
+         *by the upper layers of libcroco.
+         *application should never use this
+         *pointer.
+         */
+        gpointer croco_data ;
+
+} ;
+
+
+gboolean
+cr_statement_does_buf_parses_against_core (const guchar *a_buf,
+                                           enum CREncoding a_encoding) ;
+CRStatement *
+cr_statement_parse_from_buf (const guchar *a_buf,
+			     enum CREncoding a_encoding) ;
+CRStatement*
+cr_statement_new_ruleset (CRStyleSheet *a_sheet,
+                          CRSelector *a_sel_list, 
+			  CRDeclaration *a_decl_list,
+			  CRStatement *a_media_rule) ;
+CRStatement *
+cr_statement_ruleset_parse_from_buf (const guchar * a_buf,
+				     enum CREncoding a_enc) ;
+
+CRStatement*
+cr_statement_new_at_import_rule (CRStyleSheet *a_container_sheet,
+                                 CRString *a_url,
+                                 GList *a_media_list,
+				 CRStyleSheet *a_imported_sheet) ;
+
+CRStatement *
+cr_statement_at_import_rule_parse_from_buf (const guchar * a_buf,
+                                            enum CREncoding a_encoding) ;
+
+CRStatement *
+cr_statement_new_at_media_rule (CRStyleSheet *a_sheet,
+                                CRStatement *a_ruleset,
+				GList *a_media) ;
+CRStatement *
+cr_statement_at_media_rule_parse_from_buf (const guchar *a_buf,
+					   enum CREncoding a_enc) ;
+
+CRStatement *
+cr_statement_new_at_charset_rule (CRStyleSheet *a_sheet,
+                                  CRString *a_charset) ;
+CRStatement *
+cr_statement_at_charset_rule_parse_from_buf (const guchar *a_buf,
+					     enum CREncoding a_encoding);
+
+
+CRStatement *
+cr_statement_new_at_font_face_rule (CRStyleSheet *a_sheet,
+                                    CRDeclaration *a_font_decls) ;
+CRStatement *
+cr_statement_font_face_rule_parse_from_buf (const guchar *a_buf,
+					    enum CREncoding a_encoding) ;
+
+CRStatement *
+cr_statement_new_at_page_rule (CRStyleSheet *a_sheet,
+                               CRDeclaration *a_decl_list,
+			       CRString *a_name,
+			       CRString *a_pseudo) ;
+CRStatement *
+cr_statement_at_page_rule_parse_from_buf (const guchar *a_buf,
+					  enum CREncoding a_encoding)  ;
+
+enum CRStatus
+cr_statement_set_parent_sheet (CRStatement *a_this, 
+                               CRStyleSheet *a_sheet) ;
+
+enum CRStatus
+cr_statement_get_parent_sheet (CRStatement *a_this, 
+                               CRStyleSheet **a_sheet) ;
+
+CRStatement *
+cr_statement_append (CRStatement *a_this,
+		     CRStatement *a_new) ;
+
+CRStatement*
+cr_statement_prepend (CRStatement *a_this,
+		      CRStatement *a_new) ;
+
+CRStatement *
+cr_statement_unlink (CRStatement *a_stmt) ;
+
+enum CRStatus
+cr_statement_ruleset_set_sel_list (CRStatement *a_this,
+				   CRSelector *a_sel_list) ;
+
+enum CRStatus
+cr_statement_ruleset_get_sel_list (CRStatement const *a_this,
+				   CRSelector **a_list) ;
+
+enum CRStatus
+cr_statement_ruleset_set_decl_list (CRStatement *a_this,
+				    CRDeclaration *a_list) ;
+
+enum CRStatus
+cr_statement_ruleset_get_declarations (CRStatement *a_this,
+                                       CRDeclaration **a_decl_list) ;
+
+enum CRStatus
+cr_statement_ruleset_append_decl2 (CRStatement *a_this,
+				   CRString *a_prop, CRTerm *a_value) ;
+
+enum CRStatus
+cr_statement_ruleset_append_decl (CRStatement *a_this,
+				  CRDeclaration *a_decl) ;
+
+enum CRStatus
+cr_statement_at_import_rule_set_imported_sheet (CRStatement *a_this,
+                                                CRStyleSheet *a_sheet) ;
+
+enum CRStatus
+cr_statement_at_import_rule_get_imported_sheet (CRStatement *a_this,
+                                                CRStyleSheet **a_sheet) ;
+
+enum CRStatus
+cr_statement_at_import_rule_set_url (CRStatement *a_this,
+				     CRString *a_url) ;
+
+enum CRStatus
+cr_statement_at_import_rule_get_url (CRStatement const *a_this,
+				     CRString **a_url) ;
+
+gint
+cr_statement_at_media_nr_rules (CRStatement const *a_this) ;
+
+CRStatement *
+cr_statement_at_media_get_from_list (CRStatement *a_this, int itemnr) ;
+
+enum CRStatus
+cr_statement_at_page_rule_set_sel (CRStatement *a_this,
+				   CRSelector *a_sel) ;
+
+enum CRStatus
+cr_statement_at_page_rule_get_sel (CRStatement const *a_this,
+				   CRSelector **a_sel) ;
+
+enum CRStatus
+cr_statement_at_page_rule_set_declarations (CRStatement *a_this,
+					    CRDeclaration *a_decl_list) ;
+
+enum CRStatus
+cr_statement_at_page_rule_get_declarations (CRStatement *a_this,
+					    CRDeclaration **a_decl_list) ;
+
+enum CRStatus
+cr_statement_at_charset_rule_set_charset (CRStatement *a_this,
+					  CRString *a_charset) ;
+
+enum CRStatus
+cr_statement_at_charset_rule_get_charset (CRStatement const *a_this,
+					  CRString **a_charset) ;
+
+enum CRStatus
+cr_statement_at_font_face_rule_set_decls (CRStatement *a_this,
+					  CRDeclaration *a_decls) ;
+
+enum CRStatus
+cr_statement_at_font_face_rule_get_decls (CRStatement *a_this,
+					  CRDeclaration **a_decls) ;
+
+enum CRStatus
+cr_statement_at_font_face_rule_add_decl (CRStatement *a_this,
+					 CRString *a_prop,
+					 CRTerm *a_value) ;
+
+gchar *
+cr_statement_to_string (CRStatement const * a_this, gulong a_indent) ;
+
+gchar*
+cr_statement_list_to_string (CRStatement const *a_this, gulong a_indent) ;
+
+void
+cr_statement_dump (CRStatement const *a_this, FILE *a_fp, gulong a_indent) ;
+
+void
+cr_statement_dump_ruleset (CRStatement const * a_this, FILE * a_fp,
+                           glong a_indent) ;
+
+void
+cr_statement_dump_font_face_rule (CRStatement const * a_this,
+                                  FILE * a_fp,
+                                  glong a_indent) ;
+
+void
+cr_statement_dump_page (CRStatement const * a_this, FILE * a_fp,
+                        gulong a_indent) ;
+
+
+void
+cr_statement_dump_media_rule (CRStatement const * a_this,
+                              FILE * a_fp,
+                              gulong a_indent) ;
+
+void
+cr_statement_dump_import_rule (CRStatement const * a_this, FILE * a_fp,
+                               gulong a_indent) ; 
+void
+cr_statement_dump_charset (CRStatement const * a_this, FILE * a_fp,
+                           gulong a_indent) ;
+gint
+cr_statement_nr_rules (CRStatement const *a_this) ;
+
+CRStatement *
+cr_statement_get_from_list (CRStatement *a_this, int itemnr) ;
+
+void
+cr_statement_destroy (CRStatement *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_STATEMENT_H__*/
diff --git a/src/st/croco/cr-string.c b/src/st/croco/cr-string.c
new file mode 100644
index 000000000..1b10bb2ab
--- /dev/null
+++ b/src/st/croco/cr-string.c
@@ -0,0 +1,168 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ * 
+ * Author: Dodji Seketeli.
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include <string.h>
+#include "cr-string.h"
+
+/**
+ *Instanciates a #CRString
+ *@return the newly instanciated #CRString
+ *Must be freed with cr_string_destroy().
+ */
+CRString *
+cr_string_new (void)
+{
+	CRString *result = NULL ;
+
+	result = g_try_malloc (sizeof (CRString)) ;
+	if (!result) {
+		cr_utils_trace_info ("Out of memory") ;
+		return NULL ;
+	}
+	memset (result, 0, sizeof (CRString)) ;
+        result->stryng = g_string_new (NULL) ;
+	return result ;
+}
+
+/**
+ *Instanciate a string and initialise it to
+ *a_string.
+ *@param a_string the initial string
+ *@return the newly instanciated string.
+ */
+CRString  *
+cr_string_new_from_string (const gchar * a_string)
+{
+	CRString *result = NULL ;
+
+	result = cr_string_new () ;
+	if (!result) {
+		cr_utils_trace_info ("Out of memory") ;
+		return NULL ;
+	}
+	if (a_string)
+		g_string_append (result->stryng, a_string) ;
+	return result ;
+}
+
+/**
+ *Instanciates a #CRString from an instance of GString.
+ *@param a_string the input string that will be copied into
+ *the newly instanciated #CRString
+ *@return the newly instanciated #CRString.
+ */
+CRString *
+cr_string_new_from_gstring (GString const *a_string)
+{
+	CRString *result = NULL ;
+
+	result = cr_string_new () ;
+	if (!result) {
+		cr_utils_trace_info ("Out of memory") ;
+		return NULL ;
+	}
+	if (a_string) {
+		g_string_append_len (result->stryng,
+				     a_string->str,
+				     a_string->len);
+
+	}
+	return result ;
+}
+
+CRString *
+cr_string_dup (CRString const *a_this)
+{
+	CRString *result = NULL ;
+	g_return_val_if_fail (a_this, NULL) ;
+
+	result = cr_string_new_from_gstring (a_this->stryng) ;
+	if (!result) {
+		cr_utils_trace_info ("Out of memory") ;
+		return NULL ;
+	}
+	cr_parsing_location_copy (&result->location,
+                                  &a_this->location) ;
+        return result ;
+}
+
+gchar *
+cr_string_dup2 (CRString const *a_this)
+{
+        gchar *result = NULL ;
+
+        g_return_val_if_fail (a_this, NULL) ;
+
+        if (a_this 
+            && a_this->stryng 
+            && a_this->stryng->str) {
+                result = g_strndup (a_this->stryng->str,
+                                    a_this->stryng->len) ;
+        }
+        return result ;
+}
+
+/**
+ *Returns a pointer to the internal raw NULL terminated string
+ *of the current instance of #CRString.
+ *@param a_this the current instance of #CRString
+ */
+const gchar *
+cr_string_peek_raw_str (CRString const *a_this)
+{
+        g_return_val_if_fail (a_this, NULL) ;
+        
+        if (a_this->stryng && a_this->stryng->str)
+                return a_this->stryng->str ;
+        return NULL ;
+}
+
+/**
+ *Returns the length of the internal raw NULL terminated
+ *string of the current instance of #CRString.
+ *@param a_this the current instance of #CRString.
+ *@return the len of the internal raw NULL termninated string,
+ *of -1 if no length can be returned.
+ */
+gint
+cr_string_peek_raw_str_len (CRString const *a_this)
+{
+        g_return_val_if_fail (a_this && a_this->stryng,
+                              -1) ;
+        return a_this->stryng->len ;
+}
+
+/**
+ *@param a_this the #CRString to destroy.
+ */
+void
+cr_string_destroy (CRString *a_this)
+{
+	g_return_if_fail (a_this) ;
+
+	if (a_this->stryng) {
+		g_string_free (a_this->stryng, TRUE) ;
+		a_this->stryng = NULL ;
+	}
+	g_free (a_this) ;
+}
diff --git a/src/st/croco/cr-string.h b/src/st/croco/cr-string.h
new file mode 100644
index 000000000..2700f0e2e
--- /dev/null
+++ b/src/st/croco/cr-string.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ * 
+ * See COPYRIGHTS file for copyright information.
+ */
+
+/**
+ *@file
+ *Declaration file of the #CRString class.
+ */
+
+#ifndef __CR_STRING_H__
+#define __CR_STRING_H__
+
+#include <glib.h>
+#include "cr-utils.h"
+#include "cr-parsing-location.h"
+
+G_BEGIN_DECLS
+
+typedef struct _CRString CRString ;
+
+/**
+ *This is a ship implementation of string based on GString.
+ *Actually, the aim of CRString is to store the parsing location
+ *(line,column,byte offset) at which a given string has been parsed
+ *in the input CSS.
+ *So this class has a gstring field of type GString that users can
+ *freely manipulate, and also a CRParginLocation type where the
+ *parsing location is store. If you don't want to deal with parsing
+ *location stuffs, then use GString instead. If we were in C++ for example,
+ *CRString would just inherit GString and just add accessors to
+ *the CRParsingLocation data ... but we are not and we still have
+ *to provide the parsing location information.
+ */
+struct _CRString {
+	/**
+	 *The GString where all the string
+	 *operation happen.
+	 */
+	GString *stryng ;
+	/**
+	 *The parsing location storage area.
+	 */
+	CRParsingLocation location ;
+} ;
+
+CRString * cr_string_new (void) ;
+
+CRString  *cr_string_new_from_string (const gchar * a_string) ;
+CRString * cr_string_new_from_gstring (GString const *a_string) ;
+CRString *cr_string_dup (CRString const *a_this) ;
+gchar *cr_string_dup2 (CRString const *a_this) ;
+const gchar *cr_string_peek_raw_str (CRString const *a_this) ;
+gint cr_string_peek_raw_str_len (CRString const *a_this) ;
+void cr_string_destroy (CRString *a_this) ;
+
+G_END_DECLS
+
+#endif 
diff --git a/src/st/croco/cr-stylesheet.c b/src/st/croco/cr-stylesheet.c
new file mode 100644
index 000000000..69909da24
--- /dev/null
+++ b/src/st/croco/cr-stylesheet.c
@@ -0,0 +1,178 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * Copyright (C) 2002-2004 Dodji Seketeli
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include "string.h"
+#include "cr-stylesheet.h"
+
+/**
+ *@file
+ *The definition of the #CRStyleSheet class
+ */
+
+/**
+ *Constructor of the #CRStyleSheet class.
+ *@param the initial list of css statements.
+ *@return the newly built css2 stylesheet, or NULL in case of error.
+ */
+CRStyleSheet *
+cr_stylesheet_new (CRStatement * a_stmts)
+{
+        CRStyleSheet *result;
+
+        result = g_try_malloc (sizeof (CRStyleSheet));
+        if (!result) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+
+        memset (result, 0, sizeof (CRStyleSheet));
+
+        if (a_stmts)
+                result->statements = a_stmts;
+
+        return result;
+}
+
+/**
+ *@param a_this the current instance of #CRStyleSheet
+ *@return the serialized stylesheet.
+ */
+gchar *
+cr_stylesheet_to_string (CRStyleSheet const *a_this)
+{
+	gchar *str = NULL;
+	GString *stringue = NULL;
+	CRStatement const *cur_stmt = NULL;
+
+        g_return_val_if_fail (a_this, NULL);
+
+	if (a_this->statements) {
+		stringue = g_string_new (NULL) ;
+		g_return_val_if_fail (stringue, NULL) ;
+	}
+        for (cur_stmt = a_this->statements;
+             cur_stmt; cur_stmt = cur_stmt->next) {
+		if (cur_stmt->prev) {
+			g_string_append (stringue, "\n\n") ;
+		}
+		str = cr_statement_to_string (cur_stmt, 0) ;
+		if (str) {
+			g_string_append (stringue, str) ;
+			g_free (str) ;
+			str = NULL ;
+		}
+        }
+	if (stringue) {
+		str = stringue->str ;
+		g_string_free (stringue, FALSE) ;
+		stringue = NULL ;
+	}
+	return str ;
+}
+
+/**
+ *Dumps the current css2 stylesheet to a file.
+ *@param a_this the current instance of #CRStyleSheet.
+ *@param a_fp the destination file
+ */
+void
+cr_stylesheet_dump (CRStyleSheet const * a_this, FILE * a_fp)
+{
+	gchar *str = NULL ;
+
+        g_return_if_fail (a_this);
+
+	str = cr_stylesheet_to_string (a_this) ;
+	if (str) {
+		fprintf (a_fp, "%s", str) ;
+		g_free (str) ;
+		str = NULL ;
+	}
+}
+
+/**
+ *Return the number of rules in the stylesheet.
+ *@param a_this the current instance of #CRStyleSheet.
+ *@return number of rules in the stylesheet.
+ */
+gint
+cr_stylesheet_nr_rules (CRStyleSheet const * a_this)
+{
+        g_return_val_if_fail (a_this, -1);
+
+        return cr_statement_nr_rules (a_this->statements);
+}
+
+/**
+ *Use an index to get a CRStatement from the rules in a given stylesheet.
+ *@param a_this the current instance of #CRStatement.
+ *@param itemnr the index into the rules.
+ *@return CRStatement at position itemnr, if itemnr > number of rules - 1,
+ *it will return NULL.
+ */
+CRStatement *
+cr_stylesheet_statement_get_from_list (CRStyleSheet * a_this, int itemnr)
+{
+        g_return_val_if_fail (a_this, NULL);
+
+        return cr_statement_get_from_list (a_this->statements, itemnr);
+}
+
+void
+cr_stylesheet_ref (CRStyleSheet * a_this)
+{
+        g_return_if_fail (a_this);
+
+        a_this->ref_count++;
+}
+
+gboolean
+cr_stylesheet_unref (CRStyleSheet * a_this)
+{
+        g_return_val_if_fail (a_this, FALSE);
+
+        if (a_this->ref_count)
+                a_this->ref_count--;
+
+        if (!a_this->ref_count) {
+                cr_stylesheet_destroy (a_this);
+                return TRUE;
+        }
+
+        return FALSE;
+}
+
+/**
+ *Destructor of the #CRStyleSheet class.
+ *@param a_this the current instance of the #CRStyleSheet class.
+ */
+void
+cr_stylesheet_destroy (CRStyleSheet * a_this)
+{
+        g_return_if_fail (a_this);
+
+        if (a_this->statements) {
+                cr_statement_destroy (a_this->statements);
+                a_this->statements = NULL;
+        }
+        g_free (a_this);
+}
diff --git a/src/st/croco/cr-stylesheet.h b/src/st/croco/cr-stylesheet.h
new file mode 100644
index 000000000..f35c94e37
--- /dev/null
+++ b/src/st/croco/cr-stylesheet.h
@@ -0,0 +1,102 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ * 
+ * see COPYRIGHTS file for copyright information.
+ */
+
+
+#ifndef __CR_STYLESHEET_H__
+#define __CR_STYLESHEET_H__
+
+#include "cr-utils.h"
+#include "cr-statement.h"
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *The declaration of the #CRStyleSheet class.
+ */
+
+
+enum CRStyleOrigin
+{
+        /*Please don't change the order of
+         *the values enumerated here ...
+         *New values should be added at the end,
+         *just before ORIGIN_END.
+         */
+        ORIGIN_UA = 0,
+        ORIGIN_USER,
+	ORIGIN_AUTHOR,	
+
+        /*must always be the last one*/
+        NB_ORIGINS 
+} ;
+
+/**
+ *An abstraction of a css stylesheet as defined
+ *by the css2 spec in chapter 4.
+ */
+struct _CRStyleSheet
+{
+	/**The css statements list*/
+	CRStatement *statements ;
+
+        enum CRStyleOrigin origin ;
+
+        /*the parent import rule, if any.*/
+        CRStatement *parent_import_rule ;
+
+	/**custom data used by libcroco*/
+	gpointer croco_data ;
+
+	/**
+	 *custom application data pointer
+	 *Can be used by applications.
+	 */
+	gpointer app_data ;
+
+	/**
+	 *the reference count of this insance
+	 *Please, don't never ever modify it
+	 *directly. Use cr_stylesheet_ref()
+	 *and cr_stylesheet_unref() instead.
+	 */
+	gulong ref_count ;
+} ;
+
+CRStyleSheet * cr_stylesheet_new (CRStatement *a_stmts) ;
+
+gchar * cr_stylesheet_to_string (CRStyleSheet const *a_this) ;
+void cr_stylesheet_dump (CRStyleSheet const *a_this, FILE *a_fp) ;
+
+gint cr_stylesheet_nr_rules (CRStyleSheet const *a_this) ;
+
+CRStatement * cr_stylesheet_statement_get_from_list (CRStyleSheet *a_this, int itemnr) ;
+
+void cr_stylesheet_ref (CRStyleSheet *a_this) ;
+
+gboolean cr_stylesheet_unref (CRStyleSheet *a_this) ;
+
+void cr_stylesheet_destroy (CRStyleSheet *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_STYLESHEET_H__*/
diff --git a/src/st/croco/cr-term.c b/src/st/croco/cr-term.c
new file mode 100644
index 000000000..9ffe6727b
--- /dev/null
+++ b/src/st/croco/cr-term.c
@@ -0,0 +1,790 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "cr-term.h"
+#include "cr-num.h"
+#include "cr-parser.h"
+
+/**
+ *@file
+ *Definition of the #CRTem class.
+ */
+
+static void
+cr_term_clear (CRTerm * a_this)
+{
+        g_return_if_fail (a_this);
+
+        switch (a_this->type) {
+        case TERM_NUMBER:
+                if (a_this->content.num) {
+                        cr_num_destroy (a_this->content.num);
+                        a_this->content.num = NULL;
+                }
+                break;
+
+        case TERM_FUNCTION:
+                if (a_this->ext_content.func_param) {
+                        cr_term_destroy (a_this->ext_content.func_param);
+                        a_this->ext_content.func_param = NULL;
+                }
+        case TERM_STRING:
+        case TERM_IDENT:
+        case TERM_URI:
+        case TERM_HASH:
+                if (a_this->content.str) {
+                        cr_string_destroy (a_this->content.str);
+                        a_this->content.str = NULL;
+                }
+                break;
+
+        case TERM_RGB:
+                if (a_this->content.rgb) {
+                        cr_rgb_destroy (a_this->content.rgb);
+                        a_this->content.rgb = NULL;
+                }
+                break;
+
+        case TERM_UNICODERANGE:
+        case TERM_NO_TYPE:
+        default:
+                break;
+        }
+
+        a_this->type = TERM_NO_TYPE;
+}
+
+/**
+ *Instanciate a #CRTerm.
+ *@return the newly build instance
+ *of #CRTerm.
+ */
+CRTerm *
+cr_term_new (void)
+{
+        CRTerm *result = NULL;
+
+        result = g_try_malloc (sizeof (CRTerm));
+        if (!result) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+        memset (result, 0, sizeof (CRTerm));
+        return result;
+}
+
+/**
+ *Parses an expresion as defined by the css2 spec
+ *and builds the expression as a list of terms.
+ *@param a_buf the buffer to parse.
+ *@return a pointer to the first term of the expression or
+ *NULL if parsing failed.
+ */
+CRTerm *
+cr_term_parse_expression_from_buf (const guchar * a_buf,
+                                   enum CREncoding a_encoding)
+{
+        CRParser *parser = NULL;
+        CRTerm *result = NULL;
+        enum CRStatus status = CR_OK;
+
+        g_return_val_if_fail (a_buf, NULL);
+
+        parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
+                                         a_encoding, FALSE);
+        g_return_val_if_fail (parser, NULL);
+
+        status = cr_parser_try_to_skip_spaces_and_comments (parser);
+        if (status != CR_OK) {
+                goto cleanup;
+        }
+        status = cr_parser_parse_expr (parser, &result);
+        if (status != CR_OK) {
+                if (result) {
+                        cr_term_destroy (result);
+                        result = NULL;
+                }
+        }
+
+      cleanup:
+        if (parser) {
+                cr_parser_destroy (parser);
+                parser = NULL;
+        }
+
+        return result;
+}
+
+enum CRStatus
+cr_term_set_number (CRTerm * a_this, CRNum * a_num)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_term_clear (a_this);
+
+        a_this->type = TERM_NUMBER;
+        a_this->content.num = a_num;
+        return CR_OK;
+}
+
+enum CRStatus
+cr_term_set_function (CRTerm * a_this, CRString * a_func_name,
+                      CRTerm * a_func_param)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_term_clear (a_this);
+
+        a_this->type = TERM_FUNCTION;
+        a_this->content.str = a_func_name;
+        a_this->ext_content.func_param = a_func_param;
+        return CR_OK;
+}
+
+enum CRStatus
+cr_term_set_string (CRTerm * a_this, CRString * a_str)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_term_clear (a_this);
+
+        a_this->type = TERM_STRING;
+        a_this->content.str = a_str;
+        return CR_OK;
+}
+
+enum CRStatus
+cr_term_set_ident (CRTerm * a_this, CRString * a_str)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_term_clear (a_this);
+
+        a_this->type = TERM_IDENT;
+        a_this->content.str = a_str;
+        return CR_OK;
+}
+
+enum CRStatus
+cr_term_set_uri (CRTerm * a_this, CRString * a_str)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_term_clear (a_this);
+
+        a_this->type = TERM_URI;
+        a_this->content.str = a_str;
+        return CR_OK;
+}
+
+enum CRStatus
+cr_term_set_rgb (CRTerm * a_this, CRRgb * a_rgb)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_term_clear (a_this);
+
+        a_this->type = TERM_RGB;
+        a_this->content.rgb = a_rgb;
+        return CR_OK;
+}
+
+enum CRStatus
+cr_term_set_hash (CRTerm * a_this, CRString * a_str)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_term_clear (a_this);
+
+        a_this->type = TERM_HASH;
+        a_this->content.str = a_str;
+        return CR_OK;
+}
+
+/**
+ *Appends a new term to the current list of #CRTerm.
+ *
+ *@param a_this the "this pointer" of the current instance
+ *of #CRTerm .
+ *@param a_new_term the term to append.
+ *@return the list of terms with the a_new_term appended to it.
+ */
+CRTerm *
+cr_term_append_term (CRTerm * a_this, CRTerm * a_new_term)
+{
+        CRTerm *cur = NULL;
+
+        g_return_val_if_fail (a_new_term, NULL);
+
+        if (a_this == NULL)
+                return a_new_term;
+
+        for (cur = a_this; cur->next; cur = cur->next) ;
+
+        cur->next = a_new_term;
+        a_new_term->prev = cur;
+
+        return a_this;
+}
+
+/**
+ *Prepends a term to the list of terms represented by a_this.
+ *
+ *@param a_this the "this pointer" of the current instance of
+ *#CRTerm .
+ *@param a_new_term the term to prepend.
+ *@return the head of the new list.
+ */
+CRTerm *
+cr_term_prepend_term (CRTerm * a_this, CRTerm * a_new_term)
+{
+        g_return_val_if_fail (a_this && a_new_term, NULL);
+
+        a_new_term->next = a_this;
+        a_this->prev = a_new_term;
+
+        return a_new_term;
+}
+
+/**
+ *Serializes the expression represented by
+ *the chained instances of #CRterm.
+ *@param a_this the current instance of #CRTerm
+ *@return the zero terminated string containing the serialized
+ *form of #CRTerm. MUST BE FREED BY THE CALLER using g_free().
+ */
+guchar *
+cr_term_to_string (CRTerm const * a_this)
+{
+        GString *str_buf = NULL;
+        CRTerm const *cur = NULL;
+        guchar *result = NULL,
+                *content = NULL;
+
+        g_return_val_if_fail (a_this, NULL);
+
+        str_buf = g_string_new (NULL);
+        g_return_val_if_fail (str_buf, NULL);
+
+        for (cur = a_this; cur; cur = cur->next) {
+                if ((cur->content.str == NULL)
+                    && (cur->content.num == NULL)
+                    && (cur->content.str == NULL)
+                    && (cur->content.rgb == NULL))
+                        continue;
+
+                switch (cur->the_operator) {
+                case DIVIDE:
+                        g_string_append (str_buf, " / ");
+                        break;
+
+                case COMMA:
+                        g_string_append (str_buf, ", ");
+                        break;
+
+                case NO_OP:
+                        if (cur->prev) {
+                                g_string_append (str_buf, " ");
+                        }
+                        break;
+                default:
+
+                        break;
+                }
+
+                switch (cur->unary_op) {
+                case PLUS_UOP:
+                        g_string_append (str_buf, "+");
+                        break;
+
+                case MINUS_UOP:
+                        g_string_append (str_buf, "-");
+                        break;
+
+                default:
+                        break;
+                }
+
+                switch (cur->type) {
+                case TERM_NUMBER:
+                        if (cur->content.num) {
+                                content = cr_num_to_string (cur->content.num);
+                        }
+
+                        if (content) {
+                                g_string_append (str_buf, (const gchar *) content);
+                                g_free (content);
+                                content = NULL;
+                        }
+
+                        break;
+
+                case TERM_FUNCTION:
+                        if (cur->content.str) {
+                                content = (guchar *) g_strndup
+                                        (cur->content.str->stryng->str,
+                                         cur->content.str->stryng->len);
+                        }
+
+                        if (content) {
+                                g_string_append_printf (str_buf, "%s(",
+                                                        content);
+
+                                if (cur->ext_content.func_param) {
+                                        guchar *tmp_str = NULL;
+
+                                        tmp_str = cr_term_to_string
+                                                (cur->
+                                                 ext_content.func_param);
+
+                                        if (tmp_str) {
+                                                g_string_append (str_buf, 
+								 (const gchar *) tmp_str);
+                                                g_free (tmp_str);
+                                                tmp_str = NULL;
+                                        }
+                                }
+                                g_string_append (str_buf, ")");
+                                g_free (content);
+                                content = NULL;
+                        }
+
+                        break;
+
+                case TERM_STRING:
+                        if (cur->content.str) {
+                                content = (guchar *) g_strndup
+                                        (cur->content.str->stryng->str,
+                                         cur->content.str->stryng->len);
+                        }
+
+                        if (content) {
+                                g_string_append_printf (str_buf,
+                                                        "\"%s\"", content);
+                                g_free (content);
+                                content = NULL;
+                        }
+                        break;
+
+                case TERM_IDENT:
+                        if (cur->content.str) {
+                                content = (guchar *) g_strndup
+                                        (cur->content.str->stryng->str,
+                                         cur->content.str->stryng->len);
+                        }
+
+                        if (content) {
+                                g_string_append (str_buf, (const gchar *) content);
+                                g_free (content);
+                                content = NULL;
+                        }
+                        break;
+
+                case TERM_URI:
+                        if (cur->content.str) {
+                                content = (guchar *) g_strndup
+                                        (cur->content.str->stryng->str,
+                                         cur->content.str->stryng->len);
+                        }
+
+                        if (content) {
+                                g_string_append_printf
+                                        (str_buf, "url(%s)", content);
+                                g_free (content);
+                                content = NULL;
+                        }
+                        break;
+
+                case TERM_RGB:
+                        if (cur->content.rgb) {
+                                guchar *tmp_str = NULL;
+
+                                g_string_append (str_buf, "rgb(");
+                                tmp_str = cr_rgb_to_string (cur->content.rgb);
+
+                                if (tmp_str) {
+                                        g_string_append (str_buf, (const gchar *) tmp_str);
+                                        g_free (tmp_str);
+                                        tmp_str = NULL;
+                                }
+                                g_string_append (str_buf, ")");
+                        }
+
+                        break;
+
+                case TERM_UNICODERANGE:
+                        g_string_append
+                                (str_buf,
+                                 "?found unicoderange: dump not supported yet?");
+                        break;
+
+                case TERM_HASH:
+                        if (cur->content.str) {
+                                content = (guchar *) g_strndup
+                                        (cur->content.str->stryng->str,
+                                         cur->content.str->stryng->len);
+                        }
+
+                        if (content) {
+                                g_string_append_printf (str_buf,
+                                                        "#%s", content);
+                                g_free (content);
+                                content = NULL;
+                        }
+                        break;
+
+                default:
+                        g_string_append (str_buf,
+                                         "Unrecognized Term type");
+                        break;
+                }
+        }
+
+        if (str_buf) {
+                result =(guchar *) str_buf->str;
+                g_string_free (str_buf, FALSE);
+                str_buf = NULL;
+        }
+
+        return result;
+}
+
+guchar *
+cr_term_one_to_string (CRTerm const * a_this)
+{
+        GString *str_buf = NULL;
+        guchar *result = NULL,
+                *content = NULL;
+
+        g_return_val_if_fail (a_this, NULL);
+
+        str_buf = g_string_new (NULL);
+        g_return_val_if_fail (str_buf, NULL);
+
+        if ((a_this->content.str == NULL)
+            && (a_this->content.num == NULL)
+            && (a_this->content.str == NULL)
+            && (a_this->content.rgb == NULL))
+                return NULL ;
+
+        switch (a_this->the_operator) {
+        case DIVIDE:
+                g_string_append_printf (str_buf, " / ");
+                break;
+
+        case COMMA:
+                g_string_append_printf (str_buf, ", ");
+                break;
+
+        case NO_OP:
+                if (a_this->prev) {
+                        g_string_append_printf (str_buf, " ");
+                }
+                break;
+        default:
+
+                break;
+        }
+
+        switch (a_this->unary_op) {
+        case PLUS_UOP:
+                g_string_append_printf (str_buf, "+");
+                break;
+
+        case MINUS_UOP:
+                g_string_append_printf (str_buf, "-");
+                break;
+
+        default:
+                break;
+        }
+
+        switch (a_this->type) {
+        case TERM_NUMBER:
+                if (a_this->content.num) {
+                        content = cr_num_to_string (a_this->content.num);
+                }
+
+                if (content) {
+                        g_string_append (str_buf, (const gchar *) content);
+                        g_free (content);
+                        content = NULL;
+                }
+
+                break;
+
+        case TERM_FUNCTION:
+                if (a_this->content.str) {
+                        content = (guchar *) g_strndup
+                                (a_this->content.str->stryng->str,
+                                 a_this->content.str->stryng->len);
+                }
+
+                if (content) {
+                        g_string_append_printf (str_buf, "%s(",
+                                                content);
+
+                        if (a_this->ext_content.func_param) {
+                                guchar *tmp_str = NULL;
+
+                                tmp_str = cr_term_to_string
+                                        (a_this->
+                                         ext_content.func_param);
+
+                                if (tmp_str) {
+                                        g_string_append_printf
+                                                (str_buf,
+                                                 "%s", tmp_str);
+                                        g_free (tmp_str);
+                                        tmp_str = NULL;
+                                }
+
+                                g_string_append_printf (str_buf, ")");
+                                g_free (content);
+                                content = NULL;
+                        }
+                }
+
+                break;
+
+        case TERM_STRING:
+                if (a_this->content.str) {
+                        content = (guchar *) g_strndup
+                                (a_this->content.str->stryng->str,
+                                 a_this->content.str->stryng->len);
+                }
+
+                if (content) {
+                        g_string_append_printf (str_buf,
+                                                "\"%s\"", content);
+                        g_free (content);
+                        content = NULL;
+                }
+                break;
+
+        case TERM_IDENT:
+                if (a_this->content.str) {
+                        content = (guchar *) g_strndup
+                                (a_this->content.str->stryng->str,
+                                 a_this->content.str->stryng->len);
+                }
+
+                if (content) {
+                        g_string_append (str_buf, (const gchar *) content);
+                        g_free (content);
+                        content = NULL;
+                }
+                break;
+
+        case TERM_URI:
+                if (a_this->content.str) {
+                        content = (guchar *) g_strndup
+                                (a_this->content.str->stryng->str,
+                                 a_this->content.str->stryng->len);
+                }
+
+                if (content) {
+                        g_string_append_printf
+                                (str_buf, "url(%s)", content);
+                        g_free (content);
+                        content = NULL;
+                }
+                break;
+
+        case TERM_RGB:
+                if (a_this->content.rgb) {
+                        guchar *tmp_str = NULL;
+
+                        g_string_append_printf (str_buf, "rgb(");
+                        tmp_str = cr_rgb_to_string (a_this->content.rgb);
+
+                        if (tmp_str) {
+                                g_string_append (str_buf, (const gchar *) tmp_str);
+                                g_free (tmp_str);
+                                tmp_str = NULL;
+                        }
+                        g_string_append_printf (str_buf, ")");
+                }
+
+                break;
+
+        case TERM_UNICODERANGE:
+                g_string_append_printf
+                        (str_buf,
+                         "?found unicoderange: dump not supported yet?");
+                break;
+
+        case TERM_HASH:
+                if (a_this->content.str) {
+                        content = (guchar *) g_strndup
+                                (a_this->content.str->stryng->str,
+                                 a_this->content.str->stryng->len);
+                }
+
+                if (content) {
+                        g_string_append_printf (str_buf,
+                                                "#%s", content);
+                        g_free (content);
+                        content = NULL;
+                }
+                break;
+
+        default:
+                g_string_append_printf (str_buf,
+                                        "%s",
+                                        "Unrecognized Term type");
+                break;
+        }
+
+        if (str_buf) {
+                result = (guchar *) str_buf->str;
+                g_string_free (str_buf, FALSE);
+                str_buf = NULL;
+        }
+
+        return result;
+}
+
+/**
+ *Dumps the expression (a list of terms connected by operators)
+ *to a file.
+ *TODO: finish the dump. The dump of some type of terms have not yet been
+ *implemented.
+ *@param a_this the current instance of #CRTerm.
+ *@param a_fp the destination file pointer.
+ */
+void
+cr_term_dump (CRTerm const * a_this, FILE * a_fp)
+{
+        guchar *content = NULL;
+
+        g_return_if_fail (a_this);
+
+        content = cr_term_to_string (a_this);
+
+        if (content) {
+                fprintf (a_fp, "%s", content);
+                g_free (content);
+        }
+}
+
+/**
+ *Return the number of terms in the expression.
+ *@param a_this the current instance of #CRTerm.
+ *@return number of terms in the expression.
+ */
+int
+cr_term_nr_values (CRTerm const *a_this)
+{
+	CRTerm const *cur = NULL ;
+	int nr = 0;
+
+	g_return_val_if_fail (a_this, -1) ;
+
+	for (cur = a_this ; cur ; cur = cur->next)
+		nr ++;
+	return nr;
+}
+
+/**
+ *Use an index to get a CRTerm from the expression.
+ *@param a_this the current instance of #CRTerm.
+ *@param itemnr the index into the expression.
+ *@return CRTerm at position itemnr, if itemnr > number of terms - 1,
+ *it will return NULL.
+ */
+CRTerm *
+cr_term_get_from_list (CRTerm *a_this, int itemnr)
+{
+	CRTerm *cur = NULL ;
+	int nr = 0;
+
+	g_return_val_if_fail (a_this, NULL) ;
+
+	for (cur = a_this ; cur ; cur = cur->next)
+		if (nr++ == itemnr)
+			return cur;
+	return NULL;
+}
+
+/**
+ *Increments the reference counter of the current instance
+ *of #CRTerm.*
+ *@param a_this the current instance of #CRTerm.
+ */
+void
+cr_term_ref (CRTerm * a_this)
+{
+        g_return_if_fail (a_this);
+
+        a_this->ref_count++;
+}
+
+/**
+ *Decrements the ref count of the current instance of
+ *#CRTerm. If the ref count reaches zero, the instance is
+ *destroyed.
+ *@param a_this the current instance of #CRTerm.
+ *@return TRUE if the current instance has been destroyed, FALSE otherwise.
+ */
+gboolean
+cr_term_unref (CRTerm * a_this)
+{
+        g_return_val_if_fail (a_this, FALSE);
+
+        if (a_this->ref_count) {
+                a_this->ref_count--;
+        }
+
+        if (a_this->ref_count == 0) {
+                cr_term_destroy (a_this);
+                return TRUE;
+        }
+
+        return FALSE;
+}
+
+/**
+ *The destructor of the the #CRTerm class.
+ *@param a_this the "this pointer" of the current instance
+ *of #CRTerm.
+ */
+void
+cr_term_destroy (CRTerm * a_this)
+{
+        g_return_if_fail (a_this);
+
+        cr_term_clear (a_this);
+
+        if (a_this->next) {
+                cr_term_destroy (a_this->next);
+                a_this->next = NULL;
+        }
+
+        if (a_this) {
+                g_free (a_this);
+        }
+
+}
diff --git a/src/st/croco/cr-term.h b/src/st/croco/cr-term.h
new file mode 100644
index 000000000..0f22dda75
--- /dev/null
+++ b/src/st/croco/cr-term.h
@@ -0,0 +1,190 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ * 
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include "cr-utils.h"
+#include "cr-rgb.h"
+#include "cr-num.h"
+#include "cr-string.h"
+
+#ifndef __CR_TERM_H__
+#define __CR_TERM_H__
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *Declaration of the #CRTem class.
+ */
+
+enum CRTermType
+{
+        TERM_NO_TYPE = 0,
+        TERM_NUMBER,
+        TERM_FUNCTION,
+        TERM_STRING,
+        TERM_IDENT,
+        TERM_URI,
+        TERM_RGB,
+        TERM_UNICODERANGE,
+        TERM_HASH
+} ;
+
+
+enum UnaryOperator
+{
+        NO_UNARY_UOP = 0,
+        PLUS_UOP,
+        MINUS_UOP,
+        EMPTY_UNARY_UOP
+} ;
+
+enum Operator
+{
+        NO_OP = 0,
+        DIVIDE,
+        COMMA		
+} ;
+
+struct _CRTerm ;
+typedef struct _CRTerm CRTerm ;
+
+/**
+ *An abstraction of a css2 term as
+ *defined in the CSS2 spec in appendix D.1:
+ *term ::=
+ *[ NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* 
+ *| ANGLE S* | TIME S* | FREQ S* | function ]
+ * | STRING S* | IDENT S* | URI S* | RGB S* 
+ *| UNICODERANGE S* | hexcolor
+ */
+struct _CRTerm
+{
+        /**
+         *The type of the term.
+         */
+        enum CRTermType type ;
+                
+        /**
+         *The unary operator associated to
+         *the current term.
+         */
+        enum UnaryOperator unary_op ;
+
+        /**
+         *The operator associated to the current term.
+         */
+        enum Operator the_operator ;
+
+
+        /**
+         *The content of the term.
+         *Depending of the type of the term,
+         *this holds either a number, a percentage ...
+         */
+        union
+        {
+                CRNum *num ;
+                CRString * str ;
+                CRRgb * rgb ;
+        } content ;
+
+        /**
+         *If the term is of type UNICODERANGE, 
+         *this field holds the upper bound of the range.
+         *if the term is of type FUNCTION, this holds
+         *an instance of CRTerm that represents
+         * the expression which is the argument of the function.
+         */
+        union
+        {
+                CRTerm *func_param ;                        
+        } ext_content ;
+
+        /**
+         *A spare pointer, just in case.
+         *Can be used by the application.
+         */
+        gpointer app_data ;
+
+        glong ref_count ;
+
+        /**
+         *A pointer to the next term, 
+         *just in case this term is part of
+         *an expression.
+         */
+        CRTerm *next ;
+
+        /**
+         *A pointer to the previous
+         *term.
+         */
+        CRTerm *prev ;
+        CRParsingLocation location ;
+} ;
+
+CRTerm * cr_term_parse_expression_from_buf (const guchar *a_buf, 
+                                            enum CREncoding a_encoding) ;
+CRTerm * cr_term_new (void) ;
+
+enum CRStatus cr_term_set_number (CRTerm *a_this, CRNum *a_num) ;
+        
+enum CRStatus cr_term_set_function (CRTerm *a_this, 
+                                    CRString *a_func_name,
+                                    CRTerm *a_func_param) ;
+
+enum CRStatus cr_term_set_string (CRTerm *a_this, CRString *a_str) ;
+
+enum CRStatus cr_term_set_ident (CRTerm *a_this, CRString *a_str) ;
+
+enum CRStatus cr_term_set_uri (CRTerm *a_this, CRString *a_str) ;
+        
+enum CRStatus cr_term_set_rgb (CRTerm *a_this, CRRgb *a_rgb) ;
+        
+enum CRStatus cr_term_set_hash (CRTerm *a_this, CRString *a_str) ;
+        
+CRTerm * cr_term_append_term (CRTerm *a_this, CRTerm *a_new_term) ;
+
+CRTerm * cr_term_prepend_term (CRTerm *a_this, CRTerm *a_new_term) ;
+
+guchar * cr_term_to_string (CRTerm const *a_this) ;
+
+guchar * cr_term_one_to_string (CRTerm const * a_this) ;
+
+void cr_term_dump (CRTerm const *a_this, FILE *a_fp) ;
+
+int cr_term_nr_values (CRTerm const *a_this) ;
+
+CRTerm * cr_term_get_from_list (CRTerm *a_this, int itemnr) ;
+
+void cr_term_ref (CRTerm *a_this) ;
+
+gboolean cr_term_unref (CRTerm *a_this) ;
+
+void cr_term_destroy (CRTerm * a_term) ;
+
+G_END_DECLS
+
+#endif /*__CR_TERM_H__*/
diff --git a/src/st/croco/cr-tknzr.c b/src/st/croco/cr-tknzr.c
new file mode 100644
index 000000000..1548c35c6
--- /dev/null
+++ b/src/st/croco/cr-tknzr.c
@@ -0,0 +1,2762 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See the COPYRIGHTS file for copyrights information.
+ */
+
+/**
+ *@file
+ *The definition of the #CRTknzr (tokenizer)
+ *class.
+ */
+
+#include "string.h"
+#include "cr-tknzr.h"
+#include "cr-doc-handler.h"
+
+struct _CRTknzrPriv {
+        /**The parser input stream of bytes*/
+        CRInput *input;
+
+        /**
+         *A cache where tknzr_unget_token()
+         *puts back the token. tknzr_get_next_token()
+         *first look in this cache, and if and 
+         *only if it's empty, fetches the next token
+         *from the input stream.
+         */
+        CRToken *token_cache;
+
+        /**
+         *The position of the end of the previous token
+         *or char fetched.
+         */
+        CRInputPos prev_pos;
+
+        CRDocHandler *sac_handler;
+
+        /**
+         *The reference count of the current instance
+         *of #CRTknzr. Is manipulated by cr_tknzr_ref()
+         *and cr_tknzr_unref().
+         */
+        glong ref_count;
+};
+
+#define PRIVATE(obj) ((obj)->priv)
+
+/**
+ *return TRUE if the character is a number ([0-9]), FALSE otherwise
+ *@param a_char the char to test.
+ */
+#define IS_NUM(a_char) (((a_char) >= '0' && (a_char) <= '9')?TRUE:FALSE)
+
+/**
+ *Checks if 'status' equals CR_OK. If not, goto the 'error' label.
+ *
+ *@param status the status (of type enum CRStatus) to test.
+ *@param is_exception if set to FALSE, the final status returned the
+ *current function will be CR_PARSING_ERROR. If set to TRUE, the
+ *current status will be the current value of the 'status' variable.
+ *
+ */
+#define CHECK_PARSING_STATUS(status, is_exception) \
+if ((status) != CR_OK) \
+{ \
+        if (is_exception == FALSE) \
+        { \
+                status = CR_PARSING_ERROR ; \
+        } \
+        goto error ; \
+}
+
+/**
+ *Peeks the next char from the input stream of the current tokenizer.
+ *invokes CHECK_PARSING_STATUS on the status returned by
+ *cr_tknzr_input_peek_char().
+ *
+ *@param the current instance of #CRTkzr.
+ *@param to_char a pointer to the char where to store the
+ *char peeked.
+ */
+#define PEEK_NEXT_CHAR(a_tknzr, a_to_char) \
+{\
+status = cr_tknzr_peek_char  (a_tknzr, a_to_char) ; \
+CHECK_PARSING_STATUS (status, TRUE) \
+}
+
+/**
+ *Reads the next char from the input stream of the current parser.
+ *In case of error, jumps to the "error:" label located in the
+ *function where this macro is called.
+ *@param parser the curent instance of #CRTknzr
+ *@param to_char a pointer to the guint32 char where to store
+ *the character read.
+ */
+#define READ_NEXT_CHAR(a_tknzr, to_char) \
+status = cr_tknzr_read_char (a_tknzr, to_char) ;\
+CHECK_PARSING_STATUS (status, TRUE)
+
+/**
+ *Gets information about the current position in
+ *the input of the parser.
+ *In case of failure, this macro returns from the 
+ *calling function and
+ *returns a status code of type enum #CRStatus.
+ *@param parser the current instance of #CRTknzr.
+ *@param pos out parameter. A pointer to the position 
+ *inside the current parser input. Must
+ */
+#define RECORD_INITIAL_POS(a_tknzr, a_pos) \
+status = cr_input_get_cur_pos (PRIVATE  \
+(a_tknzr)->input, a_pos) ; \
+g_return_val_if_fail (status == CR_OK, status)
+
+/**
+ *Gets the address of the current byte inside the
+ *parser input.
+ *@param parser the current instance of #CRTknzr.
+ *@param addr out parameter a pointer (guchar*)
+ *to where the address  must be put.
+ */
+#define RECORD_CUR_BYTE_ADDR(a_tknzr, a_addr) \
+status = cr_input_get_cur_byte_addr \
+            (PRIVATE (a_tknzr)->input, a_addr) ; \
+CHECK_PARSING_STATUS (status, TRUE)
+
+/**
+ *Peeks a byte from the topmost parser input at
+ *a given offset from the current position.
+ *If it fails, goto the "error:" label.
+ *
+ *@param a_parser the current instance of #CRTknzr.
+ *@param a_offset the offset of the byte to peek, the
+ *current byte having the offset '0'.
+ *@param a_byte_ptr out parameter a pointer (guchar*) to
+ *where the peeked char is to be stored.
+ */
+#define PEEK_BYTE(a_tknzr, a_offset, a_byte_ptr) \
+status = cr_tknzr_peek_byte (a_tknzr, \
+                             a_offset, \
+                             a_byte_ptr) ; \
+CHECK_PARSING_STATUS (status, TRUE) ;
+
+#define BYTE(a_input, a_n, a_eof) \
+cr_input_peek_byte2 (a_input, a_n, a_eof)
+
+/**
+ *Reads a byte from the topmost parser input
+ *steam.
+ *If it fails, goto the "error" label.
+ *@param a_parser the current instance of #CRTknzr.
+ *@param a_byte_ptr the guchar * where to put the read char.
+ */
+#define READ_NEXT_BYTE(a_tknzr, a_byte_ptr) \
+status = \
+cr_input_read_byte (PRIVATE (a_tknzr)->input, a_byte_ptr) ;\
+CHECK_PARSING_STATUS (status, TRUE) ;
+
+/**
+ *Skips a given number of byte in the topmost
+ *parser input. Don't update line and column number.
+ *In case of error, jumps to the "error:" label
+ *of the surrounding function.
+ *@param a_parser the current instance of #CRTknzr.
+ *@param a_nb_bytes the number of bytes to skip.
+ */
+#define SKIP_BYTES(a_tknzr, a_nb_bytes) \
+status = cr_input_seek_index (PRIVATE (a_tknzr)->input, \
+                                     CR_SEEK_CUR, a_nb_bytes) ; \
+CHECK_PARSING_STATUS (status, TRUE) ;
+
+/**
+ *Skip utf8 encoded characters.
+ *Updates line and column numbers.
+ *@param a_parser the current instance of #CRTknzr.
+ *@param a_nb_chars the number of chars to skip. Must be of
+ *type glong.
+ */
+#define SKIP_CHARS(a_tknzr, a_nb_chars) \
+{ \
+gulong nb_chars = a_nb_chars ; \
+status = cr_input_consume_chars \
+     (PRIVATE (a_tknzr)->input,0, &nb_chars) ; \
+CHECK_PARSING_STATUS (status, TRUE) ; \
+}
+
+/**
+ *Tests the condition and if it is false, sets
+ *status to "CR_PARSING_ERROR" and goto the 'error'
+ *label.
+ *@param condition the condition to test.
+ */
+#define ENSURE_PARSING_COND(condition) \
+if (! (condition)) {status = CR_PARSING_ERROR; goto error ;}
+
+static enum CRStatus  cr_tknzr_parse_nl (CRTknzr * a_this, 
+                                         guchar ** a_start, 
+                                         guchar ** a_end,
+                                         CRParsingLocation *a_location);
+
+static enum CRStatus cr_tknzr_parse_w (CRTknzr * a_this, 
+                                       guchar ** a_start, 
+                                       guchar ** a_end,
+                                       CRParsingLocation *a_location) ;
+
+static enum CRStatus cr_tknzr_parse_unicode_escape (CRTknzr * a_this, 
+                                                    guint32 * a_unicode,
+                                                    CRParsingLocation *a_location) ;
+
+static enum CRStatus cr_tknzr_parse_escape (CRTknzr * a_this, 
+                                            guint32 * a_esc_code,
+                                            CRParsingLocation *a_location);
+
+static enum CRStatus cr_tknzr_parse_string (CRTknzr * a_this, 
+                                            CRString ** a_str);
+
+static enum CRStatus cr_tknzr_parse_comment (CRTknzr * a_this, 
+                                             CRString ** a_comment);
+
+static enum CRStatus cr_tknzr_parse_nmstart (CRTknzr * a_this, 
+                                             guint32 * a_char, 
+                                             CRParsingLocation *a_location);
+
+static enum CRStatus cr_tknzr_parse_num (CRTknzr * a_this,
+                                         CRNum ** a_num);
+
+/**********************************
+ *PRIVATE methods
+ **********************************/
+
+/**
+ *Parses a "w" as defined by the css spec at [4.1.1]:
+ * w ::= [ \t\r\n\f]*
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_start out param. Upon successfull completion, points
+ *to the beginning of the parsed white space, points to NULL otherwise.
+ *Can also point to NULL is there is no white space actually.
+ *@param a_end out param. Upon successfull completion, points
+ *to the end of the parsed white space, points to NULL otherwise.
+ *Can also point to NULL is there is no white space actually.
+ */
+static enum CRStatus
+cr_tknzr_parse_w (CRTknzr * a_this, 
+                  guchar ** a_start, 
+                  guchar ** a_end, 
+                  CRParsingLocation *a_location)
+{
+        guint32 cur_char = 0;
+        CRInputPos init_pos;
+        enum CRStatus status = CR_OK;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input
+                              && a_start && a_end, 
+                              CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        *a_start = NULL;
+        *a_end = NULL;
+
+        READ_NEXT_CHAR (a_this, &cur_char);
+
+        if (cr_utils_is_white_space (cur_char) == FALSE) {
+                status = CR_PARSING_ERROR;
+                goto error;
+        }
+        if (a_location) {
+                cr_tknzr_get_parsing_location (a_this, 
+                                               a_location) ;
+        }
+        RECORD_CUR_BYTE_ADDR (a_this, a_start);
+        *a_end = *a_start;
+
+        for (;;) {
+                gboolean is_eof = FALSE;
+
+                cr_input_get_end_of_file (PRIVATE (a_this)->input, &is_eof);
+                if (is_eof)
+                        break;
+
+                status = cr_tknzr_peek_char (a_this, &cur_char);
+                if (status == CR_END_OF_INPUT_ERROR) {
+                        break;
+                } else if (status != CR_OK) {
+                        goto error;
+                }
+
+                if (cr_utils_is_white_space (cur_char) == TRUE) {
+                        READ_NEXT_CHAR (a_this, &cur_char);
+                        RECORD_CUR_BYTE_ADDR (a_this, a_end);
+                } else {
+                        break;
+                }
+        }
+
+        return CR_OK;
+
+      error:
+        cr_tknzr_set_cur_pos (a_this, &init_pos);
+
+        return status;
+}
+
+/**
+ *Parses a newline as defined in the css2 spec:
+ * nl   ::=    \n|\r\n|\r|\f
+ *
+ *@param a_this the "this pointer" of the current instance of #CRTknzr.
+ *@param a_start a pointer to the first character of the successfully 
+ *parsed string.
+ *@param a_end a pointer to the last character of the successfully parsed
+ *string.
+ *@result CR_OK uppon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_nl (CRTknzr * a_this, 
+                   guchar ** a_start, 
+                   guchar ** a_end, 
+                   CRParsingLocation *a_location)
+{
+        CRInputPos init_pos;
+        guchar next_chars[2] = { 0 };
+        enum CRStatus status = CR_PARSING_ERROR;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_start && a_end, CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        PEEK_BYTE (a_this, 1, &next_chars[0]);
+        PEEK_BYTE (a_this, 2, &next_chars[1]);
+
+        if ((next_chars[0] == '\r' && next_chars[1] == '\n')) {
+                SKIP_BYTES (a_this, 1);
+                if (a_location) {
+                        cr_tknzr_get_parsing_location 
+                                (a_this, a_location) ;
+                }
+                SKIP_CHARS (a_this, 1);
+
+                RECORD_CUR_BYTE_ADDR (a_this, a_end);
+
+                status = CR_OK;
+        } else if (next_chars[0] == '\n'
+                   || next_chars[0] == '\r' || next_chars[0] == '\f') {
+                SKIP_CHARS (a_this, 1);
+                if (a_location) {
+                        cr_tknzr_get_parsing_location 
+                                (a_this, a_location) ;
+                }
+                RECORD_CUR_BYTE_ADDR (a_this, a_start);
+                *a_end = *a_start;
+                status = CR_OK;
+        } else {
+                status = CR_PARSING_ERROR;
+                goto error;
+        }
+        return CR_OK ;
+
+ error:
+        cr_tknzr_set_cur_pos (a_this, &init_pos) ;
+        return status;
+}
+
+/**
+ *Go ahead in the parser input, skipping all the spaces.
+ *If the next char if not a white space, this function does nothing.
+ *In any cases, it stops when it encounters a non white space character.
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_try_to_skip_spaces (CRTknzr * a_this)
+{
+        enum CRStatus status = CR_ERROR;
+        guint32 cur_char = 0;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
+
+        status = cr_input_peek_char (PRIVATE (a_this)->input, &cur_char);
+
+        if (status != CR_OK) {
+                if (status == CR_END_OF_INPUT_ERROR)
+                        return CR_OK;
+                return status;
+        }
+
+        if (cr_utils_is_white_space (cur_char) == TRUE) {
+                gulong nb_chars = -1; /*consume all spaces */
+
+                status = cr_input_consume_white_spaces
+                        (PRIVATE (a_this)->input, &nb_chars);
+        }
+
+        return status;
+}
+
+/**
+ *Parses a "comment" as defined in the css spec at [4.1.1]:
+ *COMMENT ::= \/\*[^*]*\*+([^/][^*]*\*+)*\/ .
+ *This complex regexp is just to say that comments start
+ *with the two chars '/''*' and ends with the two chars '*''/'.
+ *It also means that comments cannot be nested.
+ *So based on that, I've just tried to implement the parsing function
+ *simply and in a straight forward manner.
+ */
+static enum CRStatus
+cr_tknzr_parse_comment (CRTknzr * a_this, 
+                        CRString ** a_comment)
+{
+        enum CRStatus status = CR_OK;
+        CRInputPos init_pos;
+        guint32 cur_char = 0, next_char= 0;
+        CRString *comment = NULL;
+        CRParsingLocation loc = {0} ;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input, 
+                              CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);        
+        READ_NEXT_CHAR (a_this, &cur_char) ;        
+        ENSURE_PARSING_COND (cur_char == '/');
+        cr_tknzr_get_parsing_location (a_this, &loc) ;
+
+        READ_NEXT_CHAR (a_this, &cur_char);
+        ENSURE_PARSING_COND (cur_char == '*');
+        comment = cr_string_new ();
+        for (;;) { /* [^*]* */
+                PEEK_NEXT_CHAR (a_this, &next_char);
+                if (next_char == '*')
+                        break;
+                READ_NEXT_CHAR (a_this, &cur_char);
+                g_string_append_unichar (comment->stryng, cur_char);
+        }
+        /* Stop condition: next_char == '*' */
+        for (;;) { /* \*+ */
+                READ_NEXT_CHAR(a_this, &cur_char);
+                ENSURE_PARSING_COND (cur_char == '*');
+                g_string_append_unichar (comment->stryng, cur_char);
+                PEEK_NEXT_CHAR (a_this, &next_char);
+                if (next_char != '*')
+                        break;
+        }
+        /* Stop condition: next_char != '*' */
+        for (;;) { /* ([^/][^*]*\*+)* */
+                if (next_char == '/')
+                        break;
+                READ_NEXT_CHAR(a_this, &cur_char);
+                g_string_append_unichar (comment->stryng, cur_char);
+                for (;;) { /* [^*]* */
+                        PEEK_NEXT_CHAR (a_this, &next_char);
+                        if (next_char == '*')
+                                break;
+                        READ_NEXT_CHAR (a_this, &cur_char);
+                        g_string_append_unichar (comment->stryng, cur_char);
+                }
+                /* Stop condition: next_char = '*', no need to verify, because peek and read exit to error anyway */
+                for (;;) { /* \*+ */
+                        READ_NEXT_CHAR(a_this, &cur_char);
+                        ENSURE_PARSING_COND (cur_char == '*');
+                        g_string_append_unichar (comment->stryng, cur_char);
+                        PEEK_NEXT_CHAR (a_this, &next_char);
+                        if (next_char != '*')
+                                break;
+                }
+                /* Continue condition: next_char != '*' */
+        }
+        /* Stop condition: next_char == '\/' */
+        READ_NEXT_CHAR(a_this, &cur_char);
+        g_string_append_unichar (comment->stryng, cur_char);
+
+        if (status == CR_OK) {
+                cr_parsing_location_copy (&comment->location, 
+                                          &loc) ;
+                *a_comment = comment;                
+                return CR_OK;
+        }
+ error:
+
+        if (comment) {
+                cr_string_destroy (comment);
+                comment = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (a_this, &init_pos);
+
+        return status;
+}
+
+/**
+ *Parses an 'unicode' escape sequence defined
+ *in css spec at chap 4.1.1:
+ *unicode ::= \\[0-9a-f]{1,6}[ \n\r\t\f]?
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_start out parameter. A pointer to the start
+ *of the unicode escape sequence. Must *NOT* be deleted by
+ *the caller.
+ *@param a_end out parameter. A pointer to the last character
+ *of the unicode escape sequence. Must *NOT* be deleted by the caller.
+ *@return CR_OK if parsing succeded, an error code otherwise.
+ *Error code can be either CR_PARSING_ERROR if the string 
+ *parsed just doesn't
+ *respect the production or another error if a 
+ *lower level error occurred.
+ */
+static enum CRStatus
+cr_tknzr_parse_unicode_escape (CRTknzr * a_this, 
+                               guint32 * a_unicode,
+                               CRParsingLocation *a_location)
+{
+        guint32 cur_char;
+        CRInputPos init_pos;
+        glong occur = 0;
+        guint32 unicode = 0;
+        guchar *tmp_char_ptr1 = NULL,
+                *tmp_char_ptr2 = NULL;
+        enum CRStatus status = CR_OK;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_unicode, CR_BAD_PARAM_ERROR);
+
+        /*first, let's backup the current position pointer */
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        READ_NEXT_CHAR (a_this, &cur_char);
+
+        if (cur_char != '\\') {
+                status = CR_PARSING_ERROR;
+                goto error;
+        }
+        if (a_location) {
+                cr_tknzr_get_parsing_location 
+                        (a_this, a_location) ;
+        }
+        PEEK_NEXT_CHAR (a_this, &cur_char);
+
+        for (occur = 0, unicode = 0; ((cur_char >= '0' && cur_char <= '9')
+                                      || (cur_char >= 'a' && cur_char <= 'f')
+                                      || (cur_char >= 'A' && cur_char <= 'F'))
+             && occur < 6; occur++) {
+                gint cur_char_val = 0;
+
+                READ_NEXT_CHAR (a_this, &cur_char);
+
+                if ((cur_char >= '0' && cur_char <= '9')) {
+                        cur_char_val = (cur_char - '0');
+                } else if ((cur_char >= 'a' && cur_char <= 'f')) {
+                        cur_char_val = 10 + (cur_char - 'a');
+                } else if ((cur_char >= 'A' && cur_char <= 'F')) {
+                        cur_char_val = 10 + (cur_char - 'A');
+                }
+
+                unicode = unicode * 16 + cur_char_val;
+
+                PEEK_NEXT_CHAR (a_this, &cur_char);
+        }
+
+        /* Eat a whitespace if possible. */
+        cr_tknzr_parse_w (a_this, &tmp_char_ptr1, 
+                          &tmp_char_ptr2, NULL);
+        *a_unicode = unicode;
+        return CR_OK;
+
+      error:
+        /*
+         *restore the initial position pointer backuped at
+         *the beginning of this function.
+         */
+        cr_tknzr_set_cur_pos (a_this, &init_pos);
+
+        return status;
+}
+
+/**
+ *parses an escape sequence as defined by the css spec:
+ *escape ::= {unicode}|\\[ -~\200-\4177777]
+ *@param a_this the current instance of #CRTknzr .
+ */
+static enum CRStatus
+cr_tknzr_parse_escape (CRTknzr * a_this, guint32 * a_esc_code,
+                       CRParsingLocation *a_location)
+{
+        enum CRStatus status = CR_OK;
+        guint32 cur_char = 0;
+        CRInputPos init_pos;
+        guchar next_chars[2];
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_esc_code, CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        PEEK_BYTE (a_this, 1, &next_chars[0]);
+        PEEK_BYTE (a_this, 2, &next_chars[1]);
+
+        if (next_chars[0] != '\\') {
+                status = CR_PARSING_ERROR;
+                goto error;
+        }
+
+        if ((next_chars[1] >= '0' && next_chars[1] <= '9')
+            || (next_chars[1] >= 'a' && next_chars[1] <= 'f')
+            || (next_chars[1] >= 'A' && next_chars[1] <= 'F')) {
+                status = cr_tknzr_parse_unicode_escape (a_this, a_esc_code, 
+                                                        a_location);
+        } else {
+                /*consume the '\' char */
+                READ_NEXT_CHAR (a_this, &cur_char);
+                if (a_location) {
+                        cr_tknzr_get_parsing_location (a_this, 
+                                                       a_location) ;
+                }
+                /*then read the char after the '\' */
+                READ_NEXT_CHAR (a_this, &cur_char);
+
+                if (cur_char != ' ' && (cur_char < 200 || cur_char > 4177777)) {
+                        status = CR_PARSING_ERROR;
+                        goto error;
+                }
+                *a_esc_code = cur_char;
+
+        }
+        if (status == CR_OK) {
+                return CR_OK;
+        }
+ error:
+        cr_tknzr_set_cur_pos (a_this, &init_pos);
+        return status;
+}
+
+/**
+ *Parses a string type as defined in css spec [4.1.1]:
+ *
+ *string ::= {string1}|{string2}
+ *string1 ::= \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\"
+ *string2 ::= \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\'
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_start out parameter. Upon successfull completion, 
+ *points to the beginning of the string, points to an undefined value
+ *otherwise.
+ *@param a_end out parameter. Upon successfull completion, points to
+ *the beginning of the string, points to an undefined value otherwise.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_string (CRTknzr * a_this, CRString ** a_str)
+{
+        guint32 cur_char = 0,
+                delim = 0;
+        CRInputPos init_pos;
+        enum CRStatus status = CR_OK;
+        CRString *str = NULL;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input
+                              && a_str, CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+        READ_NEXT_CHAR (a_this, &cur_char);
+
+        if (cur_char == '"')
+                delim = '"';
+        else if (cur_char == '\'')
+                delim = '\'';
+        else {
+                status = CR_PARSING_ERROR;
+                goto error;
+        }
+        str = cr_string_new ();
+        if (str) {
+                cr_tknzr_get_parsing_location 
+                        (a_this, &str->location) ;
+        }
+        for (;;) {
+                guchar next_chars[2] = { 0 };
+
+                PEEK_BYTE (a_this, 1, &next_chars[0]);
+                PEEK_BYTE (a_this, 2, &next_chars[1]);
+
+                if (next_chars[0] == '\\') {
+                        guchar *tmp_char_ptr1 = NULL,
+                                *tmp_char_ptr2 = NULL;
+                        guint32 esc_code = 0;
+
+                        if (next_chars[1] == '\'' || next_chars[1] == '"') {
+                                g_string_append_unichar (str->stryng, 
+                                                         next_chars[1]);
+                                SKIP_BYTES (a_this, 2);
+                                status = CR_OK;
+                        } else {
+                                status = cr_tknzr_parse_escape
+                                        (a_this, &esc_code, NULL);
+
+                                if (status == CR_OK) {
+                                        g_string_append_unichar
+                                                (str->stryng, 
+                                                 esc_code);
+                                }
+                        }
+
+                        if (status != CR_OK) {
+                                /*
+                                 *consume the '\' char, and try to parse
+                                 *a newline.
+                                 */
+                                READ_NEXT_CHAR (a_this, &cur_char);
+
+                                status = cr_tknzr_parse_nl
+                                        (a_this, &tmp_char_ptr1,
+                                         &tmp_char_ptr2, NULL);
+                        }
+
+                        CHECK_PARSING_STATUS (status, FALSE);
+                } else if (strchr ("\t !#$%&", next_chars[0])
+                           || (next_chars[0] >= '(' && next_chars[0] <= '~')) {
+                        READ_NEXT_CHAR (a_this, &cur_char);
+                        g_string_append_unichar (str->stryng, 
+                                                 cur_char);
+                        status = CR_OK;
+                }
+
+                else if (cr_utils_is_nonascii (next_chars[0])) {
+                        READ_NEXT_CHAR (a_this, &cur_char);
+                        g_string_append_unichar (str->stryng, cur_char);
+                } else if (next_chars[0] == delim) {
+                        READ_NEXT_CHAR (a_this, &cur_char);
+                        break;
+                } else {
+                        status = CR_PARSING_ERROR;
+                        goto error;
+                }
+        }
+
+        if (status == CR_OK) {
+                if (*a_str == NULL) {
+                        *a_str = str;
+                        str = NULL;
+                } else {
+                        (*a_str)->stryng = g_string_append_len
+                                ((*a_str)->stryng,
+                                 str->stryng->str, 
+                                 str->stryng->len);
+                        cr_string_destroy (str);
+                }
+                return CR_OK;
+        }
+
+ error:
+
+        if (str) {
+                cr_string_destroy (str) ;
+                str = NULL;
+        }
+        cr_tknzr_set_cur_pos (a_this, &init_pos);
+        return status;
+}
+
+/**
+ *Parses the an nmstart as defined by the css2 spec [4.1.1]:
+ * nmstart [a-zA-Z]|{nonascii}|{escape}
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_start out param. A pointer to the starting point of
+ *the token.
+ *@param a_end out param. A pointer to the ending point of the
+ *token.
+ *@param a_char out param. The actual parsed nmchar.
+ *@return CR_OK upon successfull completion, 
+ *an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_nmstart (CRTknzr * a_this, 
+                        guint32 * a_char,
+                        CRParsingLocation *a_location)
+{
+        CRInputPos init_pos;
+        enum CRStatus status = CR_OK;
+        guint32 cur_char = 0,
+                next_char = 0;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input
+                              && a_char, CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        PEEK_NEXT_CHAR (a_this, &next_char);
+
+        if (next_char == '\\') {
+                status = cr_tknzr_parse_escape (a_this, a_char,
+                                                a_location);
+
+                if (status != CR_OK)
+                        goto error;
+
+        } else if (cr_utils_is_nonascii (next_char) == TRUE
+                   || ((next_char >= 'a') && (next_char <= 'z'))
+                   || ((next_char >= 'A') && (next_char <= 'Z'))
+                ) {
+                READ_NEXT_CHAR (a_this, &cur_char);
+                if (a_location) {
+                        cr_tknzr_get_parsing_location (a_this, 
+                                                       a_location) ;
+                }
+                *a_char = cur_char;
+                status = CR_OK;
+        } else {
+                status = CR_PARSING_ERROR;
+                goto error;
+        }
+
+        return CR_OK;
+
+ error:        
+        cr_tknzr_set_cur_pos (a_this, &init_pos);
+
+        return status;
+
+}
+
+/**
+ *Parses an nmchar as described in the css spec at
+ *chap 4.1.1:
+ *nmchar ::= [a-z0-9-]|{nonascii}|{escape}
+ *
+ *Humm, I have added the possibility for nmchar to
+ *contain upper case letters.
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_start out param. A pointer to the starting point of
+ *the token.
+ *@param a_end out param. A pointer to the ending point of the
+ *token.
+ *@param a_char out param. The actual parsed nmchar.
+ *@return CR_OK upon successfull completion, 
+ *an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_nmchar (CRTknzr * a_this, guint32 * a_char,
+                       CRParsingLocation *a_location)
+{
+        guint32 cur_char = 0,
+                next_char = 0;
+        enum CRStatus status = CR_OK;
+        CRInputPos init_pos;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this) && a_char,
+                              CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_input_peek_char (PRIVATE (a_this)->input, 
+                                     &next_char) ;
+        if (status != CR_OK)
+                goto error;
+
+        if (next_char == '\\') {
+                status = cr_tknzr_parse_escape (a_this, a_char, 
+                                                a_location);
+
+                if (status != CR_OK)
+                        goto error;
+
+        } else if (cr_utils_is_nonascii (next_char) == TRUE
+                   || ((next_char >= 'a') && (next_char <= 'z'))
+                   || ((next_char >= 'A') && (next_char <= 'Z'))
+                   || ((next_char >= '0') && (next_char <= '9'))
+                   || (next_char == '-')
+                   || (next_char == '_') /*'_' not allowed by the spec. */
+                ) {
+                READ_NEXT_CHAR (a_this, &cur_char);
+                *a_char = cur_char;
+                status = CR_OK;
+                if (a_location) {
+                        cr_tknzr_get_parsing_location
+                                (a_this, a_location) ;
+                }
+        } else {
+                status = CR_PARSING_ERROR;
+                goto error;
+        }
+        return CR_OK;
+
+ error:
+        cr_tknzr_set_cur_pos (a_this, &init_pos);
+        return status;
+}
+
+/**
+ *Parses an "ident" as defined in css spec [4.1.1]:
+ *ident ::= {nmstart}{nmchar}*
+ *
+ *Actually parses it using the css3 grammar:
+ *ident ::= -?{nmstart}{nmchar}*
+ *@param a_this the currens instance of #CRTknzr.
+ *
+ *@param a_str a pointer to parsed ident. If *a_str is NULL,
+ *this function allocates a new instance of CRString. If not, 
+ *the function just appends the parsed string to the one passed.
+ *In both cases it is up to the caller to free *a_str.
+ *
+ *@return CR_OK upon successfull completion, an error code 
+ *otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_ident (CRTknzr * a_this, CRString ** a_str)
+{
+        guint32 tmp_char = 0;
+        CRString *stringue = NULL ;
+        CRInputPos init_pos;
+        enum CRStatus status = CR_OK;
+        gboolean location_is_set = FALSE ;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input
+                              && a_str, CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+        PEEK_NEXT_CHAR (a_this, &tmp_char) ;
+        stringue = cr_string_new () ;
+        g_return_val_if_fail (stringue, 
+                              CR_OUT_OF_MEMORY_ERROR) ;
+
+        if (tmp_char == '-') {
+                READ_NEXT_CHAR (a_this, &tmp_char) ;
+                cr_tknzr_get_parsing_location
+                        (a_this, &stringue->location) ;
+                location_is_set = TRUE ;
+                g_string_append_unichar (stringue->stryng, 
+                                         tmp_char) ;
+        }
+        status = cr_tknzr_parse_nmstart (a_this, &tmp_char, NULL);
+        if (status != CR_OK) {
+                status = CR_PARSING_ERROR;
+                goto end ;
+        }
+        if (location_is_set == FALSE) {
+                cr_tknzr_get_parsing_location 
+                        (a_this, &stringue->location) ;
+                location_is_set = TRUE ;
+        }
+        g_string_append_unichar (stringue->stryng, tmp_char);
+        for (;;) {
+                status = cr_tknzr_parse_nmchar (a_this, 
+                                                &tmp_char, 
+                                                NULL);
+                if (status != CR_OK) {
+                        status = CR_OK ;
+                        break;
+                }
+                g_string_append_unichar (stringue->stryng, tmp_char);
+        }
+        if (status == CR_OK) {
+                if (!*a_str) {
+                        *a_str = stringue ;
+                
+                } else {
+                        g_string_append_len ((*a_str)->stryng, 
+                                             stringue->stryng->str, 
+                                             stringue->stryng->len) ;
+                        cr_string_destroy (stringue) ;
+                }
+                stringue = NULL ;
+        }
+
+ error:
+ end:
+        if (stringue) {
+                cr_string_destroy (stringue) ;
+                stringue = NULL ;
+        }
+        if (status != CR_OK ) {
+                cr_tknzr_set_cur_pos (a_this, &init_pos) ;
+        }
+        return status ;
+}
+
+
+/**
+ *Parses a "name" as defined by css spec [4.1.1]:
+ *name ::= {nmchar}+
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *
+ *@param a_str out parameter. A pointer to the successfully parsed
+ *name. If *a_str is set to NULL, this function allocates a new instance
+ *of CRString. If not, it just appends the parsed name to the passed *a_str.
+ *In both cases, it is up to the caller to free *a_str.
+ *
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_name (CRTknzr * a_this, 
+                     CRString ** a_str)
+{
+        guint32 tmp_char = 0;
+        CRInputPos init_pos;
+        enum CRStatus status = CR_OK;
+        gboolean str_needs_free = FALSE,
+                is_first_nmchar=TRUE ;
+        glong i = 0;
+        CRParsingLocation loc = {0} ;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input
+                              && a_str,
+                              CR_BAD_PARAM_ERROR) ;
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        if (*a_str == NULL) {
+                *a_str = cr_string_new ();
+                str_needs_free = TRUE;
+        }
+        for (i = 0;; i++) {
+                if (is_first_nmchar == TRUE) {
+                        status = cr_tknzr_parse_nmchar 
+                                (a_this, &tmp_char,
+                                 &loc) ;
+                        is_first_nmchar = FALSE ;
+                } else {
+                        status = cr_tknzr_parse_nmchar 
+                                (a_this, &tmp_char, NULL) ;
+                }
+                if (status != CR_OK)
+                        break;                
+                g_string_append_unichar ((*a_str)->stryng, 
+                                         tmp_char);
+        }
+        if (i > 0) {
+                cr_parsing_location_copy 
+                        (&(*a_str)->location, &loc) ;
+                return CR_OK;
+        }
+        if (str_needs_free == TRUE && *a_str) {
+                cr_string_destroy (*a_str);
+                *a_str = NULL;
+        }
+        cr_tknzr_set_cur_pos (a_this, &init_pos);
+        return CR_PARSING_ERROR;
+}
+
+/**
+ *Parses a "hash" as defined by the css spec in [4.1.1]:
+ *HASH ::= #{name}
+ */
+static enum CRStatus
+cr_tknzr_parse_hash (CRTknzr * a_this, CRString ** a_str)
+{
+        guint32 cur_char = 0;
+        CRInputPos init_pos;
+        enum CRStatus status = CR_OK;
+        gboolean str_needs_free = FALSE;
+        CRParsingLocation loc = {0} ;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input,
+                              CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+        READ_NEXT_CHAR (a_this, &cur_char);
+        if (cur_char != '#') {
+                status = CR_PARSING_ERROR;
+                goto error;
+        }
+        if (*a_str == NULL) {
+                *a_str = cr_string_new ();
+                str_needs_free = TRUE;
+        }
+        cr_tknzr_get_parsing_location (a_this,
+                                       &loc) ;
+        status = cr_tknzr_parse_name (a_this, a_str);
+        cr_parsing_location_copy (&(*a_str)->location, &loc) ;
+        if (status != CR_OK) {
+                goto error;
+        }
+        return CR_OK;
+
+ error:
+        if (str_needs_free == TRUE && *a_str) {
+                cr_string_destroy (*a_str);
+                *a_str = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (a_this, &init_pos);
+        return status;
+}
+
+/**
+ *Parses an uri as defined by the css spec [4.1.1]:
+ * URI ::= url\({w}{string}{w}\)
+ *         |url\({w}([!#$%&*-~]|{nonascii}|{escape})*{w}\)
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_str the successfully parsed url.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_uri (CRTknzr * a_this, 
+                    CRString ** a_str)
+{
+        guint32 cur_char = 0;
+        CRInputPos init_pos;
+        enum CRStatus status = CR_PARSING_ERROR;
+        guchar tab[4] = { 0 }, *tmp_ptr1 = NULL, *tmp_ptr2 = NULL;
+        CRString *str = NULL;
+        CRParsingLocation location = {0} ;
+
+        g_return_val_if_fail (a_this 
+                              && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input
+                              && a_str, 
+                              CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        PEEK_BYTE (a_this, 1, &tab[0]);
+        PEEK_BYTE (a_this, 2, &tab[1]);
+        PEEK_BYTE (a_this, 3, &tab[2]);
+        PEEK_BYTE (a_this, 4, &tab[3]);
+
+        if (tab[0] != 'u' || tab[1] != 'r' || tab[2] != 'l' || tab[3] != '(') {
+                status = CR_PARSING_ERROR;
+                goto error;
+        }
+        /*
+         *Here, we want to skip 4 bytes ('u''r''l''(').
+         *But we also need to keep track of the parsing location
+         *of the 'u'. So, we skip 1 byte, we record the parsing
+         *location, then we skip the 3 remaining bytes.
+         */
+        SKIP_CHARS (a_this, 1);
+        cr_tknzr_get_parsing_location (a_this, &location) ;
+        SKIP_CHARS (a_this, 3);
+        cr_tknzr_try_to_skip_spaces (a_this);
+        status = cr_tknzr_parse_string (a_this, a_str);
+
+        if (status == CR_OK) {
+                guint32 next_char = 0;
+                status = cr_tknzr_parse_w (a_this, &tmp_ptr1, 
+                                           &tmp_ptr2, NULL);
+                cr_tknzr_try_to_skip_spaces (a_this);
+                PEEK_NEXT_CHAR (a_this, &next_char);
+                if (next_char == ')') {
+                        READ_NEXT_CHAR (a_this, &cur_char);
+                        status = CR_OK;
+                } else {
+                        status = CR_PARSING_ERROR;
+                }
+        }
+        if (status != CR_OK) {
+                str = cr_string_new ();
+                for (;;) {
+                        guint32 next_char = 0;
+                        PEEK_NEXT_CHAR (a_this, &next_char);
+                        if (strchr ("!#$%&", next_char)
+                            || (next_char >= '*' && next_char <= '~')
+                            || (cr_utils_is_nonascii (next_char) == TRUE)) {
+                                READ_NEXT_CHAR (a_this, &cur_char);
+                                g_string_append_unichar 
+                                        (str->stryng, cur_char);
+                                status = CR_OK;
+                        } else {
+                                guint32 esc_code = 0;
+                                status = cr_tknzr_parse_escape
+                                        (a_this, &esc_code, NULL);
+                                if (status == CR_OK) {
+                                        g_string_append_unichar
+                                                (str->stryng, 
+                                                 esc_code);
+                                } else {
+                                        status = CR_OK;
+                                        break;
+                                }
+                        }
+                }
+                cr_tknzr_try_to_skip_spaces (a_this);
+                READ_NEXT_CHAR (a_this, &cur_char);
+                if (cur_char == ')') {
+                        status = CR_OK;
+                } else {
+                        status = CR_PARSING_ERROR;
+                        goto error;
+                }
+                if (str) {                        
+                        if (*a_str == NULL) {
+                                *a_str = str;
+                                str = NULL;
+                        } else {
+                                g_string_append_len
+                                        ((*a_str)->stryng,
+                                         str->stryng->str,
+                                         str->stryng->len);
+                                cr_string_destroy (str);
+                        }                        
+                }
+        }
+
+        cr_parsing_location_copy
+                (&(*a_str)->location,
+                 &location) ;
+        return CR_OK ;
+ error:
+        if (str) {
+                cr_string_destroy (str);
+                str = NULL;
+        }
+        cr_tknzr_set_cur_pos (a_this, &init_pos);
+        return status;
+}
+
+/**
+ *parses an RGB as defined in the css2 spec.
+ *rgb: rgb '('S*{num}%?S* ',' {num}#?S*,S*{num}#?S*')'
+ *
+ *@param a_this the "this pointer" of the current instance of
+ *@param a_rgb out parameter the parsed rgb.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_rgb (CRTknzr * a_this, CRRgb ** a_rgb)
+{
+        enum CRStatus status = CR_OK;
+        CRInputPos init_pos;
+        CRNum *num = NULL;
+        guchar next_bytes[3] = { 0 }, cur_byte = 0;
+        glong red = 0,
+                green = 0,
+                blue = 0,
+                i = 0;
+        gboolean is_percentage = FALSE;
+        CRParsingLocation location = {0} ;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        PEEK_BYTE (a_this, 1, &next_bytes[0]);
+        PEEK_BYTE (a_this, 2, &next_bytes[1]);
+        PEEK_BYTE (a_this, 3, &next_bytes[2]);
+
+        if (((next_bytes[0] == 'r') || (next_bytes[0] == 'R'))
+            && ((next_bytes[1] == 'g') || (next_bytes[1] == 'G'))
+            && ((next_bytes[2] == 'b') || (next_bytes[2] == 'B'))) {
+                SKIP_CHARS (a_this, 1);
+                cr_tknzr_get_parsing_location (a_this, &location) ;
+                SKIP_CHARS (a_this, 2);
+        } else {
+                status = CR_PARSING_ERROR;
+                goto error;
+        }
+        READ_NEXT_BYTE (a_this, &cur_byte);
+        ENSURE_PARSING_COND (cur_byte == '(');
+
+        cr_tknzr_try_to_skip_spaces (a_this);
+        status = cr_tknzr_parse_num (a_this, &num);
+        ENSURE_PARSING_COND ((status == CR_OK) && (num != NULL));
+
+        if (num->val > G_MAXLONG) {
+                status = CR_PARSING_ERROR;
+                goto error;
+        }
+
+        red = num->val;
+        cr_num_destroy (num);
+        num = NULL;
+
+        PEEK_BYTE (a_this, 1, &next_bytes[0]);
+        if (next_bytes[0] == '%') {
+                SKIP_CHARS (a_this, 1);
+                is_percentage = TRUE;
+        }
+        cr_tknzr_try_to_skip_spaces (a_this);
+
+        for (i = 0; i < 2; i++) {
+                READ_NEXT_BYTE (a_this, &cur_byte);
+                ENSURE_PARSING_COND (cur_byte == ',');
+
+                cr_tknzr_try_to_skip_spaces (a_this);
+                status = cr_tknzr_parse_num (a_this, &num);
+                ENSURE_PARSING_COND ((status == CR_OK) && (num != NULL));
+
+                if (num->val > G_MAXLONG) {
+                        status = CR_PARSING_ERROR;
+                        goto error;
+                }
+
+                PEEK_BYTE (a_this, 1, &next_bytes[0]);
+                if (next_bytes[0] == '%') {
+                        SKIP_CHARS (a_this, 1);
+                        is_percentage = 1;
+                }
+
+                if (i == 0) {
+                        green = num->val;
+                } else if (i == 1) {
+                        blue = num->val;
+                }
+
+                if (num) {
+                        cr_num_destroy (num);
+                        num = NULL;
+                }
+                cr_tknzr_try_to_skip_spaces (a_this);
+        }
+
+        READ_NEXT_BYTE (a_this, &cur_byte);
+        if (*a_rgb == NULL) {
+                *a_rgb = cr_rgb_new_with_vals (red, green, blue,
+                                               is_percentage);
+
+                if (*a_rgb == NULL) {
+                        status = CR_ERROR;
+                        goto error;
+                }
+                status = CR_OK;
+        } else {
+                (*a_rgb)->red = red;
+                (*a_rgb)->green = green;
+                (*a_rgb)->blue = blue;
+                (*a_rgb)->is_percentage = is_percentage;
+
+                status = CR_OK;
+        }
+
+        if (status == CR_OK) {
+                if (a_rgb && *a_rgb) {
+                        cr_parsing_location_copy 
+                                (&(*a_rgb)->location, 
+                                 &location) ;
+                }
+                return CR_OK;
+        }
+
+ error:
+        if (num) {
+                cr_num_destroy (num);
+                num = NULL;
+        }
+
+        cr_tknzr_set_cur_pos (a_this, &init_pos);
+        return CR_OK;
+}
+
+/**
+ *Parses a atkeyword as defined by the css spec in [4.1.1]:
+ *ATKEYWORD ::= @{ident}
+ *
+ *@param a_this the "this pointer" of the current instance of
+ *#CRTknzr.
+ *
+ *@param a_str out parameter. The parsed atkeyword. If *a_str is
+ *set to NULL this function allocates a new instance of CRString and
+ *sets it to the parsed atkeyword. If not, this function just appends
+ *the parsed atkeyword to the end of *a_str. In both cases it is up to
+ *the caller to free *a_str.
+ *
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_atkeyword (CRTknzr * a_this, 
+                          CRString ** a_str)
+{
+        guint32 cur_char = 0;
+        CRInputPos init_pos;
+        gboolean str_needs_free = FALSE;
+        enum CRStatus status = CR_OK;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input
+                              && a_str, CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        READ_NEXT_CHAR (a_this, &cur_char);
+
+        if (cur_char != '@') {
+                status = CR_PARSING_ERROR;
+                goto error;
+        }
+
+        if (*a_str == NULL) {
+                *a_str = cr_string_new ();
+                str_needs_free = TRUE;
+        }
+        status = cr_tknzr_parse_ident (a_this, a_str);
+        if (status != CR_OK) {
+                goto error;
+        }
+        return CR_OK;
+ error:
+
+        if (str_needs_free == TRUE && *a_str) {
+                cr_string_destroy (*a_str);
+                *a_str = NULL;
+        }
+        cr_tknzr_set_cur_pos (a_this, &init_pos);
+        return status;
+}
+
+static enum CRStatus
+cr_tknzr_parse_important (CRTknzr * a_this,
+                          CRParsingLocation *a_location)
+{
+        guint32 cur_char = 0;
+        CRInputPos init_pos;
+        enum CRStatus status = CR_OK;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input,
+                              CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+        READ_NEXT_CHAR (a_this, &cur_char);
+        ENSURE_PARSING_COND (cur_char == '!');
+        if (a_location) {
+                cr_tknzr_get_parsing_location (a_this, 
+                                               a_location) ;
+        }
+        cr_tknzr_try_to_skip_spaces (a_this);
+
+        if (BYTE (PRIVATE (a_this)->input, 1, NULL) == 'i'
+            && BYTE (PRIVATE (a_this)->input, 2, NULL) == 'm'
+            && BYTE (PRIVATE (a_this)->input, 3, NULL) == 'p'
+            && BYTE (PRIVATE (a_this)->input, 4, NULL) == 'o'
+            && BYTE (PRIVATE (a_this)->input, 5, NULL) == 'r'
+            && BYTE (PRIVATE (a_this)->input, 6, NULL) == 't'
+            && BYTE (PRIVATE (a_this)->input, 7, NULL) == 'a'
+            && BYTE (PRIVATE (a_this)->input, 8, NULL) == 'n'
+            && BYTE (PRIVATE (a_this)->input, 9, NULL) == 't') {
+                SKIP_BYTES (a_this, 9);
+                if (a_location) {
+                        cr_tknzr_get_parsing_location (a_this,
+                                                       a_location) ;
+                }
+                return CR_OK;
+        } else {
+                status = CR_PARSING_ERROR;
+        }
+
+ error:
+        cr_tknzr_set_cur_pos (a_this, &init_pos);
+
+        return status;
+}
+
+/**
+ *Parses a num as defined in the css spec [4.1.1]:
+ *[0-9]+|[0-9]*\.[0-9]+
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_num out parameter. The parsed number.
+ *@return CR_OK upon successfull completion, 
+ *an error code otherwise.
+ *
+ *The CSS specification says that numbers may be
+ *preceeded by '+' or '-' to indicate the sign.
+ *Technically, the "num" construction as defined
+ *by the tokenizer doesn't allow this, but we parse
+ *it here for simplicity.
+ */
+static enum CRStatus
+cr_tknzr_parse_num (CRTknzr * a_this, 
+                    CRNum ** a_num)
+{
+        enum CRStatus status = CR_PARSING_ERROR;
+        enum CRNumType val_type = NUM_GENERIC;
+        gboolean parsing_dec,  /* true iff seen decimal point. */
+                parsed; /* true iff the substring seen so far is a valid CSS
+                           number, i.e. `[0-9]+|[0-9]*\.[0-9]+'. */
+        guint32 cur_char = 0,
+                next_char = 0;
+        gdouble numerator, denominator = 1;
+        CRInputPos init_pos;
+        CRParsingLocation location = {0} ;
+        int sign = 1;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input, 
+                              CR_BAD_PARAM_ERROR);
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+        READ_NEXT_CHAR (a_this, &cur_char);
+
+        if (cur_char == '+' || cur_char == '-') {
+                if (cur_char == '-') {
+                        sign = -1;
+                }
+                READ_NEXT_CHAR (a_this, &cur_char);
+        }
+
+        if (IS_NUM (cur_char)) {
+                numerator = (cur_char - '0');
+                parsing_dec = FALSE;
+                parsed = TRUE;
+        } else if (cur_char == '.') {
+                numerator = 0;
+                parsing_dec = TRUE;
+                parsed = FALSE;
+        } else {
+                status = CR_PARSING_ERROR;
+                goto error;
+        }
+        cr_tknzr_get_parsing_location (a_this, &location) ;
+
+        for (;;) {
+                status = cr_tknzr_peek_char (a_this, &next_char);
+                if (status != CR_OK) {
+                        if (status == CR_END_OF_INPUT_ERROR)
+                                status = CR_OK;
+                        break;
+                }
+                if (next_char == '.') {
+                        if (parsing_dec) {
+                                status = CR_PARSING_ERROR;
+                                goto error;
+                        }
+
+                        READ_NEXT_CHAR (a_this, &cur_char);
+                        parsing_dec = TRUE;
+                        parsed = FALSE;  /* In CSS, there must be at least
+                                            one digit after `.'. */
+                } else if (IS_NUM (next_char)) {
+                        READ_NEXT_CHAR (a_this, &cur_char);
+                        parsed = TRUE;
+
+                        numerator = numerator * 10 + (cur_char - '0');
+                        if (parsing_dec) {
+                                denominator *= 10;
+                        }
+                } else {
+                        break;
+                }
+        }
+
+        if (!parsed) {
+                status = CR_PARSING_ERROR;
+        }
+
+        /*
+         *Now, set the output param values.
+         */
+        if (status == CR_OK) {
+                gdouble val = (numerator / denominator) * sign;
+                if (*a_num == NULL) {
+                        *a_num = cr_num_new_with_val (val, val_type);
+
+                        if (*a_num == NULL) {
+                                status = CR_ERROR;
+                                goto error;
+                        }
+                } else {
+                        (*a_num)->val = val;
+                        (*a_num)->type = val_type;
+                }
+                cr_parsing_location_copy (&(*a_num)->location,
+                                          &location) ;
+                return CR_OK;
+        }
+
+ error:
+
+        cr_tknzr_set_cur_pos (a_this, &init_pos);
+
+        return status;
+}
+
+/*********************************************
+ *PUBLIC methods
+ ********************************************/
+
+CRTknzr *
+cr_tknzr_new (CRInput * a_input)
+{
+        CRTknzr *result = NULL;
+
+        result = g_try_malloc (sizeof (CRTknzr));
+
+        if (result == NULL) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+
+        memset (result, 0, sizeof (CRTknzr));
+
+        result->priv = g_try_malloc (sizeof (CRTknzrPriv));
+
+        if (result->priv == NULL) {
+                cr_utils_trace_info ("Out of memory");
+
+                if (result) {
+                        g_free (result);
+                        result = NULL;
+                }
+
+                return NULL;
+        }
+        memset (result->priv, 0, sizeof (CRTknzrPriv));
+        if (a_input)
+                cr_tknzr_set_input (result, a_input);
+        return result;
+}
+
+CRTknzr *
+cr_tknzr_new_from_buf (guchar * a_buf, gulong a_len,
+                       enum CREncoding a_enc, 
+                       gboolean a_free_at_destroy)
+{
+        CRTknzr *result = NULL;
+        CRInput *input = NULL;
+
+        input = cr_input_new_from_buf (a_buf, a_len, a_enc,
+                                       a_free_at_destroy);
+
+        g_return_val_if_fail (input != NULL, NULL);
+
+        result = cr_tknzr_new (input);
+
+        return result;
+}
+
+CRTknzr *
+cr_tknzr_new_from_uri (const guchar * a_file_uri, 
+                       enum CREncoding a_enc)
+{
+        CRTknzr *result = NULL;
+        CRInput *input = NULL;
+
+        input = cr_input_new_from_uri ((const gchar *) a_file_uri, a_enc);
+        g_return_val_if_fail (input != NULL, NULL);
+
+        result = cr_tknzr_new (input);
+
+        return result;
+}
+
+void
+cr_tknzr_ref (CRTknzr * a_this)
+{
+        g_return_if_fail (a_this && PRIVATE (a_this));
+
+        PRIVATE (a_this)->ref_count++;
+}
+
+gboolean
+cr_tknzr_unref (CRTknzr * a_this)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this), FALSE);
+
+        if (PRIVATE (a_this)->ref_count > 0) {
+                PRIVATE (a_this)->ref_count--;
+        }
+
+        if (PRIVATE (a_this)->ref_count == 0) {
+                cr_tknzr_destroy (a_this);
+                return TRUE;
+        }
+
+        return FALSE;
+}
+
+enum CRStatus
+cr_tknzr_set_input (CRTknzr * a_this, CRInput * a_input)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        if (PRIVATE (a_this)->input) {
+                cr_input_unref (PRIVATE (a_this)->input);
+        }
+
+        PRIVATE (a_this)->input = a_input;
+
+        cr_input_ref (PRIVATE (a_this)->input);
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_tknzr_get_input (CRTknzr * a_this, CRInput ** a_input)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        *a_input = PRIVATE (a_this)->input;
+
+        return CR_OK;
+}
+
+/*********************************
+ *Tokenizer input handling routines
+ *********************************/
+
+/**
+ *Reads the next byte from the parser input stream.
+ *@param a_this the "this pointer" of the current instance of
+ *#CRParser.
+ *@param a_byte out parameter the place where to store the byte
+ *read.
+ *@return CR_OK upon successfull completion, an error 
+ *code otherwise.
+ */
+enum CRStatus
+cr_tknzr_read_byte (CRTknzr * a_this, guchar * a_byte)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+        return cr_input_read_byte (PRIVATE (a_this)->input, a_byte);
+
+}
+
+/**
+ *Reads the next char from the parser input stream.
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_char out parameter. The read char.
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_tknzr_read_char (CRTknzr * a_this, guint32 * a_char)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input
+                              && a_char, CR_BAD_PARAM_ERROR);
+
+        if (PRIVATE (a_this)->token_cache) {
+                cr_input_set_cur_pos (PRIVATE (a_this)->input,
+                                      &PRIVATE (a_this)->prev_pos);
+                cr_token_destroy (PRIVATE (a_this)->token_cache);
+                PRIVATE (a_this)->token_cache = NULL;
+        }
+
+        return cr_input_read_char (PRIVATE (a_this)->input, a_char);
+}
+
+/**
+ *Peeks a char from the parser input stream.
+ *To "peek a char" means reads the next char without consuming it.
+ *Subsequent calls to this function return the same char.
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_char out parameter. The peeked char uppon successfull completion.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_tknzr_peek_char (CRTknzr * a_this, guint32 * a_char)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input
+                              && a_char, CR_BAD_PARAM_ERROR);
+
+        if (PRIVATE (a_this)->token_cache) {
+                cr_input_set_cur_pos (PRIVATE (a_this)->input,
+                                      &PRIVATE (a_this)->prev_pos);
+                cr_token_destroy (PRIVATE (a_this)->token_cache);
+                PRIVATE (a_this)->token_cache = NULL;
+        }
+
+        return cr_input_peek_char (PRIVATE (a_this)->input, a_char);
+}
+
+/**
+ *Peeks a byte ahead at a given postion in the parser input stream.
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_offset the offset of the peeked byte starting from the current
+ *byte in the parser input stream.
+ *@param a_byte out parameter. The peeked byte upon 
+ *successfull completion.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_tknzr_peek_byte (CRTknzr * a_this, gulong a_offset, guchar * a_byte)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input && a_byte,
+                              CR_BAD_PARAM_ERROR);
+
+        if (PRIVATE (a_this)->token_cache) {
+                cr_input_set_cur_pos (PRIVATE (a_this)->input,
+                                      &PRIVATE (a_this)->prev_pos);
+                cr_token_destroy (PRIVATE (a_this)->token_cache);
+                PRIVATE (a_this)->token_cache = NULL;
+        }
+
+        return cr_input_peek_byte (PRIVATE (a_this)->input,
+                                   CR_SEEK_CUR, a_offset, a_byte);
+}
+
+/**
+ *Same as cr_tknzr_peek_byte() but this api returns the byte peeked.
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_offset the offset of the peeked byte starting from the current
+ *byte in the parser input stream.
+ *@param a_eof out parameter. If not NULL, is set to TRUE if we reached end of
+ *file, FALE otherwise. If the caller sets it to NULL, this parameter 
+ *is just ignored.
+ *@return the peeked byte.
+ */
+guchar
+cr_tknzr_peek_byte2 (CRTknzr * a_this, gulong a_offset, gboolean * a_eof)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input, 0);
+
+        return cr_input_peek_byte2 (PRIVATE (a_this)->input, a_offset, a_eof);
+}
+
+/**
+ *Gets the number of bytes left in the topmost input stream
+ *associated to this parser.
+ *@param a_this the current instance of #CRTknzr
+ *@return the number of bytes left or -1 in case of error.
+ */
+glong
+cr_tknzr_get_nb_bytes_left (CRTknzr * a_this)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
+
+        if (PRIVATE (a_this)->token_cache) {
+                cr_input_set_cur_pos (PRIVATE (a_this)->input,
+                                      &PRIVATE (a_this)->prev_pos);
+                cr_token_destroy (PRIVATE (a_this)->token_cache);
+                PRIVATE (a_this)->token_cache = NULL;
+        }
+
+        return cr_input_get_nb_bytes_left (PRIVATE (a_this)->input);
+}
+
+enum CRStatus
+cr_tknzr_get_cur_pos (CRTknzr * a_this, CRInputPos * a_pos)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input
+                              && a_pos, CR_BAD_PARAM_ERROR);
+
+        if (PRIVATE (a_this)->token_cache) {
+                cr_input_set_cur_pos (PRIVATE (a_this)->input,
+                                      &PRIVATE (a_this)->prev_pos);
+                cr_token_destroy (PRIVATE (a_this)->token_cache);
+                PRIVATE (a_this)->token_cache = NULL;
+        }
+
+        return cr_input_get_cur_pos (PRIVATE (a_this)->input, a_pos);
+}
+
+enum CRStatus 
+cr_tknzr_get_parsing_location (CRTknzr *a_this,
+                               CRParsingLocation *a_loc)
+{
+        g_return_val_if_fail (a_this 
+                              && PRIVATE (a_this)
+                              && a_loc,
+                              CR_BAD_PARAM_ERROR) ;
+
+        return cr_input_get_parsing_location 
+                (PRIVATE (a_this)->input, a_loc) ;
+}
+
+enum CRStatus
+cr_tknzr_get_cur_byte_addr (CRTknzr * a_this, guchar ** a_addr)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
+        if (PRIVATE (a_this)->token_cache) {
+                cr_input_set_cur_pos (PRIVATE (a_this)->input,
+                                      &PRIVATE (a_this)->prev_pos);
+                cr_token_destroy (PRIVATE (a_this)->token_cache);
+                PRIVATE (a_this)->token_cache = NULL;
+        }
+
+        return cr_input_get_cur_byte_addr (PRIVATE (a_this)->input, a_addr);
+}
+
+enum CRStatus
+cr_tknzr_seek_index (CRTknzr * a_this, enum CRSeekPos a_origin, gint a_pos)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
+
+        if (PRIVATE (a_this)->token_cache) {
+                cr_input_set_cur_pos (PRIVATE (a_this)->input,
+                                      &PRIVATE (a_this)->prev_pos);
+                cr_token_destroy (PRIVATE (a_this)->token_cache);
+                PRIVATE (a_this)->token_cache = NULL;
+        }
+
+        return cr_input_seek_index (PRIVATE (a_this)->input, a_origin, a_pos);
+}
+
+enum CRStatus
+cr_tknzr_consume_chars (CRTknzr * a_this, guint32 a_char, glong * a_nb_char)
+{
+	gulong consumed = *(gulong *) a_nb_char;
+	enum CRStatus status;
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
+
+        if (PRIVATE (a_this)->token_cache) {
+                cr_input_set_cur_pos (PRIVATE (a_this)->input,
+                                      &PRIVATE (a_this)->prev_pos);
+                cr_token_destroy (PRIVATE (a_this)->token_cache);
+                PRIVATE (a_this)->token_cache = NULL;
+        }
+
+        status = cr_input_consume_chars (PRIVATE (a_this)->input,
+                                         a_char, &consumed);
+	*a_nb_char = (glong) consumed;
+	return status;
+}
+
+enum CRStatus
+cr_tknzr_set_cur_pos (CRTknzr * a_this, CRInputPos * a_pos)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
+
+        if (PRIVATE (a_this)->token_cache) {
+                cr_token_destroy (PRIVATE (a_this)->token_cache);
+                PRIVATE (a_this)->token_cache = NULL;
+        }
+
+        return cr_input_set_cur_pos (PRIVATE (a_this)->input, a_pos);
+}
+
+enum CRStatus
+cr_tknzr_unget_token (CRTknzr * a_this, CRToken * a_token)
+{
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->token_cache == NULL,
+                              CR_BAD_PARAM_ERROR);
+
+        PRIVATE (a_this)->token_cache = a_token;
+
+        return CR_OK;
+}
+
+/**
+ *Returns the next token of the input stream.
+ *This method is really central. Each parsing
+ *method calls it.
+ *@param a_this the current tokenizer.
+ *@param a_tk out parameter. The returned token.
+ *for the sake of mem leak avoidance, *a_tk must
+ *be NULL.
+ *@param CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_tknzr_get_next_token (CRTknzr * a_this, CRToken ** a_tk)
+{
+        enum CRStatus status = CR_OK;
+        CRToken *token = NULL;
+        CRInputPos init_pos;
+        guint32 next_char = 0;
+        guchar next_bytes[4] = { 0 };
+        gboolean reached_eof = FALSE;
+        CRInput *input = NULL;
+        CRString *str = NULL;
+        CRRgb *rgb = NULL;
+        CRParsingLocation location = {0} ;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && a_tk && *a_tk == NULL
+                              && PRIVATE (a_this)->input, 
+                              CR_BAD_PARAM_ERROR);
+
+        if (PRIVATE (a_this)->token_cache) {
+                *a_tk = PRIVATE (a_this)->token_cache;
+                PRIVATE (a_this)->token_cache = NULL;
+                return CR_OK;
+        }
+
+        RECORD_INITIAL_POS (a_this, &init_pos);
+
+        status = cr_input_get_end_of_file
+                (PRIVATE (a_this)->input, &reached_eof);
+        ENSURE_PARSING_COND (status == CR_OK);
+
+        if (reached_eof == TRUE) {
+                status = CR_END_OF_INPUT_ERROR;
+                goto error;
+        }
+
+        input = PRIVATE (a_this)->input;
+
+        PEEK_NEXT_CHAR (a_this, &next_char);
+        token = cr_token_new ();
+        ENSURE_PARSING_COND (token);
+
+        switch (next_char) {
+        case '@':
+                {
+                        if (BYTE (input, 2, NULL) == 'f'
+                            && BYTE (input, 3, NULL) == 'o'
+                            && BYTE (input, 4, NULL) == 'n'
+                            && BYTE (input, 5, NULL) == 't'
+                            && BYTE (input, 6, NULL) == '-'
+                            && BYTE (input, 7, NULL) == 'f'
+                            && BYTE (input, 8, NULL) == 'a'
+                            && BYTE (input, 9, NULL) == 'c'
+                            && BYTE (input, 10, NULL) == 'e') {
+                                SKIP_CHARS (a_this, 1);
+                                cr_tknzr_get_parsing_location 
+                                        (a_this, &location) ;
+                                SKIP_CHARS (a_this, 9);
+                                status = cr_token_set_font_face_sym (token);
+                                CHECK_PARSING_STATUS (status, TRUE);
+                                cr_parsing_location_copy (&token->location,
+                                                          &location) ;
+                                goto done;
+                        }
+
+                        if (BYTE (input, 2, NULL) == 'c'
+                            && BYTE (input, 3, NULL) == 'h'
+                            && BYTE (input, 4, NULL) == 'a'
+                            && BYTE (input, 5, NULL) == 'r'
+                            && BYTE (input, 6, NULL) == 's'
+                            && BYTE (input, 7, NULL) == 'e'
+                            && BYTE (input, 8, NULL) == 't') {
+                                SKIP_CHARS (a_this, 1);
+                                cr_tknzr_get_parsing_location
+                                        (a_this, &location) ;
+                                SKIP_CHARS (a_this, 7);
+                                status = cr_token_set_charset_sym (token);
+                                CHECK_PARSING_STATUS (status, TRUE);
+                                cr_parsing_location_copy (&token->location,
+                                                          &location) ;
+                                goto done;
+                        }
+
+                        if (BYTE (input, 2, NULL) == 'i'
+                            && BYTE (input, 3, NULL) == 'm'
+                            && BYTE (input, 4, NULL) == 'p'
+                            && BYTE (input, 5, NULL) == 'o'
+                            && BYTE (input, 6, NULL) == 'r'
+                            && BYTE (input, 7, NULL) == 't') {
+                                SKIP_CHARS (a_this, 1);
+                                cr_tknzr_get_parsing_location 
+                                        (a_this, &location) ;
+                                SKIP_CHARS (a_this, 6);
+                                status = cr_token_set_import_sym (token);
+                                CHECK_PARSING_STATUS (status, TRUE);
+                                cr_parsing_location_copy (&token->location,
+                                                          &location) ;
+                                goto done;
+                        }
+
+                        if (BYTE (input, 2, NULL) == 'm'
+                            && BYTE (input, 3, NULL) == 'e'
+                            && BYTE (input, 4, NULL) == 'd'
+                            && BYTE (input, 5, NULL) == 'i'
+                            && BYTE (input, 6, NULL) == 'a') {
+                                SKIP_CHARS (a_this, 1);
+                                cr_tknzr_get_parsing_location (a_this, 
+                                                               &location) ;
+                                SKIP_CHARS (a_this, 5);
+                                status = cr_token_set_media_sym (token);
+                                CHECK_PARSING_STATUS (status, TRUE);
+                                cr_parsing_location_copy (&token->location, 
+                                                          &location) ;
+                                goto done;
+                        }
+
+                        if (BYTE (input, 2, NULL) == 'p'
+                            && BYTE (input, 3, NULL) == 'a'
+                            && BYTE (input, 4, NULL) == 'g'
+                            && BYTE (input, 5, NULL) == 'e') {
+                                SKIP_CHARS (a_this, 1);
+                                cr_tknzr_get_parsing_location (a_this, 
+                                                               &location) ;
+                                SKIP_CHARS (a_this, 4);
+                                status = cr_token_set_page_sym (token);
+                                CHECK_PARSING_STATUS (status, TRUE);
+                                cr_parsing_location_copy (&token->location, 
+                                                          &location) ;
+                                goto done;
+                        }
+                        status = cr_tknzr_parse_atkeyword (a_this, &str);
+                        if (status == CR_OK) {
+                                status = cr_token_set_atkeyword (token, str);
+                                CHECK_PARSING_STATUS (status, TRUE);
+                                if (str) {
+                                        cr_parsing_location_copy (&token->location, 
+                                                                  &str->location) ;
+                                }
+                                goto done;
+                        }
+                }
+                break;
+
+        case 'u':
+
+                if (BYTE (input, 2, NULL) == 'r'
+                    && BYTE (input, 3, NULL) == 'l'
+                    && BYTE (input, 4, NULL) == '(') {
+                        CRString *str2 = NULL;
+
+                        status = cr_tknzr_parse_uri (a_this, &str2);
+                        if (status == CR_OK) {
+                                status = cr_token_set_uri (token, str2);
+                                CHECK_PARSING_STATUS (status, TRUE);
+                                if (str2) {
+                                        cr_parsing_location_copy (&token->location,
+                                                                  &str2->location) ;
+                                }
+                                goto done;
+                        }
+                } 
+                goto fallback;
+                break;
+
+        case 'r':
+                if (BYTE (input, 2, NULL) == 'g'
+                    && BYTE (input, 3, NULL) == 'b'
+                    && BYTE (input, 4, NULL) == '(') {
+                        status = cr_tknzr_parse_rgb (a_this, &rgb);
+                        if (status == CR_OK && rgb) {
+                                status = cr_token_set_rgb (token, rgb);
+                                CHECK_PARSING_STATUS (status, TRUE);
+                                if (rgb) {
+                                        cr_parsing_location_copy (&token->location, 
+                                                                  &rgb->location) ;
+                                }
+                                rgb = NULL;
+                                goto done;
+                        }
+
+                }
+                goto fallback;
+                break;
+
+        case '<':
+                if (BYTE (input, 2, NULL) == '!'
+                    && BYTE (input, 3, NULL) == '-'
+                    && BYTE (input, 4, NULL) == '-') {
+                        SKIP_CHARS (a_this, 1);
+                        cr_tknzr_get_parsing_location (a_this, 
+                                                       &location) ;
+                        SKIP_CHARS (a_this, 3);
+                        status = cr_token_set_cdo (token);
+                        CHECK_PARSING_STATUS (status, TRUE);
+                        cr_parsing_location_copy (&token->location, 
+                                                  &location) ;
+                        goto done;
+                }
+                break;
+
+        case '-':
+                if (BYTE (input, 2, NULL) == '-'
+                    && BYTE (input, 3, NULL) == '>') {
+                        SKIP_CHARS (a_this, 1);
+                        cr_tknzr_get_parsing_location (a_this, 
+                                                       &location) ;
+                        SKIP_CHARS (a_this, 2);
+                        status = cr_token_set_cdc (token);
+                        CHECK_PARSING_STATUS (status, TRUE);
+                        cr_parsing_location_copy (&token->location, 
+                                                  &location) ;
+                        goto done;
+                } else {
+                        status = cr_tknzr_parse_ident
+                                (a_this, &str);
+                        if (status == CR_OK) {
+                                cr_token_set_ident
+                                        (token, str);
+                                if (str) {
+                                        cr_parsing_location_copy (&token->location, 
+                                                                  &str->location) ;
+                                }
+                                goto done;
+                        } else {
+                                goto parse_number;
+                        }
+                }
+                break;
+
+        case '~':
+                if (BYTE (input, 2, NULL) == '=') {
+                        SKIP_CHARS (a_this, 1);
+                        cr_tknzr_get_parsing_location (a_this, 
+                                                       &location) ;
+                        SKIP_CHARS (a_this, 1);
+                        status = cr_token_set_includes (token);
+                        CHECK_PARSING_STATUS (status, TRUE);
+                        cr_parsing_location_copy (&token->location, 
+                                                  &location) ;
+                        goto done;
+                }
+                break;
+
+        case '|':
+                if (BYTE (input, 2, NULL) == '=') {
+                        SKIP_CHARS (a_this, 1);
+                        cr_tknzr_get_parsing_location (a_this, 
+                                                       &location) ;
+                        SKIP_CHARS (a_this, 1);
+                        status = cr_token_set_dashmatch (token);
+                        CHECK_PARSING_STATUS (status, TRUE);
+                        cr_parsing_location_copy (&token->location,
+                                                  &location) ;
+                        goto done;
+                }
+                break;
+
+        case '/':
+                if (BYTE (input, 2, NULL) == '*') {
+                        status = cr_tknzr_parse_comment (a_this, &str);
+
+                        if (status == CR_OK) {
+                                status = cr_token_set_comment (token, str);
+                                str = NULL;
+                                CHECK_PARSING_STATUS (status, TRUE);
+                                if (str) {
+                                        cr_parsing_location_copy (&token->location, 
+                                                                  &str->location) ;
+                                }
+                                goto done;
+                        }
+                }
+                break ;
+
+        case ';':
+                SKIP_CHARS (a_this, 1);
+                cr_tknzr_get_parsing_location (a_this, 
+                                               &location) ;
+                status = cr_token_set_semicolon (token);
+                CHECK_PARSING_STATUS (status, TRUE);
+                cr_parsing_location_copy (&token->location, 
+                                          &location) ;
+                goto done;
+
+        case '{':
+                SKIP_CHARS (a_this, 1);
+                cr_tknzr_get_parsing_location (a_this, 
+                                               &location) ;
+                status = cr_token_set_cbo (token);
+                CHECK_PARSING_STATUS (status, TRUE);
+                cr_tknzr_get_parsing_location (a_this, 
+                                               &location) ;
+                goto done;
+
+        case '}':
+                SKIP_CHARS (a_this, 1);
+                cr_tknzr_get_parsing_location (a_this, 
+                                               &location) ;
+                status = cr_token_set_cbc (token);
+                CHECK_PARSING_STATUS (status, TRUE);
+                cr_parsing_location_copy (&token->location, 
+                                          &location) ;
+                goto done;
+
+        case '(':
+                SKIP_CHARS (a_this, 1);
+                cr_tknzr_get_parsing_location (a_this, 
+                                               &location) ;
+                status = cr_token_set_po (token);
+                CHECK_PARSING_STATUS (status, TRUE);
+                cr_parsing_location_copy (&token->location, 
+                                          &location) ;
+                goto done;
+
+        case ')':
+                SKIP_CHARS (a_this, 1);
+                cr_tknzr_get_parsing_location (a_this, 
+                                               &location) ;
+                status = cr_token_set_pc (token);
+                CHECK_PARSING_STATUS (status, TRUE);
+                cr_parsing_location_copy (&token->location, 
+                                          &location) ;
+                goto done;
+
+        case '[':
+                SKIP_CHARS (a_this, 1);
+                cr_tknzr_get_parsing_location (a_this, 
+                                               &location) ;
+                status = cr_token_set_bo (token);
+                CHECK_PARSING_STATUS (status, TRUE);
+                cr_parsing_location_copy (&token->location, 
+                                          &location) ;
+                goto done;
+
+        case ']':
+                SKIP_CHARS (a_this, 1);
+                cr_tknzr_get_parsing_location (a_this, 
+                                               &location) ;
+                status = cr_token_set_bc (token);
+                CHECK_PARSING_STATUS (status, TRUE);
+                cr_parsing_location_copy (&token->location, 
+                                          &location) ;
+                goto done;
+
+        case ' ':
+        case '\t':
+        case '\n':
+        case '\f':
+        case '\r':
+                {
+                        guchar *start = NULL,
+                                *end = NULL;
+
+                        status = cr_tknzr_parse_w (a_this, &start, 
+                                                   &end, &location);
+                        if (status == CR_OK) {
+                                status = cr_token_set_s (token);
+                                CHECK_PARSING_STATUS (status, TRUE);
+                                cr_tknzr_get_parsing_location (a_this, 
+                                                               &location) ;
+                                goto done;
+                        }
+                }
+                break;
+
+        case '#':
+                {
+                        status = cr_tknzr_parse_hash (a_this, &str);
+                        if (status == CR_OK && str) {
+                                status = cr_token_set_hash (token, str);
+                                CHECK_PARSING_STATUS (status, TRUE);
+                                if (str) {
+                                        cr_parsing_location_copy (&token->location,
+                                                                  &str->location) ;
+                                }
+                                str = NULL;
+                                goto done;
+                        }
+                }
+                break;
+
+        case '\'':
+        case '"':
+                status = cr_tknzr_parse_string (a_this, &str);
+                if (status == CR_OK && str) {
+                        status = cr_token_set_string (token, str);
+                        CHECK_PARSING_STATUS (status, TRUE);
+                        if (str) {
+                                cr_parsing_location_copy (&token->location, 
+                                                          &str->location) ;
+                        }
+                        str = NULL;
+                        goto done;
+                }
+                break;
+
+        case '!':
+                status = cr_tknzr_parse_important (a_this, &location);
+                if (status == CR_OK) {
+                        status = cr_token_set_important_sym (token);
+                        CHECK_PARSING_STATUS (status, TRUE);
+                        cr_parsing_location_copy (&token->location, 
+                                                  &location) ;
+                        goto done;
+                }
+                break;
+
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+        case '.':
+        case '+':
+        /* '-' case is handled separately above for --> comments */
+        parse_number:
+                {
+                        CRNum *num = NULL;
+
+                        status = cr_tknzr_parse_num (a_this, &num);
+                        if (status == CR_OK && num) {
+                                next_bytes[0] = BYTE (input, 1, NULL);
+                                next_bytes[1] = BYTE (input, 2, NULL);
+                                next_bytes[2] = BYTE (input, 3, NULL);
+                                next_bytes[3] = BYTE (input, 4, NULL);
+
+                                if (next_bytes[0] == 'e'
+                                    && next_bytes[1] == 'm') {
+                                        num->type = NUM_LENGTH_EM;
+                                        status = cr_token_set_ems (token,
+                                                                   num);
+                                        num = NULL;
+                                        SKIP_CHARS (a_this, 2);
+                                } else if (next_bytes[0] == 'e'
+                                           && next_bytes[1] == 'x') {
+                                        num->type = NUM_LENGTH_EX;
+                                        status = cr_token_set_exs (token,
+                                                                   num);
+                                        num = NULL;
+                                        SKIP_CHARS (a_this, 2);
+                                } else if (next_bytes[0] == 'p'
+                                           && next_bytes[1] == 'x') {
+                                        num->type = NUM_LENGTH_PX;
+                                        status = cr_token_set_length
+                                                (token, num, LENGTH_PX_ET);
+                                        num = NULL;
+                                        SKIP_CHARS (a_this, 2);
+                                } else if (next_bytes[0] == 'c'
+                                           && next_bytes[1] == 'm') {
+                                        num->type = NUM_LENGTH_CM;
+                                        status = cr_token_set_length
+                                                (token, num, LENGTH_CM_ET);
+                                        num = NULL;
+                                        SKIP_CHARS (a_this, 2);
+                                } else if (next_bytes[0] == 'm'
+                                           && next_bytes[1] == 'm') {
+                                        num->type = NUM_LENGTH_MM;
+                                        status = cr_token_set_length
+                                                (token, num, LENGTH_MM_ET);
+                                        num = NULL;
+                                        SKIP_CHARS (a_this, 2);
+                                } else if (next_bytes[0] == 'i'
+                                           && next_bytes[1] == 'n') {
+                                        num->type = NUM_LENGTH_IN;
+                                        status = cr_token_set_length
+                                                (token, num, LENGTH_IN_ET);
+                                        num = NULL;
+                                        SKIP_CHARS (a_this, 2);
+                                } else if (next_bytes[0] == 'p'
+                                           && next_bytes[1] == 't') {
+                                        num->type = NUM_LENGTH_PT;
+                                        status = cr_token_set_length
+                                                (token, num, LENGTH_PT_ET);
+                                        num = NULL;
+                                        SKIP_CHARS (a_this, 2);
+                                } else if (next_bytes[0] == 'p'
+                                           && next_bytes[1] == 'c') {
+                                        num->type = NUM_LENGTH_PC;
+                                        status = cr_token_set_length
+                                                (token, num, LENGTH_PC_ET);
+                                        num = NULL;
+                                        SKIP_CHARS (a_this, 2);
+                                } else if (next_bytes[0] == 'd'
+                                           && next_bytes[1] == 'e'
+                                           && next_bytes[2] == 'g') {
+                                        num->type = NUM_ANGLE_DEG;
+                                        status = cr_token_set_angle
+                                                (token, num, ANGLE_DEG_ET);
+                                        num = NULL;
+                                        SKIP_CHARS (a_this, 3);
+                                } else if (next_bytes[0] == 'r'
+                                           && next_bytes[1] == 'a'
+                                           && next_bytes[2] == 'd') {
+                                        num->type = NUM_ANGLE_RAD;
+                                        status = cr_token_set_angle
+                                                (token, num, ANGLE_RAD_ET);
+                                        num = NULL;
+                                        SKIP_CHARS (a_this, 3);
+                                } else if (next_bytes[0] == 'g'
+                                           && next_bytes[1] == 'r'
+                                           && next_bytes[2] == 'a'
+                                           && next_bytes[3] == 'd') {
+                                        num->type = NUM_ANGLE_GRAD;
+                                        status = cr_token_set_angle
+                                                (token, num, ANGLE_GRAD_ET);
+                                        num = NULL;
+                                        SKIP_CHARS (a_this, 4);
+                                } else if (next_bytes[0] == 'm'
+                                           && next_bytes[1] == 's') {
+                                        num->type = NUM_TIME_MS;
+                                        status = cr_token_set_time
+                                                (token, num, TIME_MS_ET);
+                                        num = NULL;
+                                        SKIP_CHARS (a_this, 2);
+                                } else if (next_bytes[0] == 's') {
+                                        num->type = NUM_TIME_S;
+                                        status = cr_token_set_time
+                                                (token, num, TIME_S_ET);
+                                        num = NULL;
+                                        SKIP_CHARS (a_this, 1);
+                                } else if (next_bytes[0] == 'H'
+                                           && next_bytes[1] == 'z') {
+                                        num->type = NUM_FREQ_HZ;
+                                        status = cr_token_set_freq
+                                                (token, num, FREQ_HZ_ET);
+                                        num = NULL;
+                                        SKIP_CHARS (a_this, 2);
+                                } else if (next_bytes[0] == 'k'
+                                           && next_bytes[1] == 'H'
+                                           && next_bytes[2] == 'z') {
+                                        num->type = NUM_FREQ_KHZ;
+                                        status = cr_token_set_freq
+                                                (token, num, FREQ_KHZ_ET);
+                                        num = NULL;
+                                        SKIP_CHARS (a_this, 3);
+                                } else if (next_bytes[0] == '%') {
+                                        num->type = NUM_PERCENTAGE;
+                                        status = cr_token_set_percentage
+                                                (token, num);
+                                        num = NULL;
+                                        SKIP_CHARS (a_this, 1);
+                                } else {
+                                        status = cr_tknzr_parse_ident (a_this,
+                                                                       &str);
+                                        if (status == CR_OK && str) {
+                                                num->type = NUM_UNKNOWN_TYPE;
+                                                status = cr_token_set_dimen
+                                                        (token, num, str);
+                                                num = NULL;
+                                                CHECK_PARSING_STATUS (status,
+                                                                      TRUE);
+                                                str = NULL;
+                                        } else {
+                                                status = cr_token_set_number
+                                                        (token, num);
+                                                num = NULL;
+                                                CHECK_PARSING_STATUS (status, CR_OK);
+                                                str = NULL;
+                                        }
+                                }
+                                if (token && token->u.num) {
+                                        cr_parsing_location_copy (&token->location,
+                                                                  &token->u.num->location) ;
+                                } else {
+                                        status = CR_ERROR ;
+                                }
+                                goto done ;
+                        }
+                }
+                break;
+
+        default:
+        fallback:
+                /*process the fallback cases here */
+
+                if (next_char == '\\'
+                    || (cr_utils_is_nonascii (next_bytes[0]) == TRUE)
+                    || ((next_char >= 'a') && (next_char <= 'z'))
+                    || ((next_char >= 'A') && (next_char <= 'Z'))) {
+                        status = cr_tknzr_parse_ident (a_this, &str);
+                        if (status == CR_OK && str) {
+                                guint32 next_c = 0;
+
+                                status = cr_input_peek_char
+                                        (PRIVATE (a_this)->input, &next_c);
+
+                                if (status == CR_OK && next_c == '(') {
+
+                                        SKIP_CHARS (a_this, 1);
+                                        status = cr_token_set_function
+                                                (token, str);
+                                        CHECK_PARSING_STATUS (status, TRUE);
+                                        /*ownership is transfered
+                                         *to token by cr_token_set_function.
+                                         */
+                                        if (str) {
+                                                cr_parsing_location_copy (&token->location, 
+                                                                          &str->location) ;
+                                        }
+                                        str = NULL;
+                                } else {
+                                        status = cr_token_set_ident (token,
+                                                                     str);
+                                        CHECK_PARSING_STATUS (status, TRUE);
+                                        if (str) {
+                                                cr_parsing_location_copy (&token->location, 
+                                                                          &str->location) ;
+                                        }
+                                        str = NULL;
+                                }
+                                goto done;
+                        } else {
+                                if (str) {
+                                        cr_string_destroy (str);
+                                        str = NULL;
+                                }
+                        }
+                }
+                break;
+        }
+
+        READ_NEXT_CHAR (a_this, &next_char);
+        cr_tknzr_get_parsing_location (a_this, 
+                                       &location) ;
+        status = cr_token_set_delim (token, next_char);
+        CHECK_PARSING_STATUS (status, TRUE);
+        cr_parsing_location_copy (&token->location, 
+                                  &location) ;
+ done:
+
+        if (status == CR_OK && token) {
+                *a_tk = token;
+                /*
+                 *store the previous position input stream pos.
+                 */
+                memmove (&PRIVATE (a_this)->prev_pos,
+                         &init_pos, sizeof (CRInputPos));
+                return CR_OK;
+        }
+
+ error:
+        if (token) {
+                cr_token_destroy (token);
+                token = NULL;
+        }
+
+        if (str) {
+                cr_string_destroy (str);
+                str = NULL;
+        }
+        cr_tknzr_set_cur_pos (a_this, &init_pos);
+        return status;
+
+}
+
+enum CRStatus
+cr_tknzr_parse_token (CRTknzr * a_this, enum CRTokenType a_type,
+                      enum CRTokenExtraType a_et, gpointer a_res,
+                      gpointer a_extra_res)
+{
+        enum CRStatus status = CR_OK;
+        CRToken *token = NULL;
+
+        g_return_val_if_fail (a_this && PRIVATE (a_this)
+                              && PRIVATE (a_this)->input
+                              && a_res, CR_BAD_PARAM_ERROR);
+
+        status = cr_tknzr_get_next_token (a_this, &token);
+        if (status != CR_OK)
+                return status;
+        if (token == NULL)
+                return CR_PARSING_ERROR;
+
+        if (token->type == a_type) {
+                switch (a_type) {
+                case NO_TK:
+                case S_TK:
+                case CDO_TK:
+                case CDC_TK:
+                case INCLUDES_TK:
+                case DASHMATCH_TK:
+                case IMPORT_SYM_TK:
+                case PAGE_SYM_TK:
+                case MEDIA_SYM_TK:
+                case FONT_FACE_SYM_TK:
+                case CHARSET_SYM_TK:
+                case IMPORTANT_SYM_TK:
+                        status = CR_OK;
+                        break;
+
+                case STRING_TK:
+                case IDENT_TK:
+                case HASH_TK:
+                case ATKEYWORD_TK:
+                case FUNCTION_TK:
+                case COMMENT_TK:
+                case URI_TK:
+                        *((CRString **) a_res) = token->u.str;
+                        token->u.str = NULL;
+                        status = CR_OK;
+                        break;
+
+                case EMS_TK:
+                case EXS_TK:
+                case PERCENTAGE_TK:
+                case NUMBER_TK:
+                        *((CRNum **) a_res) = token->u.num;
+                        token->u.num = NULL;
+                        status = CR_OK;
+                        break;
+
+                case LENGTH_TK:
+                case ANGLE_TK:
+                case TIME_TK:
+                case FREQ_TK:
+                        if (token->extra_type == a_et) {
+                                *((CRNum **) a_res) = token->u.num;
+                                token->u.num = NULL;
+                                status = CR_OK;
+                        }
+                        break;
+
+                case DIMEN_TK:
+                        *((CRNum **) a_res) = token->u.num;
+                        if (a_extra_res == NULL) {
+                                status = CR_BAD_PARAM_ERROR;
+                                goto error;
+                        }
+
+                        *((CRString **) a_extra_res) = token->dimen;
+                        token->u.num = NULL;
+                        token->dimen = NULL;
+                        status = CR_OK;
+                        break;
+
+                case DELIM_TK:
+                        *((guint32 *) a_res) = token->u.unichar;
+                        status = CR_OK;
+                        break;
+
+                case UNICODERANGE_TK:
+                default:
+                        status = CR_PARSING_ERROR;
+                        break;
+                }
+
+                cr_token_destroy (token);
+                token = NULL;
+        } else {
+                cr_tknzr_unget_token (a_this, token);
+                token = NULL;
+                status = CR_PARSING_ERROR;
+        }
+
+        return status;
+
+      error:
+
+        if (token) {
+                cr_tknzr_unget_token (a_this, token);
+                token = NULL;
+        }
+
+        return status;
+}
+
+void
+cr_tknzr_destroy (CRTknzr * a_this)
+{
+        g_return_if_fail (a_this);
+
+        if (PRIVATE (a_this) && PRIVATE (a_this)->input) {
+                if (cr_input_unref (PRIVATE (a_this)->input)
+                    == TRUE) {
+                        PRIVATE (a_this)->input = NULL;
+                }
+        }
+
+        if (PRIVATE (a_this)->token_cache) {
+                cr_token_destroy (PRIVATE (a_this)->token_cache);
+                PRIVATE (a_this)->token_cache = NULL;
+        }
+
+        if (PRIVATE (a_this)) {
+                g_free (PRIVATE (a_this));
+                PRIVATE (a_this) = NULL;
+        }
+
+        g_free (a_this);
+}
diff --git a/src/st/croco/cr-tknzr.h b/src/st/croco/cr-tknzr.h
new file mode 100644
index 000000000..13985b30e
--- /dev/null
+++ b/src/st/croco/cr-tknzr.h
@@ -0,0 +1,115 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for coypyright information.
+ */
+
+/**
+ *@file
+ *The declaration of the #CRTknzr (tokenizer)
+ *class.
+ */
+
+#ifndef __CR_TKNZR_H__
+#define __CR_TKNZR_H__
+
+#include "cr-utils.h"
+#include "cr-input.h"
+#include "cr-token.h"
+
+G_BEGIN_DECLS
+	
+	
+typedef struct _CRTknzr CRTknzr ;
+typedef struct _CRTknzrPriv CRTknzrPriv ;
+
+/**
+ *The tokenizer is the class that knows
+ *about all the css token. Its main job is
+ *to return the next token found in the character 
+ *input stream.
+ */
+struct _CRTknzr
+{
+        /*the private data of the tokenizer.*/
+        CRTknzrPriv *priv ;
+} ;
+
+CRTknzr * cr_tknzr_new (CRInput *a_input) ;
+
+CRTknzr * cr_tknzr_new_from_uri (const guchar *a_file_uri,
+                                 enum CREncoding a_enc) ;
+
+CRTknzr * cr_tknzr_new_from_buf (guchar *a_buf, gulong a_len,
+                                 enum CREncoding a_enc,
+                                 gboolean a_free_at_destroy) ;
+
+gboolean cr_tknzr_unref (CRTknzr *a_this) ;
+        
+void cr_tknzr_ref (CRTknzr *a_this) ;
+
+enum CRStatus cr_tknzr_read_byte (CRTknzr *a_this, guchar *a_byte) ;
+        
+enum CRStatus cr_tknzr_read_char (CRTknzr *a_this, guint32 *a_char);
+
+enum CRStatus cr_tknzr_peek_char (CRTknzr *a_this, guint32 *a_char) ;
+
+enum CRStatus cr_tknzr_peek_byte (CRTknzr *a_this, gulong a_offset, 
+                                  guchar *a_byte) ;
+
+guchar cr_tknzr_peek_byte2 (CRTknzr *a_this, gulong a_offset, 
+                            gboolean *a_eof) ;
+
+enum CRStatus cr_tknzr_set_cur_pos (CRTknzr *a_this, CRInputPos *a_pos) ;
+
+glong cr_tknzr_get_nb_bytes_left (CRTknzr *a_this) ;
+
+enum CRStatus cr_tknzr_get_cur_pos (CRTknzr *a_this, CRInputPos *a_pos) ;
+
+enum CRStatus cr_tknzr_get_parsing_location (CRTknzr *a_this,
+                                             CRParsingLocation *a_loc) ;
+
+enum CRStatus cr_tknzr_seek_index (CRTknzr *a_this,
+                                   enum CRSeekPos a_origin,
+                                   gint a_pos) ;
+
+enum CRStatus cr_tknzr_get_cur_byte_addr (CRTknzr *a_this, guchar **a_addr) ;
+
+
+enum CRStatus cr_tknzr_consume_chars (CRTknzr *a_this, guint32 a_char,
+                                      glong *a_nb_char) ;
+
+enum CRStatus cr_tknzr_get_next_token (CRTknzr *a_this, CRToken ** a_tk) ;
+
+enum CRStatus cr_tknzr_unget_token (CRTknzr *a_this, CRToken *a_token) ;
+
+
+enum CRStatus cr_tknzr_parse_token (CRTknzr *a_this, enum CRTokenType a_type,
+                                    enum CRTokenExtraType a_et, gpointer a_res,
+                                    gpointer a_extra_res) ;
+enum CRStatus cr_tknzr_set_input (CRTknzr *a_this, CRInput *a_input) ;
+
+enum CRStatus cr_tknzr_get_input (CRTknzr *a_this, CRInput **a_input) ;
+
+void cr_tknzr_destroy (CRTknzr *a_this) ;
+	
+G_END_DECLS
+
+#endif /*__CR_TKZNR_H__*/
diff --git a/src/st/croco/cr-token.c b/src/st/croco/cr-token.c
new file mode 100644
index 000000000..e240ab8f1
--- /dev/null
+++ b/src/st/croco/cr-token.c
@@ -0,0 +1,636 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ * 
+ * Author: Dodji Seketeli
+ * see COPYRIGHTS file for copyright information.
+ */
+
+/**
+ *@file
+ *The definition of the #CRToken class.
+ *Abstracts a css2 token.
+ */
+#include <string.h>
+#include "cr-token.h"
+
+/*
+ *TODO: write a CRToken::to_string() method.
+ */
+
+/**
+ *Frees the attributes of the current instance
+ *of #CRtoken.
+ *@param a_this the current instance of #CRToken.
+ */
+static void
+cr_token_clear (CRToken * a_this)
+{
+        g_return_if_fail (a_this);
+
+        switch (a_this->type) {
+        case S_TK:
+        case CDO_TK:
+        case CDC_TK:
+        case INCLUDES_TK:
+        case DASHMATCH_TK:
+        case PAGE_SYM_TK:
+        case MEDIA_SYM_TK:
+        case FONT_FACE_SYM_TK:
+        case CHARSET_SYM_TK:
+        case IMPORT_SYM_TK:
+        case IMPORTANT_SYM_TK:
+        case SEMICOLON_TK:
+        case NO_TK:
+        case DELIM_TK:
+        case CBO_TK:
+        case CBC_TK:
+        case BO_TK:
+        case BC_TK:
+                break;
+
+        case STRING_TK:
+        case IDENT_TK:
+        case HASH_TK:
+        case URI_TK:
+        case FUNCTION_TK:
+        case COMMENT_TK:
+        case ATKEYWORD_TK:
+                if (a_this->u.str) {
+                        cr_string_destroy (a_this->u.str);
+                        a_this->u.str = NULL;
+                }
+                break;
+
+        case EMS_TK:
+        case EXS_TK:
+        case LENGTH_TK:
+        case ANGLE_TK:
+        case TIME_TK:
+        case FREQ_TK:
+        case PERCENTAGE_TK:
+        case NUMBER_TK:
+        case PO_TK:
+        case PC_TK:
+                if (a_this->u.num) {
+                        cr_num_destroy (a_this->u.num);
+                        a_this->u.num = NULL;
+                }
+                break;
+
+        case DIMEN_TK:
+                if (a_this->u.num) {
+                        cr_num_destroy (a_this->u.num);
+                        a_this->u.num = NULL;
+                }
+
+                if (a_this->dimen) {
+                        cr_string_destroy (a_this->dimen);
+                        a_this->dimen = NULL;
+                }
+
+                break;
+
+        case RGB_TK:
+                if (a_this->u.rgb) {
+                        cr_rgb_destroy (a_this->u.rgb) ;
+                        a_this->u.rgb = NULL ;
+                }
+                break ;
+
+        case UNICODERANGE_TK:
+                /*not supported yet. */
+                break;
+
+        default:
+                cr_utils_trace_info ("I don't know how to clear this token\n") ;
+                break;
+        }
+
+        a_this->type = NO_TK;
+}
+
+/**
+ *Default constructor of
+ *the #CRToken class.
+ *@return the newly built instance of #CRToken.
+ */
+CRToken *
+cr_token_new (void)
+{
+        CRToken *result = NULL;
+
+        result = g_try_malloc (sizeof (CRToken));
+
+        if (result == NULL) {
+                cr_utils_trace_info ("Out of memory");
+                return NULL;
+        }
+
+        memset (result, 0, sizeof (CRToken));
+
+        return result;
+}
+
+/**
+ *Sets the type of curren instance of
+ *#CRToken to 'S_TK' (S in the css2 spec)
+ *@param a_this the current instance of #CRToken.
+ *@return CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_token_set_s (CRToken * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = S_TK;
+
+        return CR_OK;
+}
+
+/**
+ *Sets the type of the current instance of
+ *#CRToken to 'CDO_TK' (CDO as said by the css2 spec)
+ *@param a_this the current instance of #CRToken.
+ *@return CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_token_set_cdo (CRToken * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = CDO_TK;
+
+        return CR_OK;
+}
+
+/**
+ *Sets the type of the current token to
+ *CDC_TK (CDC as said by the css2 spec).
+ *@param a_this the current instance of #CRToken.
+ *@return CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_token_set_cdc (CRToken * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = CDC_TK;
+
+        return CR_OK;
+}
+
+/**
+ *Sets the type of the current instance of
+ *#CRToken to INCLUDES_TK (INCLUDES as said by the css2 spec).
+ *@param a_this the current instance of #CRToken.
+ *@return CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_token_set_includes (CRToken * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = INCLUDES_TK;
+
+        return CR_OK;
+}
+
+/**
+ *Sets the type of the current instance of
+ *#CRToken to DASHMATCH_TK (DASHMATCH as said by the css2 spec).
+ *@param a_this the current instance of #CRToken.
+ *@return CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_token_set_dashmatch (CRToken * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = DASHMATCH_TK;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_comment (CRToken * a_this, CRString * a_str)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+        a_this->type = COMMENT_TK;
+        a_this->u.str = a_str ;
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_string (CRToken * a_this, CRString * a_str)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = STRING_TK;
+
+        a_this->u.str = a_str ;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_ident (CRToken * a_this, CRString * a_ident)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+        a_this->type = IDENT_TK;
+        a_this->u.str = a_ident;
+        return CR_OK;
+}
+
+
+enum CRStatus
+cr_token_set_function (CRToken * a_this, CRString * a_fun_name)
+{
+        g_return_val_if_fail (a_this,
+                              CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+        a_this->type = FUNCTION_TK;
+        a_this->u.str  = a_fun_name;
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_hash (CRToken * a_this, CRString * a_hash)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+        a_this->type = HASH_TK;
+        a_this->u.str = a_hash;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_rgb (CRToken * a_this, CRRgb * a_rgb)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+        a_this->type = RGB_TK;
+        a_this->u.rgb = a_rgb;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_import_sym (CRToken * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = IMPORT_SYM_TK;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_page_sym (CRToken * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = PAGE_SYM_TK;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_media_sym (CRToken * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = MEDIA_SYM_TK;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_font_face_sym (CRToken * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+        a_this->type = FONT_FACE_SYM_TK;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_charset_sym (CRToken * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+        a_this->type = CHARSET_SYM_TK;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_atkeyword (CRToken * a_this, CRString * a_atname)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+        a_this->type = ATKEYWORD_TK;
+        a_this->u.str = a_atname;
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_important_sym (CRToken * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+        cr_token_clear (a_this);
+        a_this->type = IMPORTANT_SYM_TK;
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_ems (CRToken * a_this, CRNum * a_num)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+        cr_token_clear (a_this);
+        a_this->type = EMS_TK;
+        a_this->u.num = a_num;
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_exs (CRToken * a_this, CRNum * a_num)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+        cr_token_clear (a_this);
+        a_this->type = EXS_TK;
+        a_this->u.num = a_num;
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_length (CRToken * a_this, CRNum * a_num,
+                     enum CRTokenExtraType a_et)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = LENGTH_TK;
+        a_this->extra_type = a_et;
+        a_this->u.num = a_num;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_angle (CRToken * a_this, CRNum * a_num,
+                    enum CRTokenExtraType a_et)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = ANGLE_TK;
+        a_this->extra_type = a_et;
+        a_this->u.num = a_num;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_time (CRToken * a_this, CRNum * a_num,
+                   enum CRTokenExtraType a_et)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = TIME_TK;
+        a_this->extra_type = a_et;
+        a_this->u.num = a_num;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_freq (CRToken * a_this, CRNum * a_num,
+                   enum CRTokenExtraType a_et)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = FREQ_TK;
+        a_this->extra_type = a_et;
+        a_this->u.num = a_num;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_dimen (CRToken * a_this, CRNum * a_num, 
+                    CRString * a_dim)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+        cr_token_clear (a_this);
+        a_this->type = DIMEN_TK;
+        a_this->u.num = a_num;
+        a_this->dimen = a_dim;
+        return CR_OK;
+
+}
+
+enum CRStatus
+cr_token_set_percentage (CRToken * a_this, CRNum * a_num)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = PERCENTAGE_TK;
+        a_this->u.num = a_num;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_number (CRToken * a_this, CRNum * a_num)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = NUMBER_TK;
+        a_this->u.num = a_num;
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_uri (CRToken * a_this, CRString * a_uri)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = URI_TK;
+        a_this->u.str = a_uri;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_delim (CRToken * a_this, guint32 a_char)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = DELIM_TK;
+        a_this->u.unichar = a_char;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_semicolon (CRToken * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = SEMICOLON_TK;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_cbo (CRToken * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = CBO_TK;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_cbc (CRToken * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = CBC_TK;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_po (CRToken * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = PO_TK;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_pc (CRToken * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = PC_TK;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_bo (CRToken * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = BO_TK;
+
+        return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_bc (CRToken * a_this)
+{
+        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+        cr_token_clear (a_this);
+
+        a_this->type = BC_TK;
+
+        return CR_OK;
+}
+
+/**
+ *The destructor of the #CRToken class.
+ *@param a_this the current instance of #CRToken.
+ */
+void
+cr_token_destroy (CRToken * a_this)
+{
+        g_return_if_fail (a_this);
+
+        cr_token_clear (a_this);
+
+        g_free (a_this);
+}
diff --git a/src/st/croco/cr-token.h b/src/st/croco/cr-token.h
new file mode 100644
index 000000000..f1257b7a8
--- /dev/null
+++ b/src/st/croco/cr-token.h
@@ -0,0 +1,212 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ * 
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#ifndef __CR_TOKEN_H__
+#define __CR_TOKEN_H__
+
+#include "cr-utils.h"
+#include "cr-input.h"
+#include "cr-num.h"
+#include "cr-rgb.h"
+#include "cr-string.h"
+#include "cr-parsing-location.h"
+
+G_BEGIN_DECLS
+
+enum CRTokenType
+{
+        NO_TK,
+        S_TK,
+        CDO_TK,
+        CDC_TK,
+        INCLUDES_TK,
+        DASHMATCH_TK,
+        COMMENT_TK,
+        STRING_TK,
+        IDENT_TK,
+        HASH_TK,
+        IMPORT_SYM_TK,
+        PAGE_SYM_TK,
+        MEDIA_SYM_TK,
+        FONT_FACE_SYM_TK,
+        CHARSET_SYM_TK,
+        ATKEYWORD_TK,
+        IMPORTANT_SYM_TK,
+        EMS_TK,
+        EXS_TK,
+        LENGTH_TK,
+        ANGLE_TK,
+        TIME_TK,
+        FREQ_TK,
+        DIMEN_TK,
+        PERCENTAGE_TK,
+        NUMBER_TK,
+        RGB_TK,
+        URI_TK,
+        FUNCTION_TK,
+        UNICODERANGE_TK,
+        SEMICOLON_TK,
+        CBO_TK, /*opening curly bracket*/
+        CBC_TK, /*closing curly bracket*/
+        PO_TK, /*opening parenthesis*/
+        PC_TK, /*closing parenthesis*/
+        BO_TK, /*opening bracket*/
+        BC_TK, /*closing bracket*/
+        DELIM_TK
+} ;
+
+enum CRTokenExtraType
+{
+        NO_ET = 0,
+        LENGTH_PX_ET,
+        LENGTH_CM_ET,
+        LENGTH_MM_ET,
+        LENGTH_IN_ET,
+        LENGTH_PT_ET,
+        LENGTH_PC_ET,
+        ANGLE_DEG_ET,
+        ANGLE_RAD_ET,
+        ANGLE_GRAD_ET,
+        TIME_MS_ET,
+        TIME_S_ET,
+        FREQ_HZ_ET,
+        FREQ_KHZ_ET
+} ;
+ 
+typedef struct _CRToken CRToken ;
+
+/**
+ *This class abstracts a css2 token.
+ */
+struct _CRToken
+{
+        enum CRTokenType type ;
+        enum CRTokenExtraType extra_type ;
+        CRInputPos pos ;
+
+        union
+        {
+                CRString *str ;
+                CRRgb *rgb ;
+                CRNum *num ;
+                guint32 unichar ;
+        } u ;
+
+        CRString * dimen ;
+        CRParsingLocation location ;
+} ;
+
+CRToken* cr_token_new (void) ;
+
+enum CRStatus cr_token_set_s (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_cdo (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_cdc (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_includes (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_dashmatch (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_comment (CRToken *a_this, CRString *a_str) ;
+
+enum CRStatus cr_token_set_string (CRToken *a_this, CRString *a_str) ;
+
+enum CRStatus cr_token_set_ident (CRToken *a_this, CRString * a_ident) ;
+
+enum CRStatus cr_token_set_hash (CRToken *a_this, CRString *a_hash) ;
+
+enum CRStatus cr_token_set_rgb (CRToken *a_this, CRRgb *a_rgb) ;
+        
+enum CRStatus cr_token_set_import_sym (CRToken *a_this) ;
+        
+enum CRStatus cr_token_set_page_sym (CRToken *a_this) ;
+        
+enum CRStatus cr_token_set_media_sym (CRToken *a_this) ;
+        
+enum CRStatus cr_token_set_font_face_sym (CRToken *a_this) ;
+        
+enum CRStatus cr_token_set_charset_sym (CRToken *a_this) ;
+        
+enum CRStatus cr_token_set_atkeyword (CRToken *a_this, CRString *a_atname) ;
+        
+enum CRStatus cr_token_set_important_sym (CRToken *a_this) ;
+        
+enum CRStatus cr_token_set_ems (CRToken *a_this, CRNum *a_num) ;
+        
+enum CRStatus cr_token_set_exs (CRToken *a_this, CRNum *a_num) ;
+        
+enum CRStatus cr_token_set_length (CRToken *a_this, CRNum *a_num,
+                                   enum CRTokenExtraType a_et) ;
+        
+enum CRStatus cr_token_set_angle (CRToken *a_this, CRNum *a_num,
+                                  enum CRTokenExtraType a_et) ;
+        
+enum CRStatus cr_token_set_time (CRToken *a_this, CRNum *a_num,
+                                 enum CRTokenExtraType a_et) ;
+        
+enum CRStatus cr_token_set_freq (CRToken *a_this, CRNum *a_num,
+                                 enum CRTokenExtraType a_et) ;
+
+enum CRStatus cr_token_set_dimen (CRToken *a_this, CRNum *a_num,
+                                  CRString *a_dim) ;
+        
+enum CRStatus cr_token_set_percentage (CRToken *a_this, CRNum *a_num) ;
+        
+enum CRStatus cr_token_set_number (CRToken *a_this, CRNum *a_num) ;
+        
+enum CRStatus cr_token_set_uri (CRToken *a_this, CRString *a_uri) ;
+        
+enum CRStatus cr_token_set_function (CRToken *a_this, 
+                                     CRString *a_fun_name) ;
+        
+enum CRStatus cr_token_set_bc (CRToken *a_this) ;
+        
+enum CRStatus cr_token_set_bo (CRToken *a_this) ;
+        
+enum CRStatus cr_token_set_po (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_pc (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_cbc (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_cbo (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_semicolon (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_delim (CRToken *a_this, guint32 a_char) ;
+
+        
+/*
+  enum CRStatus
+  cr_token_set_unicoderange (CRToken *a_this, 
+  CRUnicodeRange *a_range) ;
+*/
+
+void
+cr_token_destroy (CRToken *a_this) ;
+        
+	
+G_END_DECLS
+
+#endif /*__CR_TOKEN_H__*/
diff --git a/src/st/croco/cr-utils.c b/src/st/croco/cr-utils.c
new file mode 100644
index 000000000..2420cec7c
--- /dev/null
+++ b/src/st/croco/cr-utils.c
@@ -0,0 +1,1330 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include "cr-utils.h"
+#include "cr-string.h"
+
+/**
+ *@file:
+ *Some misc utility functions used
+ *in the libcroco.
+ *Note that troughout this file I will
+ *refer to the CSS SPECIFICATIONS DOCUMENTATION
+ *written by the w3c guys. You can find that document
+ *at http://www.w3.org/TR/REC-CSS2/ .
+ */
+
+/****************************
+ *Encoding transformations and
+ *encoding helpers
+ ****************************/
+
+/*
+ *Here is the correspondance between the ucs-4 charactere codes
+ *and there matching utf-8 encoding pattern as dscribed by RFC 2279:
+ *
+ *UCS-4 range (hex.)    UTF-8 octet sequence (binary)
+ *------------------    -----------------------------
+ *0000 0000-0000 007F   0xxxxxxx
+ *0000 0080-0000 07FF   110xxxxx 10xxxxxx
+ *0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
+ *0001 0000-001F FFFF   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ *0020 0000-03FF FFFF   111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ *0400 0000-7FFF FFFF   1111110x 10xxxxxx ... 10xxxxxx
+ */
+
+/**
+ *Given an utf8 string buffer, calculates
+ *the length of this string if it was encoded
+ *in ucs4.
+ *@param a_in_start a pointer to the begining of
+ *the input utf8 string.
+ *@param a_in_end a pointre to the end of the input
+ *utf8 string (points to the last byte of the buffer)
+ *@param a_len out parameter the calculated length.
+ *@return CR_OK upon succesfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_utils_utf8_str_len_as_ucs4 (const guchar * a_in_start,
+                               const guchar * a_in_end, gulong * a_len)
+{
+        guchar *byte_ptr = NULL;
+        gint len = 0;
+
+        /*
+         *to store the final decoded 
+         *unicode char
+         */
+        guint c = 0;
+
+        g_return_val_if_fail (a_in_start && a_in_end && a_len,
+                              CR_BAD_PARAM_ERROR);
+        *a_len = 0;
+
+        for (byte_ptr = (guchar *) a_in_start;
+             byte_ptr <= a_in_end; byte_ptr++) {
+                gint nb_bytes_2_decode = 0;
+
+                if (*byte_ptr <= 0x7F) {
+                        /*
+                         *7 bits long char
+                         *encoded over 1 byte:
+                         * 0xxx xxxx
+                         */
+                        c = *byte_ptr;
+                        nb_bytes_2_decode = 1;
+
+                } else if ((*byte_ptr & 0xE0) == 0xC0) {
+                        /*
+                         *up to 11 bits long char.
+                         *encoded over 2 bytes:
+                         *110x xxxx  10xx xxxx
+                         */
+                        c = *byte_ptr & 0x1F;
+                        nb_bytes_2_decode = 2;
+
+                } else if ((*byte_ptr & 0xF0) == 0xE0) {
+                        /*
+                         *up to 16 bit long char
+                         *encoded over 3 bytes:
+                         *1110 xxxx  10xx xxxx  10xx xxxx
+                         */
+                        c = *byte_ptr & 0x0F;
+                        nb_bytes_2_decode = 3;
+
+                } else if ((*byte_ptr & 0xF8) == 0xF0) {
+                        /*
+                         *up to 21 bits long char
+                         *encoded over 4 bytes:
+                         *1111 0xxx  10xx xxxx  10xx xxxx  10xx xxxx
+                         */
+                        c = *byte_ptr & 0x7;
+                        nb_bytes_2_decode = 4;
+
+                } else if ((*byte_ptr & 0xFC) == 0xF8) {
+                        /*
+                         *up to 26 bits long char
+                         *encoded over 5 bytes.
+                         *1111 10xx  10xx xxxx  10xx xxxx  
+                         *10xx xxxx  10xx xxxx
+                         */
+                        c = *byte_ptr & 3;
+                        nb_bytes_2_decode = 5;
+
+                } else if ((*byte_ptr & 0xFE) == 0xFC) {
+                        /*
+                         *up to 31 bits long char
+                         *encoded over 6 bytes:
+                         *1111 110x  10xx xxxx  10xx xxxx  
+                         *10xx xxxx  10xx xxxx  10xx xxxx
+                         */
+                        c = *byte_ptr & 1;
+                        nb_bytes_2_decode = 6;
+
+                } else {
+                        /*
+                         *BAD ENCODING
+                         */
+                        return CR_ENCODING_ERROR;
+                }
+
+                /*
+                 *Go and decode the remaining byte(s)
+                 *(if any) to get the current character.
+                 */
+                for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) {
+                        /*decode the next byte */
+                        byte_ptr++;
+
+                        /*byte pattern must be: 10xx xxxx */
+                        if ((*byte_ptr & 0xC0) != 0x80) {
+                                return CR_ENCODING_ERROR;
+                        }
+
+                        c = (c << 6) | (*byte_ptr & 0x3F);
+                }
+
+                len++;
+        }
+
+        *a_len = len;
+
+        return CR_OK;
+}
+
+/**
+ *Given an ucs4 string, this function
+ *returns the size (in bytes) this string
+ *would have occupied if it was encoded in utf-8.
+ *@param a_in_start a pointer to the beginning of the input
+ *buffer.
+ *@param a_in_end a pointer to the end of the input buffer.
+ *@param a_len out parameter. The computed length.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_ucs4_str_len_as_utf8 (const guint32 * a_in_start,
+                               const guint32 * a_in_end, gulong * a_len)
+{
+        gint len = 0;
+        guint32 *char_ptr = NULL;
+
+        g_return_val_if_fail (a_in_start && a_in_end && a_len,
+                              CR_BAD_PARAM_ERROR);
+
+        for (char_ptr = (guint32 *) a_in_start;
+             char_ptr <= a_in_end; char_ptr++) {
+                if (*char_ptr <= 0x7F) {
+                        /*the utf-8 char would take 1 byte */
+                        len += 1;
+                } else if (*char_ptr <= 0x7FF) {
+                        /*the utf-8 char would take 2 bytes */
+                        len += 2;
+                } else if (*char_ptr <= 0xFFFF) {
+                        len += 3;
+                } else if (*char_ptr <= 0x1FFFFF) {
+                        len += 4;
+                } else if (*char_ptr <= 0x3FFFFFF) {
+                        len += 5;
+                } else if (*char_ptr <= 0x7FFFFFFF) {
+                        len += 6;
+                }
+        }
+
+        *a_len = len;
+        return CR_OK;
+}
+
+/**
+ *Given an ucsA string, this function
+ *returns the size (in bytes) this string
+ *would have occupied if it was encoded in utf-8.
+ *@param a_in_start a pointer to the beginning of the input
+ *buffer.
+ *@param a_in_end a pointer to the end of the input buffer.
+ *@param a_len out parameter. The computed length.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_ucs1_str_len_as_utf8 (const guchar * a_in_start,
+                               const guchar * a_in_end, gulong * a_len)
+{
+        gint len = 0;
+        guchar *char_ptr = NULL;
+
+        g_return_val_if_fail (a_in_start && a_in_end && a_len,
+                              CR_BAD_PARAM_ERROR);
+
+        for (char_ptr = (guchar *) a_in_start;
+             char_ptr <= a_in_end; char_ptr++) {
+                if (*char_ptr <= 0x7F) {
+                        /*the utf-8 char would take 1 byte */
+                        len += 1;
+                } else {
+                        /*the utf-8 char would take 2 bytes */
+                        len += 2;
+                }
+        }
+
+        *a_len = len;
+        return CR_OK;
+}
+
+/**
+ *Converts an utf8 buffer into an ucs4 buffer.
+ *
+ *@param a_in the input utf8 buffer to convert.
+ *@param a_in_len in/out parameter. The size of the
+ *input buffer to convert. After return, this parameter contains
+ *the actual number of bytes consumed.
+ *@param a_out the output converted ucs4 buffer. Must be allocated by
+ *the caller.
+ *@param a_out_len in/out parameter. The size of the output buffer.
+ *If this size is actually smaller than the real needed size, the function
+ *just converts what it can and returns a success status. After return,
+ *this param points to the actual number of characters decoded.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_utf8_to_ucs4 (const guchar * a_in,
+                       gulong * a_in_len, guint32 * a_out, gulong * a_out_len)
+{
+        gulong in_len = 0,
+                out_len = 0,
+                in_index = 0,
+                out_index = 0;
+        enum CRStatus status = CR_OK;
+
+        /*
+         *to store the final decoded 
+         *unicode char
+         */
+        guint c = 0;
+
+        g_return_val_if_fail (a_in && a_in_len
+                              && a_out && a_out_len, CR_BAD_PARAM_ERROR);
+
+        if (*a_in_len < 1) {
+                status = CR_OK;
+                goto end;
+        }
+
+        in_len = *a_in_len;
+        out_len = *a_out_len;
+
+        for (in_index = 0, out_index = 0;
+             (in_index < in_len) && (out_index < out_len);
+             in_index++, out_index++) {
+                gint nb_bytes_2_decode = 0;
+
+                if (a_in[in_index] <= 0x7F) {
+                        /*
+                         *7 bits long char
+                         *encoded over 1 byte:
+                         * 0xxx xxxx
+                         */
+                        c = a_in[in_index];
+                        nb_bytes_2_decode = 1;
+
+                } else if ((a_in[in_index] & 0xE0) == 0xC0) {
+                        /*
+                         *up to 11 bits long char.
+                         *encoded over 2 bytes:
+                         *110x xxxx  10xx xxxx
+                         */
+                        c = a_in[in_index] & 0x1F;
+                        nb_bytes_2_decode = 2;
+
+                } else if ((a_in[in_index] & 0xF0) == 0xE0) {
+                        /*
+                         *up to 16 bit long char
+                         *encoded over 3 bytes:
+                         *1110 xxxx  10xx xxxx  10xx xxxx
+                         */
+                        c = a_in[in_index] & 0x0F;
+                        nb_bytes_2_decode = 3;
+
+                } else if ((a_in[in_index] & 0xF8) == 0xF0) {
+                        /*
+                         *up to 21 bits long char
+                         *encoded over 4 bytes:
+                         *1111 0xxx  10xx xxxx  10xx xxxx  10xx xxxx
+                         */
+                        c = a_in[in_index] & 0x7;
+                        nb_bytes_2_decode = 4;
+
+                } else if ((a_in[in_index] & 0xFC) == 0xF8) {
+                        /*
+                         *up to 26 bits long char
+                         *encoded over 5 bytes.
+                         *1111 10xx  10xx xxxx  10xx xxxx  
+                         *10xx xxxx  10xx xxxx
+                         */
+                        c = a_in[in_index] & 3;
+                        nb_bytes_2_decode = 5;
+
+                } else if ((a_in[in_index] & 0xFE) == 0xFC) {
+                        /*
+                         *up to 31 bits long char
+                         *encoded over 6 bytes:
+                         *1111 110x  10xx xxxx  10xx xxxx  
+                         *10xx xxxx  10xx xxxx  10xx xxxx
+                         */
+                        c = a_in[in_index] & 1;
+                        nb_bytes_2_decode = 6;
+
+                } else {
+                        /*BAD ENCODING */
+                        goto end;
+                }
+
+                /*
+                 *Go and decode the remaining byte(s)
+                 *(if any) to get the current character.
+                 */
+                for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) {
+                        /*decode the next byte */
+                        in_index++;
+
+                        /*byte pattern must be: 10xx xxxx */
+                        if ((a_in[in_index] & 0xC0) != 0x80) {
+                                goto end;
+                        }
+
+                        c = (c << 6) | (a_in[in_index] & 0x3F);
+                }
+
+                /*
+                 *The decoded ucs4 char is now
+                 *in c.
+                 */
+
+                /************************
+                 *Some security tests
+                 ***********************/
+
+                /*be sure c is a char */
+                if (c == 0xFFFF || c == 0xFFFE)
+                        goto end;
+
+                /*be sure c is inferior to the max ucs4 char value */
+                if (c > 0x10FFFF)
+                        goto end;
+
+                /*
+                 *c must be less than UTF16 "lower surrogate begin"
+                 *or higher than UTF16 "High surrogate end"
+                 */
+                if (c >= 0xD800 && c <= 0xDFFF)
+                        goto end;
+
+                /*Avoid characters that equals zero */
+                if (c == 0)
+                        goto end;
+
+                a_out[out_index] = c;
+        }
+
+      end:
+        *a_out_len = out_index + 1;
+        *a_in_len = in_index + 1;
+
+        return status;
+}
+
+/**
+ *Reads a character from an utf8 buffer.
+ *Actually decode the next character code (unicode character code)
+ *and returns it.
+ *@param a_in the starting address of the utf8 buffer.
+ *@param a_in_len the length of the utf8 buffer.
+ *@param a_out output parameter. The resulting read char.
+ *@param a_consumed the number of the bytes consumed to
+ *decode the returned character code.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_read_char_from_utf8_buf (const guchar * a_in,
+                                  gulong a_in_len,
+                                  guint32 * a_out, gulong * a_consumed)
+{
+        gulong in_index = 0,
+               nb_bytes_2_decode = 0;
+        enum CRStatus status = CR_OK;
+
+        /*
+         *to store the final decoded 
+         *unicode char
+         */
+        guint32 c = 0;
+
+        g_return_val_if_fail (a_in && a_out && a_out
+                              && a_consumed, CR_BAD_PARAM_ERROR);
+
+        if (a_in_len < 1) {
+                status = CR_OK;
+                goto end;
+        }
+
+        if (*a_in <= 0x7F) {
+                /*
+                 *7 bits long char
+                 *encoded over 1 byte:
+                 * 0xxx xxxx
+                 */
+                c = *a_in;
+                nb_bytes_2_decode = 1;
+
+        } else if ((*a_in & 0xE0) == 0xC0) {
+                /*
+                 *up to 11 bits long char.
+                 *encoded over 2 bytes:
+                 *110x xxxx  10xx xxxx
+                 */
+                c = *a_in & 0x1F;
+                nb_bytes_2_decode = 2;
+
+        } else if ((*a_in & 0xF0) == 0xE0) {
+                /*
+                 *up to 16 bit long char
+                 *encoded over 3 bytes:
+                 *1110 xxxx  10xx xxxx  10xx xxxx
+                 */
+                c = *a_in & 0x0F;
+                nb_bytes_2_decode = 3;
+
+        } else if ((*a_in & 0xF8) == 0xF0) {
+                /*
+                 *up to 21 bits long char
+                 *encoded over 4 bytes:
+                 *1111 0xxx  10xx xxxx  10xx xxxx  10xx xxxx
+                 */
+                c = *a_in & 0x7;
+                nb_bytes_2_decode = 4;
+
+        } else if ((*a_in & 0xFC) == 0xF8) {
+                /*
+                 *up to 26 bits long char
+                 *encoded over 5 bytes.
+                 *1111 10xx  10xx xxxx  10xx xxxx  
+                 *10xx xxxx  10xx xxxx
+                 */
+                c = *a_in & 3;
+                nb_bytes_2_decode = 5;
+
+        } else if ((*a_in & 0xFE) == 0xFC) {
+                /*
+                 *up to 31 bits long char
+                 *encoded over 6 bytes:
+                 *1111 110x  10xx xxxx  10xx xxxx  
+                 *10xx xxxx  10xx xxxx  10xx xxxx
+                 */
+                c = *a_in & 1;
+                nb_bytes_2_decode = 6;
+
+        } else {
+                /*BAD ENCODING */
+                goto end;
+        }
+
+        if (nb_bytes_2_decode > a_in_len) {
+                status = CR_END_OF_INPUT_ERROR;
+                goto end;
+        }
+
+        /*
+         *Go and decode the remaining byte(s)
+         *(if any) to get the current character.
+         */
+        for (in_index = 1; in_index < nb_bytes_2_decode; in_index++) {
+                /*byte pattern must be: 10xx xxxx */
+                if ((a_in[in_index] & 0xC0) != 0x80) {
+                        goto end;
+                }
+
+                c = (c << 6) | (a_in[in_index] & 0x3F);
+        }
+
+        /*
+         *The decoded ucs4 char is now
+         *in c.
+         */
+
+    /************************
+     *Some security tests
+     ***********************/
+
+        /*be sure c is a char */
+        if (c == 0xFFFF || c == 0xFFFE)
+                goto end;
+
+        /*be sure c is inferior to the max ucs4 char value */
+        if (c > 0x10FFFF)
+                goto end;
+
+        /*
+         *c must be less than UTF16 "lower surrogate begin"
+         *or higher than UTF16 "High surrogate end"
+         */
+        if (c >= 0xD800 && c <= 0xDFFF)
+                goto end;
+
+        /*Avoid characters that equals zero */
+        if (c == 0)
+                goto end;
+
+        *a_out = c;
+
+      end:
+        *a_consumed = nb_bytes_2_decode;
+
+        return status;
+}
+
+/**
+ *
+ */
+enum CRStatus
+cr_utils_utf8_str_len_as_ucs1 (const guchar * a_in_start,
+                               const guchar * a_in_end, gulong * a_len)
+{
+        /*
+         *Note: this function can be made shorter
+         *but it considers all the cases of the utf8 encoding
+         *to ease further extensions ...
+         */
+
+        guchar *byte_ptr = NULL;
+        gint len = 0;
+
+        /*
+         *to store the final decoded 
+         *unicode char
+         */
+        guint c = 0;
+
+        g_return_val_if_fail (a_in_start && a_in_end && a_len,
+                              CR_BAD_PARAM_ERROR);
+        *a_len = 0;
+
+        for (byte_ptr = (guchar *) a_in_start;
+             byte_ptr <= a_in_end; byte_ptr++) {
+                gint nb_bytes_2_decode = 0;
+
+                if (*byte_ptr <= 0x7F) {
+                        /*
+                         *7 bits long char
+                         *encoded over 1 byte:
+                         * 0xxx xxxx
+                         */
+                        c = *byte_ptr;
+                        nb_bytes_2_decode = 1;
+
+                } else if ((*byte_ptr & 0xE0) == 0xC0) {
+                        /*
+                         *up to 11 bits long char.
+                         *encoded over 2 bytes:
+                         *110x xxxx  10xx xxxx
+                         */
+                        c = *byte_ptr & 0x1F;
+                        nb_bytes_2_decode = 2;
+
+                } else if ((*byte_ptr & 0xF0) == 0xE0) {
+                        /*
+                         *up to 16 bit long char
+                         *encoded over 3 bytes:
+                         *1110 xxxx  10xx xxxx  10xx xxxx
+                         */
+                        c = *byte_ptr & 0x0F;
+                        nb_bytes_2_decode = 3;
+
+                } else if ((*byte_ptr & 0xF8) == 0xF0) {
+                        /*
+                         *up to 21 bits long char
+                         *encoded over 4 bytes:
+                         *1111 0xxx  10xx xxxx  10xx xxxx  10xx xxxx
+                         */
+                        c = *byte_ptr & 0x7;
+                        nb_bytes_2_decode = 4;
+
+                } else if ((*byte_ptr & 0xFC) == 0xF8) {
+                        /*
+                         *up to 26 bits long char
+                         *encoded over 5 bytes.
+                         *1111 10xx  10xx xxxx  10xx xxxx  
+                         *10xx xxxx  10xx xxxx
+                         */
+                        c = *byte_ptr & 3;
+                        nb_bytes_2_decode = 5;
+
+                } else if ((*byte_ptr & 0xFE) == 0xFC) {
+                        /*
+                         *up to 31 bits long char
+                         *encoded over 6 bytes:
+                         *1111 110x  10xx xxxx  10xx xxxx  
+                         *10xx xxxx  10xx xxxx  10xx xxxx
+                         */
+                        c = *byte_ptr & 1;
+                        nb_bytes_2_decode = 6;
+
+                } else {
+                        /*
+                         *BAD ENCODING
+                         */
+                        return CR_ENCODING_ERROR;
+                }
+
+                /*
+                 *Go and decode the remaining byte(s)
+                 *(if any) to get the current character.
+                 */
+                for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) {
+                        /*decode the next byte */
+                        byte_ptr++;
+
+                        /*byte pattern must be: 10xx xxxx */
+                        if ((*byte_ptr & 0xC0) != 0x80) {
+                                return CR_ENCODING_ERROR;
+                        }
+
+                        c = (c << 6) | (*byte_ptr & 0x3F);
+                }
+
+                /*
+                 *The decoded ucs4 char is now
+                 *in c.
+                 */
+
+                if (c <= 0xFF) { /*Add other conditions to support
+                                  *other char sets (ucs2, ucs3, ucs4).
+                                  */
+                        len++;
+                } else {
+                        /*the char is too long to fit
+                         *into the supposed charset len.
+                         */
+                        return CR_ENCODING_ERROR;
+                }
+        }
+
+        *a_len = len;
+
+        return CR_OK;
+}
+
+/**
+ *Converts an utf8 string into an ucs4 string.
+ *@param a_in the input string to convert.
+ *@param a_in_len in/out parameter. The length of the input
+ *string. After return, points to the actual number of bytes
+ *consumed. This can be usefull to debug the input stream in case
+ *of encoding error.
+ *@param a_out out parameter. Points to the output string. It is allocated 
+ *by this function and must be freed by the caller.
+ *@param a_out_len out parameter. The length of the output string.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ *
+ */
+enum CRStatus
+cr_utils_utf8_str_to_ucs4 (const guchar * a_in,
+                           gulong * a_in_len,
+                           guint32 ** a_out, gulong * a_out_len)
+{
+        enum CRStatus status = CR_OK;
+
+        g_return_val_if_fail (a_in && a_in_len
+                              && a_out && a_out_len, CR_BAD_PARAM_ERROR);
+
+        status = cr_utils_utf8_str_len_as_ucs4 (a_in,
+                                                &a_in[*a_in_len - 1],
+                                                a_out_len);
+
+        g_return_val_if_fail (status == CR_OK, status);
+
+        *a_out = g_malloc0 (*a_out_len * sizeof (guint32));
+
+        status = cr_utils_utf8_to_ucs4 (a_in, a_in_len, *a_out, a_out_len);
+
+        return status;
+}
+
+/**
+ *Converts an ucs4 buffer into an utf8 buffer.
+ *
+ *@param a_in the input ucs4 buffer to convert.
+ *@param a_in_len in/out parameter. The size of the
+ *input buffer to convert. After return, this parameter contains
+ *the actual number of characters consumed.
+ *@param a_out the output converted utf8 buffer. Must be allocated by
+ *the caller.
+ *@param a_out_len in/out parameter. The size of the output buffer.
+ *If this size is actually smaller than the real needed size, the function
+ *just converts what it can and returns a success status. After return,
+ *this param points to the actual number of bytes in the buffer.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_ucs4_to_utf8 (const guint32 * a_in,
+                       gulong * a_in_len, guchar * a_out, gulong * a_out_len)
+{
+        gulong in_len = 0,
+                in_index = 0,
+                out_index = 0;
+        enum CRStatus status = CR_OK;
+
+        g_return_val_if_fail (a_in && a_in_len && a_out && a_out_len,
+                              CR_BAD_PARAM_ERROR);
+
+        if (*a_in_len < 1) {
+                status = CR_OK;
+                goto end;
+        }
+
+        in_len = *a_in_len;
+
+        for (in_index = 0; in_index < in_len; in_index++) {
+                /*
+                 *FIXME: return whenever we encounter forbidden char values.
+                 */
+
+                if (a_in[in_index] <= 0x7F) {
+                        a_out[out_index] = a_in[in_index];
+                        out_index++;
+                } else if (a_in[in_index] <= 0x7FF) {
+                        a_out[out_index] = (0xC0 | (a_in[in_index] >> 6));
+                        a_out[out_index + 1] =
+                                (0x80 | (a_in[in_index] & 0x3F));
+                        out_index += 2;
+                } else if (a_in[in_index] <= 0xFFFF) {
+                        a_out[out_index] = (0xE0 | (a_in[in_index] >> 12));
+                        a_out[out_index + 1] =
+                                (0x80 | ((a_in[in_index] >> 6) & 0x3F));
+                        a_out[out_index + 2] =
+                                (0x80 | (a_in[in_index] & 0x3F));
+                        out_index += 3;
+                } else if (a_in[in_index] <= 0x1FFFFF) {
+                        a_out[out_index] = (0xF0 | (a_in[in_index] >> 18));
+                        a_out[out_index + 1]
+                                = (0x80 | ((a_in[in_index] >> 12) & 0x3F));
+                        a_out[out_index + 2]
+                                = (0x80 | ((a_in[in_index] >> 6) & 0x3F));
+                        a_out[out_index + 3]
+                                = (0x80 | (a_in[in_index] & 0x3F));
+                        out_index += 4;
+                } else if (a_in[in_index] <= 0x3FFFFFF) {
+                        a_out[out_index] = (0xF8 | (a_in[in_index] >> 24));
+                        a_out[out_index + 1] =
+                                (0x80 | (a_in[in_index] >> 18));
+                        a_out[out_index + 2]
+                                = (0x80 | ((a_in[in_index] >> 12) & 0x3F));
+                        a_out[out_index + 3]
+                                = (0x80 | ((a_in[in_index] >> 6) & 0x3F));
+                        a_out[out_index + 4]
+                                = (0x80 | (a_in[in_index] & 0x3F));
+                        out_index += 5;
+                } else if (a_in[in_index] <= 0x7FFFFFFF) {
+                        a_out[out_index] = (0xFC | (a_in[in_index] >> 30));
+                        a_out[out_index + 1] =
+                                (0x80 | (a_in[in_index] >> 24));
+                        a_out[out_index + 2]
+                                = (0x80 | ((a_in[in_index] >> 18) & 0x3F));
+                        a_out[out_index + 3]
+                                = (0x80 | ((a_in[in_index] >> 12) & 0x3F));
+                        a_out[out_index + 4]
+                                = (0x80 | ((a_in[in_index] >> 6) & 0x3F));
+                        a_out[out_index + 4]
+                                = (0x80 | (a_in[in_index] & 0x3F));
+                        out_index += 6;
+                } else {
+                        status = CR_ENCODING_ERROR;
+                        goto end;
+                }
+        }                       /*end for */
+
+      end:
+        *a_in_len = in_index + 1;
+        *a_out_len = out_index + 1;
+
+        return status;
+}
+
+/**
+ *Converts an ucs4 string into an utf8 string.
+ *@param a_in the input string to convert.
+ *@param a_in_len in/out parameter. The length of the input
+ *string. After return, points to the actual number of characters
+ *consumed. This can be usefull to debug the input string in case
+ *of encoding error.
+ *@param a_out out parameter. Points to the output string. It is allocated 
+ *by this function and must be freed by the caller.
+ *@param a_out_len out parameter. The length (in bytes) of the output string.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_ucs4_str_to_utf8 (const guint32 * a_in,
+                           gulong * a_in_len,
+                           guchar ** a_out, gulong * a_out_len)
+{
+        enum CRStatus status = CR_OK;
+
+        g_return_val_if_fail (a_in && a_in_len && a_out
+                              && a_out_len, CR_BAD_PARAM_ERROR);
+
+        status = cr_utils_ucs4_str_len_as_utf8 (a_in,
+                                                &a_in[*a_out_len - 1],
+                                                a_out_len);
+
+        g_return_val_if_fail (status == CR_OK, status);
+
+        status = cr_utils_ucs4_to_utf8 (a_in, a_in_len, *a_out, a_out_len);
+
+        return status;
+}
+
+/**
+ *Converts an ucs1 buffer into an utf8 buffer.
+ *The caller must know the size of the resulting buffer and
+ *allocate it prior to calling this function.
+ *
+ *@param a_in the input ucs1 buffer.
+ *
+ *@param a_in_len in/out parameter. The length of the input buffer.
+ *After return, points to the number of bytes actually consumed even
+ *in case of encoding error.
+ *
+ *@param a_out out parameter. The output utf8 converted buffer.
+ *
+ *@param a_out_len in/out parameter. The size of the output buffer.
+ *If the output buffer size is shorter than the actual needed size, 
+ *this function just convert what it can.
+ *
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ *
+ */
+enum CRStatus
+cr_utils_ucs1_to_utf8 (const guchar * a_in,
+                       gulong * a_in_len, guchar * a_out, gulong * a_out_len)
+{
+        gulong out_index = 0,
+                in_index = 0,
+                in_len = 0,
+                out_len = 0;
+        enum CRStatus status = CR_OK;
+
+        g_return_val_if_fail (a_in && a_in_len
+                              && a_out_len, 
+                              CR_BAD_PARAM_ERROR);
+
+        if (*a_in_len == 0) {
+                *a_out_len = 0 ;
+                return status;
+        }
+        g_return_val_if_fail (a_out, CR_BAD_PARAM_ERROR) ;
+
+        in_len = *a_in_len;
+        out_len = *a_out_len;
+
+        for (in_index = 0, out_index = 0;
+             (in_index < in_len) && (out_index < out_len); in_index++) {
+                /*
+                 *FIXME: return whenever we encounter forbidden char values.
+                 */
+
+                if (a_in[in_index] <= 0x7F) {
+                        a_out[out_index] = a_in[in_index];
+                        out_index++;
+                } else {
+                        a_out[out_index] = (0xC0 | (a_in[in_index] >> 6));
+                        a_out[out_index + 1] =
+                                (0x80 | (a_in[in_index] & 0x3F));
+                        out_index += 2;
+                }
+        }                       /*end for */
+
+        *a_in_len = in_index;
+        *a_out_len = out_index;
+
+        return status;
+}
+
+/**
+ *Converts an ucs1 string into an utf8 string.
+ *@param a_in_start the beginning of the input string to convert.
+ *@param a_in_end the end of the input string to convert.
+ *@param a_out out parameter. The converted string.
+ *@param a_out out parameter. The length of the converted string.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ *
+ */
+enum CRStatus
+cr_utils_ucs1_str_to_utf8 (const guchar * a_in,
+                           gulong * a_in_len,
+                           guchar ** a_out, gulong * a_out_len)
+{
+        gulong out_len = 0;
+        enum CRStatus status = CR_OK;
+
+        g_return_val_if_fail (a_in && a_in_len && a_out
+                              && a_out_len, CR_BAD_PARAM_ERROR);
+
+        if (*a_in_len < 1) {
+                *a_out_len = 0;
+                *a_out = NULL;
+                return CR_OK;
+        }
+
+        status = cr_utils_ucs1_str_len_as_utf8 (a_in, &a_in[*a_in_len - 1],
+                                                &out_len);
+
+        g_return_val_if_fail (status == CR_OK, status);
+
+        *a_out = g_malloc0 (out_len);
+
+        status = cr_utils_ucs1_to_utf8 (a_in, a_in_len, *a_out, &out_len);
+
+        *a_out_len = out_len;
+
+        return status;
+}
+
+/**
+ *Converts an utf8 buffer into an ucs1 buffer.
+ *The caller must know the size of the resulting
+ *converted buffer, and allocated it prior to calling this
+ *function.
+ *
+ *@param a_in the input utf8 buffer to convert.
+ *
+ *@param a_in_len in/out parameter. The size of the input utf8 buffer.
+ *After return, points to the number of bytes consumed
+ *by the function even in case of encoding error.
+ *
+ *@param a_out out parameter. Points to the resulting buffer.
+ *Must be allocated by the caller. If the size of a_out is shorter
+ *than its required size, this function converts what it can and return
+ *a successfull status.
+ *
+ *@param a_out_len in/out parameter. The size of the output buffer.
+ *After return, points to the number of bytes consumed even in case of
+ *encoding error.
+ *
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_utf8_to_ucs1 (const guchar * a_in,
+                       gulong * a_in_len, guchar * a_out, gulong * a_out_len)
+{
+        gulong in_index = 0,
+                out_index = 0,
+                in_len = 0,
+                out_len = 0;
+        enum CRStatus status = CR_OK;
+
+        /*
+         *to store the final decoded 
+         *unicode char
+         */
+        guint32 c = 0;
+
+        g_return_val_if_fail (a_in && a_in_len
+                              && a_out && a_out_len, CR_BAD_PARAM_ERROR);
+
+        if (*a_in_len < 1) {
+                goto end;
+        }
+
+        in_len = *a_in_len;
+        out_len = *a_out_len;
+
+        for (in_index = 0, out_index = 0;
+             (in_index < in_len) && (out_index < out_len);
+             in_index++, out_index++) {
+                gint nb_bytes_2_decode = 0;
+
+                if (a_in[in_index] <= 0x7F) {
+                        /*
+                         *7 bits long char
+                         *encoded over 1 byte:
+                         * 0xxx xxxx
+                         */
+                        c = a_in[in_index];
+                        nb_bytes_2_decode = 1;
+
+                } else if ((a_in[in_index] & 0xE0) == 0xC0) {
+                        /*
+                         *up to 11 bits long char.
+                         *encoded over 2 bytes:
+                         *110x xxxx  10xx xxxx
+                         */
+                        c = a_in[in_index] & 0x1F;
+                        nb_bytes_2_decode = 2;
+
+                } else if ((a_in[in_index] & 0xF0) == 0xE0) {
+                        /*
+                         *up to 16 bit long char
+                         *encoded over 3 bytes:
+                         *1110 xxxx  10xx xxxx  10xx xxxx
+                         */
+                        c = a_in[in_index] & 0x0F;
+                        nb_bytes_2_decode = 3;
+
+                } else if ((a_in[in_index] & 0xF8) == 0xF0) {
+                        /*
+                         *up to 21 bits long char
+                         *encoded over 4 bytes:
+                         *1111 0xxx  10xx xxxx  10xx xxxx  10xx xxxx
+                         */
+                        c = a_in[in_index] & 0x7;
+                        nb_bytes_2_decode = 4;
+
+                } else if ((a_in[in_index] & 0xFC) == 0xF8) {
+                        /*
+                         *up to 26 bits long char
+                         *encoded over 5 bytes.
+                         *1111 10xx  10xx xxxx  10xx xxxx  
+                         *10xx xxxx  10xx xxxx
+                         */
+                        c = a_in[in_index] & 3;
+                        nb_bytes_2_decode = 5;
+
+                } else if ((a_in[in_index] & 0xFE) == 0xFC) {
+                        /*
+                         *up to 31 bits long char
+                         *encoded over 6 bytes:
+                         *1111 110x  10xx xxxx  10xx xxxx  
+                         *10xx xxxx  10xx xxxx  10xx xxxx
+                         */
+                        c = a_in[in_index] & 1;
+                        nb_bytes_2_decode = 6;
+
+                } else {
+                        /*BAD ENCODING */
+                        status = CR_ENCODING_ERROR;
+                        goto end;
+                }
+
+                /*
+                 *Go and decode the remaining byte(s)
+                 *(if any) to get the current character.
+                 */
+                if (in_index + nb_bytes_2_decode - 1 >= in_len) {
+                        goto end;
+                }
+
+                for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) {
+                        /*decode the next byte */
+                        in_index++;
+
+                        /*byte pattern must be: 10xx xxxx */
+                        if ((a_in[in_index] & 0xC0) != 0x80) {
+                                status = CR_ENCODING_ERROR;
+                                goto end;
+                        }
+
+                        c = (c << 6) | (a_in[in_index] & 0x3F);
+                }
+
+                /*
+                 *The decoded ucs4 char is now
+                 *in c.
+                 */
+
+                if (c > 0xFF) {
+                        status = CR_ENCODING_ERROR;
+                        goto end;
+                }
+
+                a_out[out_index] = c;
+        }
+
+      end:
+        *a_out_len = out_index;
+        *a_in_len = in_index;
+
+        return status;
+}
+
+/**
+ *Converts an utf8 buffer into an
+ *ucs1 buffer.
+ *@param a_in_start the start of the input buffer.
+ *@param a_in_end the end of the input buffer.
+ *@param a_out out parameter. The resulting converted ucs4 buffer.
+ *Must be freed by the caller.
+ *@param a_out_len out parameter. The length of the converted buffer.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ *Note that out parameters are valid if and only if this function
+ *returns CR_OK.
+ */
+enum CRStatus
+cr_utils_utf8_str_to_ucs1 (const guchar * a_in,
+                           gulong * a_in_len,
+                           guchar ** a_out, gulong * a_out_len)
+{
+        enum CRStatus status = CR_OK;
+
+        g_return_val_if_fail (a_in && a_in_len
+                              && a_out && a_out_len, CR_BAD_PARAM_ERROR);
+
+        if (*a_in_len < 1) {
+                *a_out_len = 0;
+                *a_out = NULL;
+                return CR_OK;
+        }
+
+        status = cr_utils_utf8_str_len_as_ucs4 (a_in, &a_in[*a_in_len - 1],
+                                                a_out_len);
+
+        g_return_val_if_fail (status == CR_OK, status);
+
+        *a_out = g_malloc0 (*a_out_len * sizeof (guint32));
+
+        status = cr_utils_utf8_to_ucs1 (a_in, a_in_len, *a_out, a_out_len);
+        return status;
+}
+
+/*****************************************
+ *CSS basic types identification utilities
+ *****************************************/
+
+/**
+ *Returns TRUE if a_char is a white space as
+ *defined in the css spec in chap 4.1.1.
+ *
+ *white-space ::= ' '| \t|\r|\n|\f
+ *
+ *@param a_char the character to test.
+ *return TRUE if is a white space, false otherwise.
+ */
+gboolean
+cr_utils_is_white_space (guint32 a_char)
+{
+        switch (a_char) {
+        case ' ':
+        case '\t':
+        case '\r':
+        case '\n':
+        case '\f':
+                return TRUE;
+                break;
+        default:
+                return FALSE;
+        }
+}
+
+/**
+ *Returns true if the character is a newline
+ *as defined in the css spec in the chap 4.1.1.
+ *
+ *nl ::= \n|\r\n|\r|\f
+ *
+ *@param a_char the character to test.
+ *@return TRUE if the character is a newline, FALSE otherwise.
+ */
+gboolean
+cr_utils_is_newline (guint32 a_char)
+{
+        switch (a_char) {
+        case '\n':
+        case '\r':
+        case '\f':
+                return TRUE;
+                break;
+        default:
+                return FALSE;
+        }
+}
+
+/**
+ *returns TRUE if the char is part of an hexa num char:
+ *i.e hexa_char ::= [0-9A-F]
+ */
+gboolean
+cr_utils_is_hexa_char (guint32 a_char)
+{
+        if ((a_char >= '0' && a_char <= '9')
+            || (a_char >= 'A' && a_char <= 'F')) {
+                return TRUE;
+        }
+        return FALSE;
+}
+
+/**
+ *Returns true if the character is a nonascii
+ *character (as defined in the css spec chap 4.1.1):
+ *
+ *nonascii ::= [^\0-\177]
+ *
+ *@param a_char the character to test.
+ *@return TRUE if the character is a nonascii char,
+ *FALSE otherwise.
+ */
+gboolean
+cr_utils_is_nonascii (guint32 a_char)
+{
+        if (a_char <= 177) {
+                return FALSE;
+        }
+
+        return TRUE;
+}
+
+/**
+ *Dumps a character a_nb times on a file.
+ *@param a_char the char to dump
+ *@param a_fp the destination file pointer
+ *@param a_nb the number of times a_char is to be dumped.
+ */
+void
+cr_utils_dump_n_chars (guchar a_char, FILE * a_fp, glong a_nb)
+{
+        glong i = 0;
+
+        for (i = 0; i < a_nb; i++) {
+                fprintf (a_fp, "%c", a_char);
+        }
+}
+
+void
+cr_utils_dump_n_chars2 (guchar a_char, GString * a_string, glong a_nb)
+{
+        glong i = 0;
+
+        g_return_if_fail (a_string);
+
+        for (i = 0; i < a_nb; i++) {
+                g_string_append_printf (a_string, "%c", a_char);
+        }
+}
+
+/**
+ *Duplicates a list of GString instances.
+ *@return the duplicated list of GString instances or NULL if
+ *something bad happened.
+ *@param a_list_of_strings the list of strings to be duplicated.
+ */
+GList *
+cr_utils_dup_glist_of_string (GList const * a_list_of_strings)
+{
+        GList const *cur = NULL;
+        GList *result = NULL;
+
+        g_return_val_if_fail (a_list_of_strings, NULL);
+
+        for (cur = a_list_of_strings; cur; cur = cur->next) {
+                GString *str = NULL;
+
+                str = g_string_new_len (((GString *) cur->data)->str,
+                                        ((GString *) cur->data)->len);
+                if (str)
+                        result = g_list_append (result, str);
+        }
+
+        return result;
+}
+
+/**
+ *Duplicate a GList where the GList::data is a CRString.
+ *@param a_list_of_strings the list to duplicate
+ *@return the duplicated list, or NULL if something bad
+ *happened.
+ */
+GList *
+cr_utils_dup_glist_of_cr_string (GList const * a_list_of_strings)
+{
+        GList const *cur = NULL;
+        GList *result = NULL;
+
+        g_return_val_if_fail (a_list_of_strings, NULL);
+
+        for (cur = a_list_of_strings; cur; cur = cur->next) {
+                CRString *str = NULL;
+
+                str = cr_string_dup ((CRString const *) cur->data) ;
+                if (str)
+                        result = g_list_append (result, str);
+        }
+
+        return result;
+}
diff --git a/src/st/croco/cr-utils.h b/src/st/croco/cr-utils.h
new file mode 100644
index 000000000..54aa24973
--- /dev/null
+++ b/src/st/croco/cr-utils.h
@@ -0,0 +1,246 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * Look at file COPYRIGHTS for copyright information
+ */
+
+#ifndef __CR_DEFS_H__
+#define __CR_DEFS_H__
+
+#include <stdio.h>
+#include <glib.h>
+#include "libcroco-config.h"
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *The Croco library basic types definitions
+ *And global definitions.
+ */
+
+/**
+ *The status type returned
+ *by the methods of the croco library.
+ */
+enum CRStatus {
+        CR_OK,
+        CR_BAD_PARAM_ERROR,
+        CR_INSTANCIATION_FAILED_ERROR,
+        CR_UNKNOWN_TYPE_ERROR,
+        CR_UNKNOWN_PROP_ERROR,
+        CR_UNKNOWN_PROP_VAL_ERROR,
+        CR_UNEXPECTED_POSITION_SCHEME,
+        CR_START_OF_INPUT_ERROR,
+        CR_END_OF_INPUT_ERROR,
+        CR_OUTPUT_TOO_SHORT_ERROR,
+        CR_INPUT_TOO_SHORT_ERROR,
+        CR_OUT_OF_BOUNDS_ERROR,
+        CR_EMPTY_PARSER_INPUT_ERROR,
+        CR_ENCODING_ERROR,
+        CR_ENCODING_NOT_FOUND_ERROR,
+        CR_PARSING_ERROR,
+        CR_SYNTAX_ERROR,
+        CR_NO_ROOT_NODE_ERROR,
+        CR_NO_TOKEN,
+        CR_OUT_OF_MEMORY_ERROR,
+        CR_PSEUDO_CLASS_SEL_HANDLER_NOT_FOUND_ERROR,
+        CR_BAD_PSEUDO_CLASS_SEL_HANDLER_ERROR,
+        CR_ERROR,
+        CR_FILE_NOT_FOUND_ERROR,
+        CR_VALUE_NOT_FOUND_ERROR
+} ;
+
+/**
+ *Values used by
+ *cr_input_seek_position() ;
+ */
+enum CRSeekPos {
+        CR_SEEK_CUR,
+        CR_SEEK_BEGIN,
+        CR_SEEK_END
+} ;
+
+/**
+ *Encoding values.
+ */
+enum CREncoding 
+{
+        CR_UCS_4 = 1/*Must be not NULL*/,
+        CR_UCS_1,
+        CR_ISO_8859_1,
+        CR_ASCII,
+        CR_UTF_8,
+        CR_UTF_16,
+        CR_AUTO/*should be the last one*/
+} ;
+
+
+
+
+#define CROCO_LOG_DOMAIN "LIBCROCO"
+
+#ifdef __GNUC__
+#define cr_utils_trace(a_log_level, a_msg) \
+g_log (CROCO_LOG_DOMAIN, \
+       G_LOG_LEVEL_CRITICAL, \
+       "file %s: line %d (%s): %s\n", \
+       __FILE__, \
+       __LINE__, \
+       __PRETTY_FUNCTION__, \
+	a_msg)
+#else /*__GNUC__*/
+
+#define cr_utils_trace(a_log_level, a_msg) \
+g_log (CROCO_LOG_DOMAIN, \
+       G_LOG_LEVEL_CRITICAL, \
+       "file %s: line %d: %s\n", \
+       __FILE__, \
+       __LINE__, \
+       a_msg)
+#endif
+
+/**
+ *Traces an info message.
+ *The file, line and enclosing function
+ *of the message will be automatically 
+ *added to the message.
+ *@param a_msg the msg to trace.
+ */
+#define cr_utils_trace_info(a_msg) \
+cr_utils_trace (G_LOG_LEVEL_INFO, a_msg)
+
+/**
+ *Trace a debug message.
+ *The file, line and enclosing function
+ *of the message will be automatically
+ *added to the message.
+ *@param a_msg the msg to trace.
+ */
+#define cr_utils_trace_debug(a_msg) \
+cr_utils_trace (G_LOG_LEVEL_DEBUG, a_msg) ;
+
+
+/****************************
+ *Encoding transformations and
+ *encoding helpers
+ ****************************/
+
+enum CRStatus
+cr_utils_read_char_from_utf8_buf (const guchar * a_in, gulong a_in_len,
+                                  guint32 *a_out, gulong *a_consumed) ;
+
+enum CRStatus
+cr_utils_ucs1_to_utf8 (const guchar *a_in, gulong *a_in_len,
+                       guchar *a_out, gulong *a_out_len) ;
+
+enum CRStatus
+cr_utils_utf8_to_ucs1 (const guchar * a_in, gulong * a_in_len,
+                       guchar *a_out, gulong *a_out_len) ;
+
+enum CRStatus
+cr_utils_ucs4_to_utf8 (const guint32 *a_in, gulong *a_in_len,
+                       guchar *a_out, gulong *a_out_len) ;
+
+enum CRStatus
+cr_utils_utf8_str_len_as_ucs4 (const guchar *a_in_start,
+                               const guchar *a_in_end,
+                               gulong *a_len) ;
+enum CRStatus
+cr_utils_ucs1_str_len_as_utf8 (const guchar *a_in_start, 
+                               const guchar *a_in_end,
+                               gulong *a_len) ;
+enum CRStatus
+cr_utils_utf8_str_len_as_ucs1 (const guchar *a_in_start,
+                               const guchar *a_in_end,
+                               gulong *a_len) ;
+enum CRStatus
+cr_utils_ucs4_str_len_as_utf8 (const guint32 *a_in_start, 
+                               const guint32 *a_in_end,
+                               gulong *a_len) ;
+
+enum CRStatus
+cr_utils_ucs1_str_to_utf8 (const guchar *a_in_start, 
+                           gulong *a_in_len,
+                           guchar **a_out, 
+                           gulong *a_len) ;
+
+enum CRStatus
+cr_utils_utf8_str_to_ucs1 (const guchar * a_in_start, 
+                           gulong * a_in_len,
+                           guchar **a_out, 
+                           gulong *a_out_len) ;
+
+enum CRStatus
+cr_utils_utf8_to_ucs4 (const guchar * a_in, 
+                       gulong * a_in_len,
+                       guint32 *a_out, gulong *a_out_len) ;
+
+enum CRStatus
+cr_utils_ucs4_str_to_utf8 (const guint32 *a_in, 
+                           gulong *a_in_len,
+                           guchar **a_out, gulong *a_out_len) ;
+
+enum CRStatus
+cr_utils_utf8_str_to_ucs4 (const guchar * a_in, 
+                           gulong *a_in_len,
+                           guint32 **a_out, 
+                           gulong *a_out_len) ;
+
+
+/*****************************************
+ *CSS basic types identification utilities
+ *****************************************/
+
+gboolean
+cr_utils_is_newline (guint32 a_char) ;
+
+gboolean
+cr_utils_is_white_space (guint32 a_char) ;
+
+gboolean
+cr_utils_is_nonascii (guint32 a_char) ;
+
+gboolean
+cr_utils_is_hexa_char (guint32 a_char) ;
+
+
+/**********************************
+ *Miscellaneous utility functions
+ ***********************************/
+
+void
+cr_utils_dump_n_chars (guchar a_char, 
+                       FILE *a_fp, 
+                       glong a_nb) ;
+
+void
+cr_utils_dump_n_chars2 (guchar a_char, 
+                        GString *a_string,
+                        glong a_nb) ;
+GList *
+cr_utils_dup_glist_of_string (GList const *a_list) ;
+
+GList *
+cr_utils_dup_glist_of_cr_string (GList const * a_list_of_strings) ;
+
+G_END_DECLS
+
+#endif /*__CR_DEFS_H__*/
diff --git a/src/st/croco/libcroco-config.h b/src/st/croco/libcroco-config.h
new file mode 100644
index 000000000..1ffb758ea
--- /dev/null
+++ b/src/st/croco/libcroco-config.h
@@ -0,0 +1,13 @@
+#ifndef LIBCROCO_VERSION_NUMBER
+#define LIBCROCO_VERSION_NUMBER 612
+#endif
+
+#ifndef LIBCROCO_VERSION
+#define LIBCROCO_VERSION "0.6.12"
+#endif
+
+#ifndef G_DISABLE_CHECKS
+#if 0
+#define G_DISABLE_CHECKS 0
+#endif
+#endif
diff --git a/src/st/croco/libcroco.h b/src/st/croco/libcroco.h
new file mode 100644
index 000000000..6187a7cb9
--- /dev/null
+++ b/src/st/croco/libcroco.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of The Croco Library
+ *
+ * Copyright (C) 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifndef __LIBCROCO_H__
+#define __LIBCROCO_H__
+
+#include "libcroco-config.h"
+
+#include "cr-utils.h"
+#include "cr-pseudo.h"
+#include "cr-term.h"
+#include "cr-attr-sel.h"
+#include "cr-simple-sel.h"
+#include "cr-selector.h"
+#include "cr-enc-handler.h"
+#include "cr-doc-handler.h"
+#include "cr-input.h"
+#include "cr-parser.h"
+#include "cr-statement.h"
+#include "cr-stylesheet.h"
+#include "cr-om-parser.h"
+#include "cr-prop-list.h"
+#include "cr-string.h"
+
+#endif /*__LIBCROCO_H__*/
diff --git a/src/st/meson.build b/src/st/meson.build
index 97ce6134d..c1994755b 100644
--- a/src/st/meson.build
+++ b/src/st/meson.build
@@ -1,3 +1,4 @@
+# please, keep this sorted alphabetically
 st_headers = [
   'st-adjustment.h',
   'st-bin.h',
@@ -43,13 +44,68 @@ st_h = configure_file(
 
 st_inc = include_directories('.', '..')
 
+# please, keep this sorted alphabetically
 st_private_headers = [
+  'croco/cr-additional-sel.h',
+  'croco/cr-attr-sel.h',
+  'croco/cr-cascade.h',
+  'croco/cr-declaration.h',
+  'croco/cr-doc-handler.h',
+  'croco/cr-enc-handler.h',
+  'croco/cr-fonts.h',
+  'croco/cr-input.h',
+  'croco/cr-num.h',
+  'croco/cr-om-parser.h',
+  'croco/cr-parser.h',
+  'croco/cr-parsing-location.h',
+  'croco/cr-prop-list.h',
+  'croco/cr-pseudo.h',
+  'croco/cr-rgb.h',
+  'croco/cr-selector.h',
+  'croco/cr-simple-sel.h',
+  'croco/cr-statement.h',
+  'croco/cr-string.h',
+  'croco/cr-stylesheet.h',
+  'croco/cr-term.h',
+  'croco/cr-tknzr.h',
+  'croco/cr-token.h',
+  'croco/cr-utils.h',
+  'croco/libcroco-config.h',
+  'croco/libcroco.h',
   'st-private.h',
   'st-theme-private.h',
   'st-theme-node-private.h',
   'st-theme-node-transition.h'
 ]
 
+# please, keep this sorted alphabetically
+croco_sources = [
+  'croco/cr-additional-sel.c',
+  'croco/cr-attr-sel.c',
+  'croco/cr-cascade.c',
+  'croco/cr-declaration.c',
+  'croco/cr-doc-handler.c',
+  'croco/cr-enc-handler.c',
+  'croco/cr-fonts.c',
+  'croco/cr-input.c',
+  'croco/cr-num.c',
+  'croco/cr-om-parser.c',
+  'croco/cr-parser.c',
+  'croco/cr-parsing-location.c',
+  'croco/cr-prop-list.c',
+  'croco/cr-pseudo.c',
+  'croco/cr-rgb.c',
+  'croco/cr-selector.c',
+  'croco/cr-simple-sel.c',
+  'croco/cr-statement.c',
+  'croco/cr-string.c',
+  'croco/cr-stylesheet.c',
+  'croco/cr-term.c',
+  'croco/cr-tknzr.c',
+  'croco/cr-token.c',
+  'croco/cr-utils.c',
+]
+
 # please, keep this sorted alphabetically
 st_sources = [
   'st-adjustment.c',
@@ -119,9 +175,9 @@ st_cflags = [
 
 # Currently meson requires a shared library for building girs
 libst = shared_library('st-1.0',
-  sources: st_gir_sources + st_non_gir_sources,
+  sources: st_gir_sources + st_non_gir_sources + croco_sources,
   c_args: st_cflags,
-  dependencies: [clutter_dep, gtk_dep, croco_dep, x11_dep, m_dep],
+  dependencies: [clutter_dep, gtk_dep, x11_dep, m_dep],
   install_rpath: mutter_typelibdir,
   install_dir: pkglibdir,
   install: true
@@ -134,7 +190,7 @@ libst_dep = declare_dependency(link_with: libst,
 test_theme = executable('test-theme',
   sources: 'test-theme.c',
   c_args: st_cflags,
-  dependencies: [clutter_dep, gtk_dep],
+  dependencies: [clutter_dep, gtk_dep, libxml_dep],
   link_with: libst
 )
 
diff --git a/src/st/st-theme-node-private.h b/src/st/st-theme-node-private.h
index 2e6b232f6..659bc37ba 100644
--- a/src/st/st-theme-node-private.h
+++ b/src/st/st-theme-node-private.h
@@ -25,7 +25,7 @@
 #include <gdk/gdk.h>
 
 #include "st-theme-node.h"
-#include <libcroco/libcroco.h>
+#include "croco/libcroco.h"
 #include "st-types.h"
 
 G_BEGIN_DECLS
diff --git a/src/st/st-theme-private.h b/src/st/st-theme-private.h
index 08f3a1864..2083a7c84 100644
--- a/src/st/st-theme-private.h
+++ b/src/st/st-theme-private.h
@@ -21,7 +21,7 @@
 #ifndef __ST_THEME_PRIVATE_H__
 #define __ST_THEME_PRIVATE_H__
 
-#include <libcroco/libcroco.h>
+#include "croco/libcroco.h"
 #include "st-theme.h"
 
 G_BEGIN_DECLS
-- 
2.23.0

