<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>test/chmindex.hhk</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -4,8 +4,13 @@
 #include &lt;libxml/parser.h&gt;
 #include &lt;libxml/HTMLparser.h&gt;
 
-struct _ChmIndexPriv {
+#include &quot;utils/utils.h&quot;
+#include &quot;models/link.h&quot;
+
+#define selfp (self-&gt;priv)
 
+struct _ChmIndexPriv {
+	GList* data; /* GList&lt;Link&gt; */
 };
 
 G_DEFINE_TYPE(ChmIndex, chmindex, G_TYPE_OBJECT);
@@ -25,24 +30,107 @@ chmindex_init(ChmIndex* self)
 	self-&gt;priv = G_TYPE_INSTANCE_GET_PRIVATE(self, TYPE_CHMINDEX, ChmIndexPriv);
 }
 
+enum {
+	STATE_OUT,
+	STATE_IN_SITEMAP
+};
+
+
 typedef struct {
+	int state;
+	GList* names; /* GList&lt;gchar*&gt; */
+	char* local;
 
+	GList* res; /* GList&lt;Link&gt; */
 } SAXContext;
 
-/**
- * TODO
- */
+SAXContext* saxcontext_new() {
+	return g_new0(SAXContext, 1);
+}
+
+void saxcontext_free(SAXContext* self) {
+	g_list_foreach(self-&gt;names, (GFunc)g_free, NULL);
+	g_list_free(self-&gt;names);
+
+	g_free(self-&gt;local);
+
+	g_list_foreach(self-&gt;res, (GFunc)g_free, NULL);
+	g_list_free(self-&gt;res);
+
+	g_free(self);
+}
+
+
 static void chm_index_start_element (void *ctx,
-		const xmlChar *name,
-		const xmlChar **atts) {
+		const xmlChar *name_,
+		const xmlChar **attrs_) {
+	const char* name = (const char*) name_;
+	const char** attrs = (const char**) attrs_;
+	SAXContext* context = (SAXContext*) ctx;
+
+	switch(context-&gt;state) {
+	case STATE_OUT:
+		if(g_ascii_strcasecmp(name, &quot;object&quot;) == 0) {
+			const char* type = get_attr(attrs, &quot;type&quot;);
+			if(g_ascii_strcasecmp(type, &quot;text/sitemap&quot;) == 0) {
+				context-&gt;state = STATE_IN_SITEMAP;
+			}
+		}
+		break;
+	case STATE_IN_SITEMAP:
+		if(g_ascii_strcasecmp(name, &quot;param&quot;) == 0) {
+			const char* name = get_attr(attrs, &quot;name&quot;);
+			const char* value = get_attr(attrs, &quot;value&quot;);
+
+			if(name != NULL &amp;&amp; value != NULL) {
+				if(g_ascii_strcasecmp(name, &quot;name&quot;) == 0) {
+					context-&gt;names = g_list_append(context-&gt;names, g_strdup(value));
+				} else if(g_ascii_strcasecmp(name, &quot;local&quot;) == 0) {
+					if(context-&gt;local != NULL) {
+						g_warning(&quot;more than one local in one sitemap&quot;);
+						g_free(context-&gt;local);
+					}
+					context-&gt;local = g_strdup(value);
+				}
+			} else {
+				g_warning(&quot;name or value is null&quot;);
+			}
+		}
+		break;
+	default:
+		g_return_if_reached();
+	}
+
 }
 
-/**
- * TODO
- */
 static void chm_index_end_element (void *ctx,
-		const xmlChar *name) {
-
+		const xmlChar *name_) {
+	const char* name = (const char*) name_;
+	SAXContext* context = (SAXContext*) ctx;
+
+	switch(context-&gt;state) {
+	case STATE_OUT:
+		break;
+	case STATE_IN_SITEMAP:
+		if(g_ascii_strcasecmp(name, &quot;object&quot;) == 0) {
+			if(context-&gt;local != NULL &amp;&amp; context-&gt;names != NULL) {
+				GList* iter;
+				for(iter = context-&gt;names; iter; iter = iter-&gt;next) {
+					Link* link = link_new(LINK_TYPE_PAGE, iter-&gt;data, context-&gt;local);
+					context-&gt;res = g_list_append(context-&gt;res, link);
+				}
+			}
+
+			g_free(context-&gt;local);
+			context-&gt;local = NULL;
+			g_list_foreach(context-&gt;names, (GFunc)g_free, NULL);
+			g_list_free(context-&gt;names);
+			context-&gt;names = NULL;
+		}
+		break;
+	default:
+		g_return_if_reached();
+	}
 }
 
 
@@ -82,22 +170,39 @@ static htmlSAXHandler hhSAXHandler = {
   NULL  /* xmlStructuredErrorFunc */
 };
 
+static gint data_sort_func(gconstpointer lhs_, gconstpointer rhs_) {
+	Link* lhs = (Link*)lhs_;
+	Link* rhs = (Link*)rhs_;
+
+	gint res = ncase_compare_utf8_string(lhs-&gt;name, rhs-&gt;name);
+	if(res == 0) {
+		res = ncase_compare_utf8_string(lhs-&gt;uri, rhs-&gt;uri);
+	}
+	return res;
+}
 
-/**
- * TODO:
- */
 ChmIndex* chmindex_new(const char* filename, const char* encoding) {
-	SAXContext context;
+	SAXContext* context = saxcontext_new();
 
 	if(htmlSAXParseFile(filename,
 			encoding,
 			&amp;hhSAXHandler,
-			&amp;context) != NULL) {
+			context) != NULL) {
 		g_error(&quot;parse %s with encoding %s failed.&quot;, filename, encoding);
 		return NULL;
 	}
 
 	ChmIndex* self = g_object_new(TYPE_CHMINDEX, NULL);
+	selfp-&gt;data = g_list_sort(context-&gt;res, data_sort_func);
+	context-&gt;res = NULL;
+
+	saxcontext_free(context);
 	return self;
 
 }
+
+GList* chmindex_get_data(ChmIndex* self) {
+	g_return_val_if_fail(IS_CHMINDEX(self), NULL);
+	return selfp-&gt;data;
+}
+</diff>
      <filename>src/models/chmindex.c</filename>
    </modified>
    <modified>
      <diff>@@ -37,5 +37,7 @@ GType chmindex_get_type(void);
  * @return NULL if open or parse indexFname failed.
  */
 ChmIndex *chmindex_new(const gchar* indexFname, const gchar* encoding);
+/** @return GList&lt;Link&gt; */
+GList* chmindex_get_data(ChmIndex* self);
 
 #endif /* CHMINDEX_H_ */</diff>
      <filename>src/models/chmindex.h</filename>
    </modified>
    <modified>
      <diff>@@ -1,15 +1,36 @@
 #include &lt;glib.h&gt;
 #include &quot;utils/utils.h&quot;
+#include &quot;models/link.h&quot;
+#include &quot;models/chmindex.h&quot;
 
 void test_issue_19() {
 	g_test_bug(&quot;19&quot;);
 	g_assert_cmpstr(&quot;WINDOWS-1256&quot;, ==, get_encoding_by_lcid(0xc01));
 }
 
+void test_chmindex() {
+	ChmIndex* chmIndex = chmindex_new(&quot;test/chmindex.hhk&quot;, &quot;UTF-8&quot;);
+	GList* data = chmindex_get_data(chmIndex);
+	g_assert_cmpint(3, ==, g_list_length(data));
+	g_assert_cmpstr(&quot;a&quot;, ==, ((Link*)data-&gt;data)-&gt;name);
+	g_assert_cmpstr(&quot;a1&quot;, ==, ((Link*)data-&gt;data)-&gt;uri);
+
+	data = data-&gt;next;
+	g_assert_cmpstr(&quot;a&quot;, ==, ((Link*)data-&gt;data)-&gt;name);
+	g_assert_cmpstr(&quot;a2&quot;, ==, ((Link*)data-&gt;data)-&gt;uri);
+
+	data = data-&gt;next;
+	g_assert_cmpstr(&quot;b&quot;, ==, ((Link*)data-&gt;data)-&gt;name);
+	g_assert_cmpstr(&quot;a1&quot;, ==, ((Link*)data-&gt;data)-&gt;uri);
+}
+
+
 int main(int argc, char* argv[]) {
+	gtk_init(&amp;argc, &amp;argv);
 	g_test_init(&amp;argc, &amp;argv, NULL);
 	g_test_bug_base(&quot;http://code.google.com/p/chmsee/issues/detail?id=&quot;);
 	g_test_add_func(&quot;/chmsee/19&quot;, test_issue_19);
+	g_test_add_func(&quot;/chmsee/chmindex&quot;, test_chmindex);
 	g_test_run();
 	return 0;
 }</diff>
      <filename>test/test.c</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>e31807bf3ef02862ffed4cf79a00ca43184571dd</id>
    </parent>
  </parents>
  <author>
    <name>LI Daobing</name>
    <email>lidaobing@gmail.com</email>
  </author>
  <url>http://github.com/lidaobing/chmsee/commit/21daf09d38358e61014e6832b290e0ea154c2cb2</url>
  <id>21daf09d38358e61014e6832b290e0ea154c2cb2</id>
  <committed-date>2009-06-14T03:18:26-07:00</committed-date>
  <authored-date>2009-06-14T03:18:26-07:00</authored-date>
  <message>add chmindex and the testcase</message>
  <tree>ab83f628f3a1dc86d2f0c589568b75ca32530a5f</tree>
  <committer>
    <name>LI Daobing</name>
    <email>lidaobing@gmail.com</email>
  </committer>
</commit>
