Ejemplo n.º 1
0
int verify_findMD5Sum(const char * md5orig, int disc_type) {

	print_gecko("Looking for MD5 [%s]\r\n", md5orig);
	char *xmlPointer = (disc_type == IS_NGC_DISC) ? ngcDAT : wiiDAT;
	if(xmlPointer) {
		mxml_node_t *pointer = (disc_type == IS_NGC_DISC)  ? ngcXML : wiiXML;
		
		pointer = mxmlLoadString(NULL, xmlPointer, MXML_TEXT_CALLBACK);
		
		print_gecko("Looking in the %s XML\r\n", pointer == ngcXML ? "GameCube" : "Wii");
		if (pointer) {
			// open the <datafile>
			mxml_node_t *item = mxmlFindElement(pointer, pointer, "datafile", NULL,
					NULL, MXML_DESCEND);
			print_gecko("DataFile Pointer OK\r\n");
			if (item) {
				mxml_index_t *iterator = mxmlIndexNew(item, "game", NULL);
				mxml_node_t *gameElem = NULL;

				//print_gecko("Item Pointer OK\r\n");
				// iterate over all the <game> entries
				while ((gameElem = mxmlIndexEnum(iterator)) != NULL) {
					// get the md5 and compare it
					mxml_node_t *md5Elem = mxmlFindElement(gameElem, gameElem,
							NULL, "md5", NULL, MXML_DESCEND);
					// get the name too
					mxml_node_t *nameElem = mxmlFindElement(gameElem, gameElem,
							NULL, "name", NULL, MXML_DESCEND);

					char md5[64];
					memset(&md5[0], 0, 64);
					strncpy(&md5[0], mxmlElementGetAttr(md5Elem, "md5"), 32);

					//print_gecko("Comparing game [%s] and md5 [%s]\r\n",mxmlElementGetAttr(nameElem, "name"),mxmlElementGetAttr(md5Elem, "md5"));
					if (!strnicmp(&md5[0], md5orig, 32)) {
						snprintf(&gameName[0], 128, "%s", mxmlElementGetAttr(
								nameElem, "name"));
						print_gecko("Found a match!\r\n");
						return 1;
					}
				}
			}
		}
	}
	return 0;
}
Ejemplo n.º 2
0
int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line args */
     char *argv[])			/* I - Command-line args */
{
	int size;
	FILE *fpr;
	char buffer[4096];
	
	mxml_node_t *mtree;
	mxml_node_t *root;
	mxml_node_t *child;
#if 1
	mxml_node_t *value;
	
	fpr = fopen("ChineseTest.xml", "r");
	if (!fpr)
		return -1;
	
	fseek(fpr, 0, SEEK_END);
	size = ftell(fpr);
	fseek(fpr, 0, SEEK_SET);
	fread(buffer, size, 1, fpr);
	printf("\n%s\n-------------------------------------\n", buffer);

	mtree = mxmlLoadString(NULL, buffer, MXML_TEXT_CALLBACK);

	root = mxmlFindElement(mtree, mtree, NULL, NULL, NULL, MXML_DESCEND_FIRST);
	if (root)
	{
		printf("name : %s\n", root->value.element.name);
		child = mxmlFindElement(root, root, NULL, NULL, NULL, MXML_DESCEND_FIRST);
        while (child)
        {
            printf("name : %s\n", child->value.element.name);
            value = child->child;
            if (MXML_TEXT == value->type)
            {
                //printf("value: %s\n", value->value.text.string);
                while ((NULL != value) && (MXML_TEXT == value->type) && 
                        (NULL != value->value.text.string))
                {
                    printf("  text.string: [%s]\n", value->value.text.string);
                    value = value->next;
                }
            }
            child = mxmlFindElement(child, child, NULL, NULL, NULL, MXML_NO_DESCEND);
        }
		
	}

	mxmlDelete(mtree);
	fclose(fpr);
#endif
    return 0;
	char chinese[32] = {0};
	fpr = fopen("chinese.txt", "r");
	if (!fpr)
		return -1;
	
	fseek(fpr, 0, SEEK_END);
	size = ftell(fpr);
	fseek(fpr, 0, SEEK_SET);
	fread(chinese, size, 1, fpr);
	printf("\nchinese: %s\n", chinese);

	mtree = mxmlNewElement(MXML_NO_PARENT, "?xml version=\"1.0\" encoding=\"UTF-8\"?");
	root = mxmlNewElement(mtree, "message");
	child = mxmlNewElement(root, "child");
	mxmlNewText(child, 0, chinese);
	
	mxmlSaveString(mtree, buffer, sizeof(buffer), MXML_TEXT_CALLBACK);
	printf("-------------------------------------\n%s\n", buffer);

	return 0;

#if 0

  int			i;		/* Looping var */
  FILE			*fp;		/* File to read */
  int			fd;		/* File descriptor */
  mxml_node_t		*tree,		/* XML tree */
			*node;		/* Node which should be in test.xml */
  mxml_index_t		*ind;		/* XML index */
  char			buffer[16384];	/* Save string */
  static const char	*types[] =	/* Strings for node types */
			{
			  "MXML_ELEMENT",
			  "MXML_INTEGER",
			  "MXML_OPAQUE",
			  "MXML_REAL",
			  "MXML_TEXT"
			};


 /*
  * Check arguments...
  */

  if (argc != 2)
  {
    fputs("Usage: testmxml filename.xml\n", stderr);
    return (1);
  }

 /*
  * Test the basic functionality...
  */

  tree = mxmlNewElement(MXML_NO_PARENT, "element");

  if (!tree)
  {
    fputs("ERROR: No parent node in basic test!\n", stderr);
    return (1);
  }

  if (tree->type != MXML_ELEMENT)
  {
    fprintf(stderr, "ERROR: Parent has type %s (%d), expected MXML_ELEMENT!\n",
            tree->type < MXML_ELEMENT || tree->type > MXML_TEXT ?
	        "UNKNOWN" : types[tree->type], tree->type);
    mxmlDelete(tree);
    return (1);
  }

  if (strcmp(tree->value.element.name, "element"))
  {
    fprintf(stderr, "ERROR: Parent value is \"%s\", expected \"element\"!\n",
            tree->value.element.name);
    mxmlDelete(tree);
    return (1);
  }

  mxmlNewInteger(tree, 123);
  mxmlNewOpaque(tree, "opaque");
  mxmlNewReal(tree, 123.4f);
  mxmlNewText(tree, 1, "text");

  mxmlLoadString(tree, "<group type='string'>string string string</group>",
                 MXML_NO_CALLBACK);
  mxmlLoadString(tree, "<group type='integer'>1 2 3</group>",
                 MXML_INTEGER_CALLBACK);
  mxmlLoadString(tree, "<group type='real'>1.0 2.0 3.0</group>",
                 MXML_REAL_CALLBACK);
  mxmlLoadString(tree, "<group>opaque opaque opaque</group>",
                 MXML_OPAQUE_CALLBACK);

  node = tree->child;

  if (!node)
  {
    fputs("ERROR: No first child node in basic test!\n", stderr);
    mxmlDelete(tree);
    return (1);
  }

  if (node->type != MXML_INTEGER)
  {
    fprintf(stderr, "ERROR: First child has type %s (%d), expected MXML_INTEGER!\n",
            node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
	        "UNKNOWN" : types[node->type], node->type);
    mxmlDelete(tree);
    return (1);
  }

  if (node->value.integer != 123)
  {
    fprintf(stderr, "ERROR: First child value is %d, expected 123!\n",
            node->value.integer);
    mxmlDelete(tree);
    return (1);
  }

  node = node->next;

  if (!node)
  {
    fputs("ERROR: No second child node in basic test!\n", stderr);
    mxmlDelete(tree);
    return (1);
  }

  if (node->type != MXML_OPAQUE)
  {
    fprintf(stderr, "ERROR: Second child has type %s (%d), expected MXML_OPAQUE!\n",
            node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
	        "UNKNOWN" : types[node->type], node->type);
    mxmlDelete(tree);
    return (1);
  }

  if (!node->value.opaque || strcmp(node->value.opaque, "opaque"))
  {
    fprintf(stderr, "ERROR: Second child value is \"%s\", expected \"opaque\"!\n",
            node->value.opaque ? node->value.opaque : "(null)");
    mxmlDelete(tree);
    return (1);
  }

  node = node->next;

  if (!node)
  {
    fputs("ERROR: No third child node in basic test!\n", stderr);
    mxmlDelete(tree);
    return (1);
  }

  if (node->type != MXML_REAL)
  {
    fprintf(stderr, "ERROR: Third child has type %s (%d), expected MXML_REAL!\n",
            node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
	        "UNKNOWN" : types[node->type], node->type);
    mxmlDelete(tree);
    return (1);
  }

  if (node->value.real != 123.4f)
  {
    fprintf(stderr, "ERROR: Third child value is %f, expected 123.4!\n",
            node->value.real);
    mxmlDelete(tree);
    return (1);
  }

  node = node->next;

  if (!node)
  {
    fputs("ERROR: No fourth child node in basic test!\n", stderr);
    mxmlDelete(tree);
    return (1);
  }

  if (node->type != MXML_TEXT)
  {
    fprintf(stderr, "ERROR: Fourth child has type %s (%d), expected MXML_TEXT!\n",
            node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
	        "UNKNOWN" : types[node->type], node->type);
    mxmlDelete(tree);
    return (1);
  }

  if (!node->value.text.whitespace ||
      !node->value.text.string || strcmp(node->value.text.string, "text"))
  {
    fprintf(stderr, "ERROR: Fourth child value is %d,\"%s\", expected 1,\"text\"!\n",
            node->value.text.whitespace,
	    node->value.text.string ? node->value.text.string : "(null)");
    mxmlDelete(tree);
    return (1);
  }

  for (i = 0; i < 4; i ++)
  {
    node = node->next;

    if (!node)
    {
      fprintf(stderr, "ERROR: No group #%d child node in basic test!\n", i + 1);
      mxmlDelete(tree);
      return (1);
    }

    if (node->type != MXML_ELEMENT)
    {
      fprintf(stderr, "ERROR: Group child #%d has type %s (%d), expected MXML_ELEMENT!\n",
              i + 1, node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
	                 "UNKNOWN" : types[node->type], node->type);
      mxmlDelete(tree);
      return (1);
    }
  }

 /*
  * Test indices...
  */

  ind = mxmlIndexNew(tree, NULL, NULL);
  if (!ind)
  {
    fputs("ERROR: Unable to create index of all nodes!\n", stderr);
    mxmlDelete(tree);
    return (1);
  }

  if (ind->num_nodes != 5)
  {
    fprintf(stderr, "ERROR: Index of all nodes contains %d "
                    "nodes; expected 5!\n", ind->num_nodes);
    mxmlIndexDelete(ind);
    mxmlDelete(tree);
    return (1);
  }

  mxmlIndexReset(ind);
  if (!mxmlIndexFind(ind, "group", NULL))
  {
    fputs("ERROR: mxmlIndexFind for \"group\" failed!\n", stderr);
    mxmlIndexDelete(ind);
    mxmlDelete(tree);
    return (1);
  }

  mxmlIndexDelete(ind);

  ind = mxmlIndexNew(tree, "group", NULL);
  if (!ind)
  {
    fputs("ERROR: Unable to create index of groups!\n", stderr);
    mxmlDelete(tree);
    return (1);
  }

  if (ind->num_nodes != 4)
  {
    fprintf(stderr, "ERROR: Index of groups contains %d "
                    "nodes; expected 4!\n", ind->num_nodes);
    mxmlIndexDelete(ind);
    mxmlDelete(tree);
    return (1);
  }

  mxmlIndexReset(ind);
  if (!mxmlIndexEnum(ind))
  {
    fputs("ERROR: mxmlIndexEnum failed!\n", stderr);
    mxmlIndexDelete(ind);
    mxmlDelete(tree);
    return (1);
  }

  mxmlIndexDelete(ind);

  ind = mxmlIndexNew(tree, NULL, "type");
  if (!ind)
  {
    fputs("ERROR: Unable to create index of type attributes!\n", stderr);
    mxmlDelete(tree);
    return (1);
  }

  if (ind->num_nodes != 3)
  {
    fprintf(stderr, "ERROR: Index of type attributes contains %d "
                    "nodes; expected 3!\n", ind->num_nodes);
    mxmlIndexDelete(ind);
    mxmlDelete(tree);
    return (1);
  }

  mxmlIndexReset(ind);
  if (!mxmlIndexFind(ind, NULL, "string"))
  {
    fputs("ERROR: mxmlIndexFind for \"string\" failed!\n", stderr);
    mxmlIndexDelete(ind);
    mxmlDelete(tree);
    return (1);
  }

  mxmlIndexDelete(ind);

  ind = mxmlIndexNew(tree, "group", "type");
  if (!ind)
  {
    fputs("ERROR: Unable to create index of elements and attributes!\n", stderr);
    mxmlDelete(tree);
    return (1);
  }

  if (ind->num_nodes != 3)
  {
    fprintf(stderr, "ERROR: Index of elements and attributes contains %d "
                    "nodes; expected 3!\n", ind->num_nodes);
    mxmlIndexDelete(ind);
    mxmlDelete(tree);
    return (1);
  }

  mxmlIndexReset(ind);
  if (!mxmlIndexFind(ind, "group", "string"))
  {
    fputs("ERROR: mxmlIndexFind for \"string\" failed!\n", stderr);
    mxmlIndexDelete(ind);
    mxmlDelete(tree);
    return (1);
  }

  mxmlIndexDelete(ind);

 /*
  * Check the mxmlDelete() works properly...
  */

  for (i = 0; i < 8; i ++)
  {
    if (tree->child)
      mxmlDelete(tree->child);
    else
    {
      fprintf(stderr, "ERROR: Child pointer prematurely NULL on child #%d\n",
              i + 1);
      mxmlDelete(tree);
      return (1);
    }
  }

  if (tree->child)
  {
    fputs("ERROR: Child pointer not NULL after deleting all children!\n", stderr);
    return (1);
  }

  if (tree->last_child)
  {
    fputs("ERROR: Last child pointer not NULL after deleting all children!\n", stderr);
    return (1);
  }

  mxmlDelete(tree);

 /*
  * Open the file...
  */

  if (argv[1][0] == '<')
    tree = mxmlLoadString(NULL, argv[1], type_cb);
  else if ((fp = fopen(argv[1], "rb")) == NULL)
  {
    perror(argv[1]);
    return (1);
  }
  else
  {
   /*
    * Read the file...
    */

    tree = mxmlLoadFile(NULL, fp, type_cb);

    fclose(fp);
  }

  if (!tree)
  {
    fputs("Unable to read XML file!\n", stderr);
    return (1);
  }

  if (!strcmp(argv[1], "test.xml"))
  {
   /*
    * Verify that mxmlFindElement() and indirectly mxmlWalkNext() work
    * properly...
    */

    if ((node = mxmlFindElement(tree, tree, "choice", NULL, NULL,
                                MXML_DESCEND)) == NULL)
    {
      fputs("Unable to find first <choice> element in XML tree!\n", stderr);
      mxmlDelete(tree);
      return (1);
    }

    if ((node = mxmlFindElement(node, tree, "choice", NULL, NULL,
                                MXML_NO_DESCEND)) == NULL)
    {
      fputs("Unable to find second <choice> element in XML tree!\n", stderr);
      mxmlDelete(tree);
      return (1);
    }
  }

 /*
  * Print the XML tree...
  */

  mxmlSaveFile(tree, stdout, whitespace_cb);

 /*
  * Save the XML tree to a string and print it...
  */

  if (mxmlSaveString(tree, buffer, sizeof(buffer), whitespace_cb) > 0)
    fputs(buffer, stderr);

 /*
  * Delete the tree...
  */

  mxmlDelete(tree);

 /*
  * Read from/write to file descriptors...
  */

  if (argv[1][0] != '<')
  {
   /*
    * Open the file again...
    */

    if ((fd = open(argv[1], O_RDONLY | O_BINARY)) < 0)
    {
      perror(argv[1]);
      return (1);
    }

   /*
    * Read the file...
    */

    tree = mxmlLoadFd(NULL, fd, type_cb);

    close(fd);

   /*
    * Create filename.xmlfd...
    */

    snprintf(buffer, sizeof(buffer), "%sfd", argv[1]);

    if ((fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)) < 0)
    {
      perror(buffer);
      mxmlDelete(tree);
      return (1);
    }

   /*
    * Write the file...
    */

    mxmlSaveFd(tree, fd, whitespace_cb);

    close(fd);

   /*
    * Delete the tree...
    */

    mxmlDelete(tree);
  }
#endif
 /*
  * Return...
  */

  return (0);
}
Ejemplo n.º 3
0
mxml_node_t*                /* O - Node or NULL if none found */
mxmlIndexFind(mxml_index_t* ind,    /* I - Index to search */
              const char*   element,    /* I - Element name to find, if any */
              const char*   value) { /* I - Attribute value, if any */
    int       diff,           /* Difference between names */
              current,        /* Current entity in search */
              first,          /* First entity in search */
              last;           /* Last entity in search */


#ifdef DEBUG
    printf("mxmlIndexFind(ind=%p, element=\"%s\", value=\"%s\")\n",
           ind, element ? element : "(null)", value ? value : "(null)");
#endif /* DEBUG */

    /*
     * Range check input...
     */

    if (!ind || (!ind->attr && value)) {
#ifdef DEBUG
        puts("    returning NULL...");
        printf("    ind->attr=\"%s\"\n", ind->attr ? ind->attr : "(null)");
#endif /* DEBUG */

        return (NULL);
    }

    /*
     * If both element and value are NULL, just enumerate the nodes in the
     * index...
     */

    if (!element && !value) {
        return (mxmlIndexEnum(ind));
    }

    /*
     * If there are no nodes in the index, return NULL...
     */

    if (!ind->num_nodes) {
#ifdef DEBUG
        puts("    returning NULL...");
        puts("    no nodes!");
#endif /* DEBUG */

        return (NULL);
    }

    /*
     * If cur_node == 0, then find the first matching node...
     */

    if (ind->cur_node == 0) {
        /*
         * Find the first node using a modified binary search algorithm...
         */

        first = 0;
        last  = ind->num_nodes - 1;

#ifdef DEBUG
        printf("    find first time, num_nodes=%d...\n", ind->num_nodes);
#endif /* DEBUG */

        while ((last - first) > 1) {
            current = (first + last) / 2;

#ifdef DEBUG
            printf("    first=%d, last=%d, current=%d\n", first, last, current);
#endif /* DEBUG */

            if ((diff = index_find(ind, element, value, ind->nodes[current])) == 0) {
                /*
                 * Found a match, move back to find the first...
                */

#ifdef DEBUG
                puts("    match!");
#endif /* DEBUG */

                while (current > 0 &&
                        !index_find(ind, element, value, ind->nodes[current - 1])) {
                    current --;
                }

#ifdef DEBUG
                printf("    returning first match=%d\n", current);
#endif /* DEBUG */

                /*
                 * Return the first match and save the index to the next...
                */

                ind->cur_node = current + 1;

                return (ind->nodes[current]);
            } else if (diff < 0) {
                last = current;
            } else {
                first = current;
            }

#ifdef DEBUG
            printf("    diff=%d\n", diff);
#endif /* DEBUG */
        }

        /*
         * If we get this far, then we found exactly 0 or 1 matches...
         */

        for (current = first; current <= last; current ++)
            if (!index_find(ind, element, value, ind->nodes[current])) {
                /*
                * Found exactly one (or possibly two) match...
                */

#ifdef DEBUG
                printf("    returning only match %d...\n", current);
#endif /* DEBUG */

                ind->cur_node = current + 1;

                return (ind->nodes[current]);
            }

        /*
         * No matches...
         */

        ind->cur_node = ind->num_nodes;

#ifdef DEBUG
        puts("    returning NULL...");
#endif /* DEBUG */

        return (NULL);
    } else if (ind->cur_node < ind->num_nodes &&
               !index_find(ind, element, value, ind->nodes[ind->cur_node])) {
        /*
         * Return the next matching node...
         */

#ifdef DEBUG
        printf("    returning next match %d...\n", ind->cur_node);
#endif /* DEBUG */

        return (ind->nodes[ind->cur_node ++]);
    }

    /*
     * If we get this far, then we have no matches...
     */

    ind->cur_node = ind->num_nodes;

#ifdef DEBUG
    puts("    returning NULL...");
#endif /* DEBUG */

    return (NULL);
}
Ejemplo n.º 4
0
int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line args */
     char *argv[])			/* I - Command-line args */
{
  int			i;		/* Looping var */
  FILE			*fp;		/* File to read */
  int			fd;		/* File descriptor */
  mxml_node_t		*tree,		/* XML tree */
			*node;		/* Node which should be in test.xml */
  mxml_index_t		*ind;		/* XML index */
  char			buffer[16384];	/* Save string */
  static const char	*types[] =	/* Strings for node types */
			{
			  "MXML_ELEMENT",
			  "MXML_INTEGER",
			  "MXML_OPAQUE",
			  "MXML_REAL",
			  "MXML_TEXT"
			};


 /*
  * Check arguments...
  */

  if (argc != 2)
  {
    fputs("Usage: testmxml filename.xml\n", stderr);
    return (1);
  }

 /*
  * Test the basic functionality...
  */

  tree = mxmlNewElement(MXML_NO_PARENT, "element");

  if (!tree)
  {
    fputs("ERROR: No parent node in basic test!\n", stderr);
    return (1);
  }

  if (tree->type != MXML_ELEMENT)
  {
    fprintf(stderr, "ERROR: Parent has type %s (%d), expected MXML_ELEMENT!\n",
            tree->type < MXML_ELEMENT || tree->type > MXML_TEXT ?
	        "UNKNOWN" : types[tree->type], tree->type);
    mxmlDelete(tree);
    return (1);
  }

  if (strcmp(tree->value.element.name, "element"))
  {
    fprintf(stderr, "ERROR: Parent value is \"%s\", expected \"element\"!\n",
            tree->value.element.name);
    mxmlDelete(tree);
    return (1);
  }

  mxmlNewInteger(tree, 123);
  mxmlNewOpaque(tree, "opaque");
  mxmlNewReal(tree, 123.4f);
  mxmlNewText(tree, 1, "text");

  mxmlLoadString(tree, "<group type='string'>string string string</group>",
                 MXML_NO_CALLBACK);
  mxmlLoadString(tree, "<group type='integer'>1 2 3</group>",
                 MXML_INTEGER_CALLBACK);
  mxmlLoadString(tree, "<group type='real'>1.0 2.0 3.0</group>",
                 MXML_REAL_CALLBACK);
  mxmlLoadString(tree, "<group>opaque opaque opaque</group>",
                 MXML_OPAQUE_CALLBACK);

  node = tree->child;

  if (!node)
  {
    fputs("ERROR: No first child node in basic test!\n", stderr);
    mxmlDelete(tree);
    return (1);
  }

  if (node->type != MXML_INTEGER)
  {
    fprintf(stderr, "ERROR: First child has type %s (%d), expected MXML_INTEGER!\n",
            node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
	        "UNKNOWN" : types[node->type], node->type);
    mxmlDelete(tree);
    return (1);
  }

  if (node->value.integer != 123)
  {
    fprintf(stderr, "ERROR: First child value is %d, expected 123!\n",
            node->value.integer);
    mxmlDelete(tree);
    return (1);
  }

  node = node->next;

  if (!node)
  {
    fputs("ERROR: No second child node in basic test!\n", stderr);
    mxmlDelete(tree);
    return (1);
  }

  if (node->type != MXML_OPAQUE)
  {
    fprintf(stderr, "ERROR: Second child has type %s (%d), expected MXML_OPAQUE!\n",
            node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
	        "UNKNOWN" : types[node->type], node->type);
    mxmlDelete(tree);
    return (1);
  }

  if (!node->value.opaque || strcmp(node->value.opaque, "opaque"))
  {
    fprintf(stderr, "ERROR: Second child value is \"%s\", expected \"opaque\"!\n",
            node->value.opaque ? node->value.opaque : "(null)");
    mxmlDelete(tree);
    return (1);
  }

  node = node->next;

  if (!node)
  {
    fputs("ERROR: No third child node in basic test!\n", stderr);
    mxmlDelete(tree);
    return (1);
  }

  if (node->type != MXML_REAL)
  {
    fprintf(stderr, "ERROR: Third child has type %s (%d), expected MXML_REAL!\n",
            node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
	        "UNKNOWN" : types[node->type], node->type);
    mxmlDelete(tree);
    return (1);
  }

  if (node->value.real != 123.4f)
  {
    fprintf(stderr, "ERROR: Third child value is %f, expected 123.4!\n",
            node->value.real);
    mxmlDelete(tree);
    return (1);
  }

  node = node->next;

  if (!node)
  {
    fputs("ERROR: No fourth child node in basic test!\n", stderr);
    mxmlDelete(tree);
    return (1);
  }

  if (node->type != MXML_TEXT)
  {
    fprintf(stderr, "ERROR: Fourth child has type %s (%d), expected MXML_TEXT!\n",
            node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
	        "UNKNOWN" : types[node->type], node->type);
    mxmlDelete(tree);
    return (1);
  }

  if (!node->value.text.whitespace ||
      !node->value.text.string || strcmp(node->value.text.string, "text"))
  {
    fprintf(stderr, "ERROR: Fourth child value is %d,\"%s\", expected 1,\"text\"!\n",
            node->value.text.whitespace,
	    node->value.text.string ? node->value.text.string : "(null)");
    mxmlDelete(tree);
    return (1);
  }

  for (i = 0; i < 4; i ++)
  {
    node = node->next;

    if (!node)
    {
      fprintf(stderr, "ERROR: No group #%d child node in basic test!\n", i + 1);
      mxmlDelete(tree);
      return (1);
    }

    if (node->type != MXML_ELEMENT)
    {
      fprintf(stderr, "ERROR: Group child #%d has type %s (%d), expected MXML_ELEMENT!\n",
              i + 1, node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
	                 "UNKNOWN" : types[node->type], node->type);
      mxmlDelete(tree);
      return (1);
    }
  }

 /*
  * Test indices...
  */

  ind = mxmlIndexNew(tree, NULL, NULL);
  if (!ind)
  {
    fputs("ERROR: Unable to create index of all nodes!\n", stderr);
    mxmlDelete(tree);
    return (1);
  }

  if (ind->num_nodes != 5)
  {
    fprintf(stderr, "ERROR: Index of all nodes contains %d "
                    "nodes; expected 5!\n", ind->num_nodes);
    mxmlIndexDelete(ind);
    mxmlDelete(tree);
    return (1);
  }

  mxmlIndexReset(ind);
  if (!mxmlIndexFind(ind, "group", NULL))
  {
    fputs("ERROR: mxmlIndexFind for \"group\" failed!\n", stderr);
    mxmlIndexDelete(ind);
    mxmlDelete(tree);
    return (1);
  }

  mxmlIndexDelete(ind);

  ind = mxmlIndexNew(tree, "group", NULL);
  if (!ind)
  {
    fputs("ERROR: Unable to create index of groups!\n", stderr);
    mxmlDelete(tree);
    return (1);
  }

  if (ind->num_nodes != 4)
  {
    fprintf(stderr, "ERROR: Index of groups contains %d "
                    "nodes; expected 4!\n", ind->num_nodes);
    mxmlIndexDelete(ind);
    mxmlDelete(tree);
    return (1);
  }

  mxmlIndexReset(ind);
  if (!mxmlIndexEnum(ind))
  {
    fputs("ERROR: mxmlIndexEnum failed!\n", stderr);
    mxmlIndexDelete(ind);
    mxmlDelete(tree);
    return (1);
  }

  mxmlIndexDelete(ind);

  ind = mxmlIndexNew(tree, NULL, "type");
  if (!ind)
  {
    fputs("ERROR: Unable to create index of type attributes!\n", stderr);
    mxmlDelete(tree);
    return (1);
  }

  if (ind->num_nodes != 3)
  {
    fprintf(stderr, "ERROR: Index of type attributes contains %d "
                    "nodes; expected 3!\n", ind->num_nodes);
    mxmlIndexDelete(ind);
    mxmlDelete(tree);
    return (1);
  }

  mxmlIndexReset(ind);
  if (!mxmlIndexFind(ind, NULL, "string"))
  {
    fputs("ERROR: mxmlIndexFind for \"string\" failed!\n", stderr);
    mxmlIndexDelete(ind);
    mxmlDelete(tree);
    return (1);
  }

  mxmlIndexDelete(ind);

  ind = mxmlIndexNew(tree, "group", "type");
  if (!ind)
  {
    fputs("ERROR: Unable to create index of elements and attributes!\n", stderr);
    mxmlDelete(tree);
    return (1);
  }

  if (ind->num_nodes != 3)
  {
    fprintf(stderr, "ERROR: Index of elements and attributes contains %d "
                    "nodes; expected 3!\n", ind->num_nodes);
    mxmlIndexDelete(ind);
    mxmlDelete(tree);
    return (1);
  }

  mxmlIndexReset(ind);
  if (!mxmlIndexFind(ind, "group", "string"))
  {
    fputs("ERROR: mxmlIndexFind for \"string\" failed!\n", stderr);
    mxmlIndexDelete(ind);
    mxmlDelete(tree);
    return (1);
  }

  mxmlIndexDelete(ind);

 /*
  * Check the mxmlDelete() works properly...
  */

  for (i = 0; i < 8; i ++)
  {
    if (tree->child)
      mxmlDelete(tree->child);
    else
    {
      fprintf(stderr, "ERROR: Child pointer prematurely NULL on child #%d\n",
              i + 1);
      mxmlDelete(tree);
      return (1);
    }
  }

  if (tree->child)
  {
    fputs("ERROR: Child pointer not NULL after deleting all children!\n", stderr);
    return (1);
  }

  if (tree->last_child)
  {
    fputs("ERROR: Last child pointer not NULL after deleting all children!\n", stderr);
    return (1);
  }

  mxmlDelete(tree);

 /*
  * Open the file...
  */

  if (argv[1][0] == '<')
    tree = mxmlLoadString(NULL, argv[1], type_cb);
  else if ((fp = fopen(argv[1], "rb")) == NULL)
  {
    perror(argv[1]);
    return (1);
  }
  else
  {
   /*
    * Read the file...
    */

    tree = mxmlLoadFile(NULL, fp, type_cb);

    fclose(fp);
  }

  if (!tree)
  {
    fputs("Unable to read XML file!\n", stderr);
    return (1);
  }

  if (!strcmp(argv[1], "test.xml"))
  {
   /*
    * Verify that mxmlFindElement() and indirectly mxmlWalkNext() work
    * properly...
    */

    if ((node = mxmlFindElement(tree, tree, "choice", NULL, NULL,
                                MXML_DESCEND)) == NULL)
    {
      fputs("Unable to find first <choice> element in XML tree!\n", stderr);
      mxmlDelete(tree);
      return (1);
    }

    if ((node = mxmlFindElement(node, tree, "choice", NULL, NULL,
                                MXML_NO_DESCEND)) == NULL)
    {
      fputs("Unable to find second <choice> element in XML tree!\n", stderr);
      mxmlDelete(tree);
      return (1);
    }
  }

 /*
  * Print the XML tree...
  */

  mxmlSaveFile(tree, stdout, whitespace_cb);

 /*
  * Save the XML tree to a string and print it...
  */

  if (mxmlSaveString(tree, buffer, sizeof(buffer), whitespace_cb) > 0)
    fputs(buffer, stderr);

 /*
  * Delete the tree...
  */

  mxmlDelete(tree);

 /*
  * Read from/write to file descriptors...
  */

  if (argv[1][0] != '<')
  {
   /*
    * Open the file again...
    */

    if ((fd = open(argv[1], O_RDONLY | O_BINARY)) < 0)
    {
      perror(argv[1]);
      return (1);
    }

   /*
    * Read the file...
    */

    tree = mxmlLoadFd(NULL, fd, type_cb);

    close(fd);

   /*
    * Create filename.xmlfd...
    */

    snprintf(buffer, sizeof(buffer), "%sfd", argv[1]);

    if ((fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)) < 0)
    {
      perror(buffer);
      mxmlDelete(tree);
      return (1);
    }

   /*
    * Write the file...
    */

    mxmlSaveFd(tree, fd, whitespace_cb);

    close(fd);

   /*
    * Delete the tree...
    */

    mxmlDelete(tree);
  }

 /*
  * Test SAX methods...
  */

  memset(event_counts, 0, sizeof(event_counts));

  if (argv[1][0] == '<')
    tree = mxmlSAXLoadString(NULL, argv[1], type_cb, sax_cb, NULL);
  else if ((fp = fopen(argv[1], "rb")) == NULL)
  {
    perror(argv[1]);
    return (1);
  }
  else
  {
   /*
    * Read the file...
    */

    tree = mxmlSAXLoadFile(NULL, fp, type_cb, sax_cb, NULL);

    fclose(fp);
  }

  if (!strcmp(argv[1], "test.xml"))
  {
    if (event_counts[MXML_SAX_CDATA] != 1)
    {
      fprintf(stderr, "MXML_SAX_CDATA seen %d times, expected 1 times!\n",
              event_counts[MXML_SAX_CDATA]);
      return (1);
    }

    if (event_counts[MXML_SAX_COMMENT] != 1)
    {
      fprintf(stderr, "MXML_SAX_COMMENT seen %d times, expected 1 times!\n",
              event_counts[MXML_SAX_COMMENT]);
      return (1);
    }

    if (event_counts[MXML_SAX_DATA] != 61)
    {
      fprintf(stderr, "MXML_SAX_DATA seen %d times, expected 61 times!\n",
              event_counts[MXML_SAX_DATA]);
      return (1);
    }

    if (event_counts[MXML_SAX_DIRECTIVE] != 1)
    {
      fprintf(stderr, "MXML_SAX_DIRECTIVE seen %d times, expected 1 times!\n",
              event_counts[MXML_SAX_DIRECTIVE]);
      return (1);
    }

    if (event_counts[MXML_SAX_ELEMENT_CLOSE] != 20)
    {
      fprintf(stderr, "MXML_SAX_ELEMENT_CLOSE seen %d times, expected 20 times!\n",
              event_counts[MXML_SAX_ELEMENT_CLOSE]);
      return (1);
    }

    if (event_counts[MXML_SAX_ELEMENT_OPEN] != 20)
    {
      fprintf(stderr, "MXML_SAX_ELEMENT_OPEN seen %d times, expected 20 times!\n",
              event_counts[MXML_SAX_ELEMENT_OPEN]);
      return (1);
    }
  }

 /*
  * Return...
  */

  return (0);
}