gboolean
_gtk_source_language_file_parse_version2 (GtkSourceLanguage       *language,
					  GtkSourceContextData    *ctx_data)
{
	GHashTable *defined_regexes, *styles;
	gboolean success;
	GError *error = NULL;
	gchar *filename;
	GHashTable *loaded_lang_ids;
	GQueue *replacements;

	g_return_val_if_fail (ctx_data != NULL, FALSE);

	filename = language->priv->lang_file_name;

	/* TODO: as an optimization tell the parser to merge CDATA
	 * as text nodes (XML_PARSE_NOCDATA), and to ignore blank
	 * nodes (XML_PARSE_NOBLANKS), if it is possible with
	 * xmlTextReader. */
	xmlKeepBlanksDefault (0);
	xmlLineNumbersDefault (1);
	xmlSubstituteEntitiesDefault (1);
	DEBUG (xmlPedanticParserDefault (1));

	defined_regexes = g_hash_table_new_full (g_str_hash, g_str_equal,
						 g_free, g_free);
	styles = g_hash_table_new_full (g_str_hash,
					g_str_equal,
					g_free,
					(GDestroyNotify) _gtk_source_style_info_free);
	loaded_lang_ids = g_hash_table_new_full (g_str_hash, g_str_equal,
						 (GDestroyNotify) xmlFree,
						 NULL);
	replacements = g_queue_new ();

	success = file_parse (filename, language, ctx_data,
			      defined_regexes, styles,
			      loaded_lang_ids, replacements,
			      &error);

	if (success)
		success = _gtk_source_context_data_finish_parse (ctx_data, replacements->head, &error);

	if (success)
		g_hash_table_foreach_steal (styles,
					    (GHRFunc) steal_styles_mapping,
					    language->priv->styles);

	g_queue_foreach (replacements, (GFunc) _gtk_source_context_replace_free, NULL);
	g_queue_free (replacements);
	g_hash_table_destroy (loaded_lang_ids);
	g_hash_table_destroy (defined_regexes);
	g_hash_table_destroy (styles);

	if (!success)
	{
		g_warning ("Failed to load '%s': %s",
			   filename, error->message);
		g_error_free (error);
		return FALSE;
	}

	return TRUE;
}
gboolean
_gtk_source_language_file_parse_version1 (GtkSourceLanguage    *language,
					  GtkSourceContextData *ctx_data)
{
	xmlDocPtr doc;
	xmlNodePtr cur;
	GMappedFile *mf;
	gunichar esc_char = 0;
	xmlChar *lang_version = NULL;

	xmlKeepBlanksDefault (0);

	mf = g_mapped_file_new (language->priv->lang_file_name, FALSE, NULL);

	if (mf == NULL)
	{
		doc = NULL;
	}
	else
	{
		doc = xmlParseMemory (g_mapped_file_get_contents (mf),
				      g_mapped_file_get_length (mf));
#if GLIB_CHECK_VERSION(2,22,0)
		g_mapped_file_unref (mf);
#else
		g_mapped_file_free (mf);
#endif
	}

	if (doc == NULL)
	{
		g_warning ("Impossible to parse file '%s'",
			   language->priv->lang_file_name);
		return FALSE;
	}

	cur = xmlDocGetRootElement (doc);

	if (cur == NULL)
	{
		g_warning ("The lang file '%s' is empty",
			   language->priv->lang_file_name);
		goto error;
	}

	if (xmlStrcmp (cur->name, (const xmlChar *) "language") != 0)
	{
		g_warning ("File '%s' is of the wrong type",
			   language->priv->lang_file_name);
		goto error;
	}

	lang_version = xmlGetProp (cur, BAD_CAST "version");

	if (lang_version == NULL || strcmp ("1.0", (char*) lang_version) != 0)
	{
		if (lang_version != NULL)
			g_warning ("Wrong language version '%s' in file '%s', expected '%s'",
				   (char*) lang_version, language->priv->lang_file_name, "1.0");
		else
			g_warning ("Language version missing in file '%s'",
				   language->priv->lang_file_name);
		goto error;
	}

	if (!define_root_context (ctx_data, language))
	{
		g_warning ("Could not create root context for file '%s'",
			   language->priv->lang_file_name);
		goto error;
	}

	/* FIXME: check that the language name, version, etc. are the
	 * right ones - Paolo */

	cur = xmlDocGetRootElement (doc);
	cur = cur->xmlChildrenNode;
	g_return_val_if_fail (cur != NULL, FALSE);

	while (cur != NULL)
	{
		if (!xmlStrcmp (cur->name, (const xmlChar *)"escape-char"))
		{
			xmlChar *escape;

			escape = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
			esc_char = g_utf8_get_char_validated ((gchar*) escape, -1);

			if (esc_char == (gunichar) -1 || esc_char == (gunichar) -2)
			{
				g_warning ("Invalid (non UTF8) escape character in file '%s'",
					   language->priv->lang_file_name);
				esc_char = 0;
			}

			xmlFree (escape);
		}
		else
		{
			parseTag (language, cur, ctx_data);
		}

		cur = cur->next;
	}

	if (esc_char != 0)
		_gtk_source_context_data_set_escape_char (ctx_data, esc_char);

	_gtk_source_context_data_finish_parse (ctx_data, NULL, NULL);
	_gtk_source_language_define_language_styles (language);

	xmlFreeDoc (doc);
	xmlFree (lang_version);
	return TRUE;

error:
	if (doc)
		xmlFreeDoc (doc);
	xmlFree (lang_version);
	return FALSE;
}