Nut/OS  4.10.3
API Reference
uxmlstream.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 by egnite GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00021  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00034 /*
00035  * \file pro/uxmlstream.c
00036  * \brief Micro XML stream parser.
00037  *
00038  * \verbatim
00039  * $Id: uxmlstream.c 3452 2011-06-01 08:51:23Z haraldkipp $
00040  * \endverbatim
00041  */
00042 
00043 #include <sys/types.h>
00044 #include <sys/heap.h>
00045 
00046 #include <stdlib.h>
00047 #include <string.h>
00048 #include <ctype.h>
00049 #include <memdebug.h>
00050 
00051 #include <pro/uxml.h>
00052 
00057 
00058 #ifndef MAX_UXMLTAG_SIZE
00059 
00064 #define MAX_UXMLTAG_SIZE     512
00065 #endif
00066 
00067 #ifndef MAX_UXMLTKN_SIZE
00068 
00075 #define MAX_UXMLTKN_SIZE     64
00076 #endif
00077 
00078 static int UxmlReadTag(FILE * stream, char *data, size_t size)
00079 {
00080     int rc = -1;
00081     int ch;
00082     int qc = 0;
00083     int state = 1;
00084     char *dp = NULL;
00085 
00086     while (state) {
00087         ch = fgetc(stream);
00088         if (ch == EOF || ch == 0) {
00089             break;
00090         }
00091         switch (state) {
00092         case 1:
00093             /* Searching first bracket. */
00094             if (ch == '<') {
00095                 /* Opening bracket found. Start collecting. */
00096                 dp = data;
00097                 state = 4;
00098             } else if (ch == '"' || ch == '\'') {
00099                 /* Quote found. Skip quoted string. */
00100                 qc = ch;
00101                 state++;
00102             }
00103             break;
00104         case 2:
00105             /* Skipping quoted string. */
00106         case 5:
00107             /* Collecting quoted string. */
00108             if (ch == qc) {
00109                 /* End quote found. */
00110                 state--;
00111             }
00112             break;
00113         case 3:
00114             /* Compressing spaces. */
00115             if (isspace(ch)) {
00116                 ch = 0;
00117                 break;
00118             }
00119             state = 4;
00120             /* Fall through. */
00121         case 4:
00122             /* Collecting data. */
00123             if (ch == '>') {
00124                 rc = 0;
00125                 state = 0;
00126             } else if (ch == '"' || ch == '\'') {
00127                 qc = ch;
00128                 state++;
00129             } else if (isspace(ch)) {
00130                 ch = ' ';
00131                 state = 3;
00132             }
00133             break;
00134         }
00135         if (dp && ch) {
00136             if (size > 1) {
00137                 size--;
00138                 *dp++ = ch;
00139             } else {
00140                 break;
00141             }
00142         }
00143     }
00144     if (dp) {
00145         *dp = 0;
00146     }
00147     return rc;
00148 }
00149 
00192 UXML_NODE *UxmlParseStream(FILE * stream, char **f_tags, char **f_attr)
00193 {
00194     char *tag;
00195     char *tkn;
00196     char *tp;
00197     UXML_NODE *root = NULL;
00198     UXML_NODE *node = NULL;
00199     UXML_NODE *nn;
00200 
00201     /* Allocate the tag buffer. */
00202     if ((tag = malloc(MAX_UXMLTAG_SIZE)) == NULL) {
00203         return NULL;
00204     }
00205     /* Allocate the token buffer. */
00206     if ((tkn = malloc(MAX_UXMLTKN_SIZE)) == NULL) {
00207         free(tag);
00208         return NULL;
00209     }
00210     for (;;) {
00211         if (NutHeapAvailable() < 8192) {
00212             break;
00213         }
00214         /* Read the next tag. */
00215         if (UxmlReadTag(stream, tag, MAX_UXMLTAG_SIZE)) {
00216             /* No more tags or error. */
00217             break;
00218         }
00219         /* Parse the tag. */
00220         if ((tp = UxmlParseTag(tag + 1, tkn, MAX_UXMLTKN_SIZE)) != NULL) {
00221             if (isalpha((unsigned char)*tkn) && UxmlFilterMatch(tkn, f_tags)) {
00222                 /* Save pointer to tp because needed to determine self closing tag */
00223                 char *old_tp = tp;
00224 
00225                 /*
00226                  * New node.
00227                  */
00228                 if ((nn = UxmlNodeCreate(tkn)) == NULL) {
00229                     break;
00230                 }
00231                 if (root == NULL) {
00232                     /* Root entry. */
00233                     root = nn;
00234                     node = nn;
00235                 } else if (node == NULL) {
00236                     /* No active node. Add root siblings. */
00237                     node = UxmlTreeAddSibling(root, nn);
00238                 } else {
00239                     /* New node is a child of the currently active one. */
00240                     node = UxmlTreeAddChild(node, nn);
00241                 }
00242                 /* Parse the attributes. */
00243                 for (;;) {
00244                     if ((tp = UxmlParseTag(tp, tkn, MAX_UXMLTKN_SIZE)) == NULL || *tkn == '>') {
00245                         /* End of this tag or error. */
00246                         break;
00247                     }
00248                     if (isalpha((unsigned char)*tkn) && UxmlFilterMatch(tkn, f_attr)) {
00249                         char *name = strdup(tkn);
00250 
00251                         if (name) {
00252                             if ((tp = UxmlParseTag(tp, tkn, MAX_UXMLTKN_SIZE)) == NULL || *tkn != '=') {
00253                                 free(name);
00254                                 break;
00255                             }
00256                             if ((tp = UxmlParseTag(tp, tkn, MAX_UXMLTKN_SIZE)) == NULL || *tkn == '>') {
00257                                 free(name);
00258                                 break;
00259                             }
00260                             UxmlNodeAddAttrib(node, name, tkn);
00261                             free(name);
00262                         }
00263                     }
00264                 }
00265                 /* Check if tag is self closing */
00266                 if (node && strlen(old_tp) > 1 && old_tp[strlen(old_tp) - 2]=='/') {
00267                     node = node->xmln_parent;
00268                 }
00269             } else if (*tkn == '/') {
00270                 /*
00271                  * End of the active node.
00272                  */
00273                 tp = UxmlParseTag(tp, tkn, MAX_UXMLTKN_SIZE);
00274                 if (tp && node && strcasecmp(node->xmln_name, tkn) == 0) {
00275                     node = node->xmln_parent;
00276                 }
00277             }
00278         }
00279     }
00280     /* Clean up. */
00281     free(tag);
00282     free(tkn);
00283 
00284     return root;
00285 }
00286