/* iksemel (XML parser for Jabber) ** Copyright (C) 2000-2003 Gurer Ozen ** This code is free software; you can redistribute it and/or ** modify it under the terms of GNU Lesser General Public License. */ #include #include #include #include #include "iksemel.h" struct element_s { struct element_s *next; enum ikstype type; enum ikstagtype tag; char *name; int nr_atts; char *atts[10]; char *vals[10]; char *cdata; int len; }; struct { char *doc; int len; struct element_s *elements; struct element_s *last_element; struct element_s *cur; int nr_tests; int nr_cur; int blocksize; } tester; void document (char *xml) { if (tester.elements) { struct element_s *tmp; for (; tester.elements; tester.elements = tmp) { tmp = tester.elements->next; free (tester.elements); } } tester.doc = xml; tester.len = strlen (xml); tester.elements = NULL; tester.last_element = NULL; tester.nr_tests++; } void element (enum ikstype type, ...) { struct element_s *el; va_list ap; char *tmp; el = malloc (sizeof (struct element_s)); memset (el, 0, sizeof (struct element_s)); el->type = type; va_start (ap, type); switch (type) { case IKS_TAG: el->tag = va_arg (ap, int); el->name = va_arg (ap, char*); if (IKS_CLOSE == el->tag) break; while (1) { tmp = va_arg (ap, char*); if (tmp) { el->atts[el->nr_atts] = tmp; el->vals[el->nr_atts] = va_arg (ap, char*); el->nr_atts++; } else { break; } } break; case IKS_CDATA: tmp = va_arg (ap, char*); el->cdata = tmp; el->len = strlen (tmp); break; case IKS_NONE: case IKS_ATTRIBUTE: puts ("invalid element() call"); exit (1); } va_end (ap); if (NULL == tester.elements) tester.elements = el; if (tester.last_element) tester.last_element->next = el; tester.last_element = el; } #define PRINT_TEST printf ("Sax test %d, blocksize %d, element %d:\n", tester.nr_tests, tester.blocksize, tester.nr_cur) #define NEXT_ELEM { tester.cur = tester.cur->next; tester.nr_cur++; } void debug_tag (enum ikstagtype type, char *name, char **atts) { int i; PRINT_TEST; if (tester.cur && tester.cur->type == IKS_TAG) { switch (tester.cur->tag) { case IKS_OPEN: printf (" Expecting tag <%s>\n", tester.cur->name); break; case IKS_CLOSE: printf (" Expecting tag \n", tester.cur->name); break; case IKS_SINGLE: printf (" Expecting tag <%s/>\n", tester.cur->name); break; } for (i = 0; i < tester.cur->nr_atts; i++) { printf (" %s='%s'\n", tester.cur->atts[i], tester.cur->vals[i]); } } else { printf (" Not expecting a tag here.\n"); } switch (type) { case IKS_OPEN: printf (" Got tag <%s>\n", name); break; case IKS_CLOSE: printf (" Got tag \n", name); break; case IKS_SINGLE: printf (" Got tag <%s/>\n", name); break; } i = 0; while (atts && atts[i]) { printf (" %s='%s'\n", atts[i], atts[i+1]); i += 2; } } #define TAG_FAIL { debug_tag (type,name,atts); exit (1); } int tagHook (void *udata, char *name, char **atts, int type) { int nr, i, flag; if (!tester.cur) TAG_FAIL; if (tester.cur->type != IKS_TAG) TAG_FAIL; if (tester.cur->tag != type) TAG_FAIL; if (iks_strcmp (tester.cur->name, name) != 0) TAG_FAIL; if (!atts && tester.cur->nr_atts > 0) TAG_FAIL; if (atts && tester.cur->nr_atts == 0) TAG_FAIL; nr = tester.cur->nr_atts; while (nr) { flag = 0; for (i = 0;atts[i]; i+= 2) { if (iks_strcmp (atts[i], tester.cur->atts[nr-1]) == 0 && iks_strcmp (atts[i+1], tester.cur->vals[nr-1]) == 0) { flag = 1; break; } } if (flag == 0) TAG_FAIL; nr--; } NEXT_ELEM; return IKS_OK; } void debug_cdata (char *data, size_t len, int pos) { int i; PRINT_TEST; if (tester.cur && tester.cur->type == IKS_CDATA) printf (" Expecting cdata [%s]\n", tester.cur->cdata); else printf (" Not expecting cdata here\n"); printf (" Got cdata ["); for (i = 0; i < len; i++) putchar (data[i]); printf ("] at the pos %d.\n", pos); } #define CDATA_FAIL { debug_cdata (data, len, pos); exit (1); } int cdataHook (void *udata, char *data, size_t len) { static int pos = 0; if (!tester.cur) CDATA_FAIL; if (tester.cur->type != IKS_CDATA) CDATA_FAIL; if (iks_strncmp (tester.cur->cdata + pos, data, len) != 0) CDATA_FAIL; pos += len; if (pos > tester.cur->len) CDATA_FAIL; if (pos == tester.cur->len) { pos = 0; NEXT_ELEM; } return IKS_OK; } void test_size (int blocksize) { enum ikserror err; iksparser *prs; int i, len; tester.cur = tester.elements; tester.nr_cur = 1; tester.blocksize = blocksize; len = tester.len; prs = iks_sax_new (NULL, tagHook, cdataHook); i = 0; if (0 == blocksize) blocksize = len; while (i < len) { if (i + blocksize > len) blocksize = len - i; err = iks_parse (prs, tester.doc + i, blocksize, 0); switch (err) { case IKS_OK: break; case IKS_NOMEM: exit (1); case IKS_BADXML: PRINT_TEST; printf ("Invalid xml at byte %ld in\n[%s]\n", iks_nr_bytes (prs), tester.doc); exit (1); case IKS_HOOK: exit (1); } i += blocksize; } if (tester.cur) exit (1); iks_parser_delete (prs); } void test (void) { int i; for (i = 0; i < tester.len; i++) { test_size (i); } } void test_bad (int badbyte) { iksparser *p; enum ikserror err; p = iks_sax_new (NULL, NULL, NULL); err = iks_parse (p, tester.doc, tester.len, 1); switch (err) { case IKS_OK: break; case IKS_NOMEM: exit (1); case IKS_BADXML: if (iks_nr_bytes (p) == badbyte) return; break; case IKS_HOOK: exit (1); } printf ("Sax test %d:\n", tester.nr_tests); printf ("Expected bad byte %d, got %ld in\n[%s]\n", badbyte, iks_nr_bytes (p), tester.doc); exit (1); } /* No more attributes */ #define NMA ((char *) 0) int main (int argc, char *argv[]) { document (""); element (IKS_TAG, IKS_SINGLE, "lonely", NMA); test (); document ("child"); element (IKS_TAG, IKS_OPEN, "parent", NMA); element (IKS_TAG, IKS_SINGLE, "child", NMA); element (IKS_TAG, IKS_SINGLE, "child", NMA); element (IKS_CDATA, "child"); element (IKS_TAG, IKS_CLOSE, "parent"); test (); document (""); element (IKS_TAG, IKS_OPEN, "mytag", "abc", "123", "id", "XC72", NMA); element (IKS_TAG, IKS_CLOSE, "mytag"); test (); document ("I'm fixing parser&tester for "<" and ">" chars."); element (IKS_TAG, IKS_OPEN, "body", NMA); element (IKS_CDATA, "I'm fixing parser&tester for \"<\" and \">\" chars."); element (IKS_TAG, IKS_CLOSE, "body"); test (); document (""); element (IKS_TAG, IKS_OPEN, "tag", "a", "1", "b", "2", "c", "3", "d", "4", "e", "5", "f", "6", "g", "7", "id", "xyz9", NMA); element (IKS_TAG, IKS_OPEN, "sub", NMA); element (IKS_TAG, IKS_CLOSE, "sub"); element (IKS_TAG, IKS_CLOSE, "tag"); test (); document ("Jabber Site"); element (IKS_TAG, IKS_OPEN, "item", "url", "http://jabber.org", NMA); element (IKS_CDATA, "Jabber Site"); element (IKS_TAG, IKS_CLOSE, "item"); test (); document (""); element (IKS_TAG, IKS_OPEN, "index", NMA); element (IKS_TAG, IKS_SINGLE, "item", "name", "lala", "page", "42", NMA); element (IKS_TAG, IKS_CLOSE, "index"); test (); document ("1234 lala ] ]] ]]] ]]>4321"); element (IKS_TAG, IKS_OPEN, "ka", NMA); element (IKS_CDATA, "1234 lala ] ]] ]]] 4321"); element (IKS_TAG, IKS_CLOSE, "ka"); test (); document ("abcd
<escape>
"); element (IKS_TAG, IKS_OPEN, "test", NMA); element (IKS_TAG, IKS_SINGLE, "standalone", "be", "happy", NMA); element (IKS_CDATA, "abcd"); element (IKS_TAG, IKS_SINGLE, "br", NMA); element (IKS_CDATA, ""); element (IKS_TAG, IKS_CLOSE, "test"); test (); document ("john&mary"); element (IKS_TAG, IKS_OPEN, "a", NMA); element (IKS_TAG, IKS_OPEN, "b", NMA); element (IKS_CDATA, "john&mary"); element (IKS_TAG, IKS_OPEN, "c", NMA); element (IKS_TAG, IKS_SINGLE, "d", "e", "f", "g", "123456", "h", "madcat", "klm", "nop", NMA); element (IKS_TAG, IKS_CLOSE, "c", NMA); element (IKS_TAG, IKS_CLOSE, "b", NMA); element (IKS_TAG, IKS_CLOSE, "a", NMA); test (); document (""); element (IKS_TAG, IKS_OPEN, "a", NMA); element (IKS_TAG, IKS_SINGLE, "b", "x1", "lala", NMA); element (IKS_TAG, IKS_SINGLE, "c", "x2", "bibi", NMA); element (IKS_TAG, IKS_CLOSE, "a", NMA); test (); document ("[[bg:Чингис хан]][[bn:চেঙ্গিজ খান]]"); element (IKS_TAG, IKS_OPEN, "a", NMA); element (IKS_CDATA, "[[bg:Чингис хан]][[bn:চেঙ্গিজ খান]]"); element (IKS_TAG, IKS_CLOSE, "a", NMA); test (); document ("\xFF"); test_bad (6); document (""); tester.len = 8; test_bad (2); document (""); test_bad (13); document (""); test_bad (10); document (""); test_bad (17); document (""); test_bad (22); document ("<<>"); test_bad (16); document ("\xC0\x80"); test_bad (4); document ("<\x8F\x85>"); test_bad (1); document ("\xC1\x80
\xED\x95\x9C\xEA\xB5\xAD\xEC\x96\xB4\xC1\x65
"); test_bad (7); return 0; }