Main Page | Data Structures | File List | Data Fields | Globals

parseupdatesxml.c

Go to the documentation of this file.
00001 /*
00002  * luau (Lib Update/Auto-Update): Simple Update Library
00003  * Copyright (C) 2003  David Eklund
00004  *
00005  * - This library is free software; you can redistribute it and/or             -
00006  * - modify it under the terms of the GNU Lesser General Public                -
00007  * - License as published by the Free Software Foundation; either              -
00008  * - version 2.1 of the License, or (at your option) any later version.        -
00009  * -                                                                           -
00010  * - This library is distributed in the hope that it will be useful,           -
00011  * - but WITHOUT ANY WARRANTY; without even the implied warranty of            -
00012  * - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         -
00013  * - Lesser General Public License for more details.                           -
00014  * -                                                                           -
00015  * - You should have received a copy of the GNU Lesser General Public          -
00016  * - License along with this library; if not, write to the Free Software       -
00017  * - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA -
00018  */
00019 
00020 #ifdef HAVE_CONFIG_H
00021 #  include <config.h>
00022 #endif
00023 
00024 #include <stdlib.h>
00025 #include <ctype.h>
00026 #include <string.h>
00027 
00028 #include <libxml/xmlmemory.h>
00029 #include <libxml/parser.h>
00030 #include <glib.h>
00031 
00032 #include "libuau.h"
00033 #include "util.h"
00034 #include "error.h"
00035 #include "parse.h"
00036 #include "parseupdates.h"
00037 
00038 #ifdef WITH_DMALLOC
00039 #  include <dmalloc.h>
00040 #endif
00041 
00042 G_LOCK_DEFINE_STATIC (parse);
00043 
00044 static GPtrArray *updates;
00045 static AUpdate *currUpdate;
00046 
00047 static void parseUpdates  (xmlDocPtr doc, xmlNodePtr node);
00048 static void parseUpdate   (xmlDocPtr doc, xmlNodePtr node, xmlChar *type);
00049 
00050 static void parseSoftware (xmlDocPtr doc, xmlNodePtr node);
00051 static void parsePackage  (xmlDocPtr doc, xmlNodePtr node);
00052 static void parseMessage  (xmlDocPtr doc, xmlNodePtr node);
00053 static void parseLibupdate(xmlDocPtr doc, xmlNodePtr node);
00054 static void parseGenericInfo(xmlDocPtr doc, xmlNodePtr node);
00055 static void parseUpdateInfo(xmlDocPtr doc, xmlNodePtr node, AUpdateType type);
00056 
00057 static gboolean parseQuantData(void **data, char *str, AQuantDataType quantDataType);
00058 
00059 
00060 GPtrArray *
00061 luau_parseUpdateFileXML(char *contents) {
00062         xmlDocPtr doc;
00063         xmlNodePtr node;
00064         xmlChar *interfaceStr;
00065         AInterface xmlInterface, readableInterface;
00066         gboolean result;
00067         GPtrArray *ret;
00068         
00069         G_LOCK (parse);
00070         
00071         updates = g_ptr_array_new();
00072         doc = xmlParseMemory(contents, strlen(contents));
00073         node = xmlDocGetRootElement(doc);
00074         if (node == NULL) {
00075                 ERROR("XML Updates file could not be parsed");
00076                 xmlFreeDoc(doc);
00077                 return NULL;
00078         }
00079         
00080         if (! xmlStrEqual(node->name, (const xmlChar *) "luau-repository")) {
00081                 ERROR("XML Updates error: Invalid root element");
00082                 xmlFreeDoc(doc);
00083                 return NULL;
00084         }
00085         
00086         interfaceStr = xmlGetProp(node, "interface");
00087         result = luau_parseInterface(&xmlInterface, interfaceStr);
00088         if (result == FALSE) {
00089                 ERROR("XML interface version either not specified or unreadable - will continue, but may not be able to parse");
00090         } else {
00091                 readableInterface.major = LUAU_XML_INTERFACE_MAJOR;
00092                 readableInterface.minor = LUAU_XML_INTERFACE_MINOR;
00093                 if (!luau_satisfiesInterface(&readableInterface, &xmlInterface))
00094                         ERROR("Unsupported XML interface specified - will continue, but will most likely encounter errors");
00095         }
00096         
00097         parseUpdates(doc, node);
00098         
00099         xmlFreeDoc(doc);
00100         
00101         ret = updates;
00102         
00103         G_UNLOCK (parse);
00104         
00105         return ret;
00106 }
00107 
00108 /* Non-Interface Methods */
00109 
00110 static void
00111 parseUpdates(xmlDocPtr doc, xmlNodePtr node) {
00112         xmlChar *type;
00113         gboolean foundProgInfo = FALSE;
00114         for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
00115                 if (xmlStrEqual(node->name, (const xmlChar *) "update")) {
00116                         type = xmlGetProp(node, "type");
00117                         parseUpdate(doc, node, type);
00118                         xmlFree(type);
00119                 } else if (xmlStrEqual(node->name, (const xmlChar *) "software")) {
00120                         parseUpdate(doc, node, "software");
00121                         currUpdate->newVersion = xmlGetProp(node, "version");
00122                         if (currUpdate->id == NULL)
00123                                 currUpdate->id = g_strdup(currUpdate->newVersion);
00124                 } else if (xmlStrEqual(node->name, (const xmlChar *) "program-info")) {
00125                         /* we can skip this since it isn't relevant to parsing updates - we do, however,
00126                            check to make sure only one <program-info> tag is specified */
00127                    if (foundProgInfo)
00128                                 ERROR("Two <program-info> tags found - only one is allowed");
00129                    foundProgInfo = TRUE;
00130                 } else if (! (xmlStrEqual(node->name, (const xmlChar *) "text")) ) {
00131                         ERROR("Only tags allowed in <luau-repository> root tag are <update>, <software>, and <program-info>; found '%s', skipping", (const char*) node->name);
00132                 }
00133         }
00134         
00135         if (!foundProgInfo)
00136                 ERROR("No <program-info> tag found - required by DTD");
00137 }
00138 
00139 static void
00140 parseUpdate(xmlDocPtr doc, xmlNodePtr node, xmlChar *type) {
00141         /* Create and initialize a new AUpdate object */
00142         currUpdate = (AUpdate*) g_malloc(sizeof(AUpdate));
00143         memset(currUpdate, 0, sizeof(AUpdate));
00144         currUpdate->keywords = g_ptr_array_new();
00145         currUpdate->packages = g_ptr_array_new();
00146         currUpdate->quantifiers = NULL;
00147         g_ptr_array_add(updates, currUpdate); /* ... and add it to the list */
00148         
00149         if (type == NULL) {
00150                 ERROR("No type specified for update: skipping");
00151         }
00152         else if (xmlStrcasecmp(type, "software")  == 0) { currUpdate->type = LUAU_SOFTWARE;  }
00153         else if (xmlStrcasecmp(type, "message" )  == 0) { currUpdate->type = LUAU_MESSAGE;   }
00154         else if (xmlStrcasecmp(type, "luau-config") == 0) { currUpdate->type = LUAU_LIBUPDATE; }
00155         else { 
00156                 ERROR("Unknown 'update' type specified: %s - Skipping", type);
00157                 return;
00158         }
00159         DBUGOUT("Found update of type %s", type);
00160         
00161         parseUpdateInfo(doc, node, currUpdate->type);
00162 }
00163 
00164 static void
00165 parseUpdateInfo(xmlDocPtr doc, xmlNodePtr node, AUpdateType type) {
00166         parseGenericInfo(doc, node);
00167         if (type == LUAU_SOFTWARE)
00168                 parseSoftware(doc, node);
00169         if (type == LUAU_MESSAGE)
00170                 parseMessage(doc, node);
00171         else if (type == LUAU_LIBUPDATE)
00172                 parseLibupdate(doc, node);
00173 }
00174 
00175 static void
00176 parseGenericInfo(xmlDocPtr doc, xmlNodePtr node) {
00177         static const char *symbols[ ] = {"id",       "i",
00178                                          "short",    "s",
00179                                          "long",     "l",
00180                                          "keyword",  "k",
00181                                          "date",     "d",
00182                                          "valid",    "v",
00183                                           NULL };
00184         char result, *temp;
00185         AQuantifier *quant = NULL;
00186         AQuantDataType quantDataType;
00187         
00188         for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
00189                 result = lutil_parse_parseSymbolArray((const char *)node->name, symbols);
00190                 switch (result) {
00191                         case 'i':
00192                                 temp = (char*) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
00193                                 currUpdate->id = g_strdup(lutil_parse_deleteWhitespace(temp));
00194                                 xmlFree(temp);
00195                                 break;
00196                         case 's':
00197                                 temp = (char*) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
00198                                 currUpdate->shortDesc = g_strdup(lutil_parse_deleteWhitespace(temp));
00199                                 xmlFree(temp);
00200                                 break;
00201                         case 'l':
00202                                 temp = (char*) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
00203                                 currUpdate->fullDesc = g_strdup(lutil_parse_deleteWhitespace(temp));
00204                                 xmlFree(temp);
00205                                 break;
00206                         case 'k':
00207                                 temp = (char*) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
00208                                 g_ptr_array_add(currUpdate->keywords, g_strdup(lutil_parse_deleteWhitespace(temp)));
00209                                 xmlFree(temp);
00210                                 break;
00211                         case 'd':
00212                                 temp = (char*) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
00213                                 currUpdate->date = g_malloc(sizeof(ADate));
00214                                 luau_parseDate(currUpdate->date, lutil_parse_deleteWhitespace(temp));
00215                                 xmlFree(temp);
00216                                 break;
00217                         case 'v':
00218                                 temp = (char*) xmlGetProp(node, "type");
00219                                 
00220                                 quantDataType = luau_parseQuantDataType(temp);
00221                                 
00222                                 if (quantDataType == LUAU_QUANT_DATA_INVALID) {
00223                                         ERROR("Unsupported quantifier data type: '%s'", temp);
00224                                         xmlFree(temp);
00225                                         break;
00226                                 }
00227                                 xmlFree(temp);
00228                                 
00229                                 if (currUpdate->quantifiers == NULL)
00230                                         currUpdate->quantifiers = g_ptr_array_new();
00231                                 
00232                                 temp = (char*) xmlGetProp(node, "from");
00233                                 if (temp != NULL) {
00234                                         quant = g_malloc(sizeof(AQuantifier));
00235                                         quant->qtype = LUAU_QUANT_FROM;
00236                                         quant->dtype = quantDataType;
00237                                         parseQuantData(&(quant->data), temp, quantDataType);
00238                                         
00239                                         g_ptr_array_add(currUpdate->quantifiers, quant);
00240                                         
00241                                         xmlFree(temp);
00242                                 }
00243                                 
00244                                 temp = (char*) xmlGetProp(node, "to");
00245                                 if (temp != NULL) {
00246                                         quant = g_malloc(sizeof(AQuantifier));
00247                                         quant->qtype = LUAU_QUANT_TO;
00248                                         quant->dtype = quantDataType;
00249                                         parseQuantData(&(quant->data), temp, quantDataType);
00250                                         
00251                                         g_ptr_array_add(currUpdate->quantifiers, quant);
00252                                         
00253                                         xmlFree(temp);
00254                                 }
00255                                 
00256                                 temp = (char*) xmlGetProp(node, "for");
00257                                 if (temp != NULL) {
00258                                         quant = g_malloc(sizeof(AQuantifier));
00259                                         quant->qtype = LUAU_QUANT_FOR;
00260                                         quant->dtype = quantDataType;
00261                                         parseQuantData(&(quant->data), temp, quantDataType);
00262                                         
00263                                         g_ptr_array_add(currUpdate->quantifiers, quant);
00264                                         
00265                                         xmlFree(temp);
00266                                 }
00267                                 
00268                                 break;
00269                 }
00270         }
00271 }
00272 
00273 static void
00274 parseSoftware(xmlDocPtr doc, xmlNodePtr node) { 
00275         static const char *symbols[ ] = {"package",   "p",
00276                                          /* "set",       "s", */
00277                                                                          "interface", "i",
00278                                                                          "display-version", "d",
00279                                           NULL };
00280         char result, *temp;
00281         
00282         for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
00283                 result = lutil_parse_parseSymbolArray((const char *)node->name, symbols);
00284                 switch (result) {
00285                         case 'p':
00286                                 parsePackage(doc, node);
00287                                 break;
00288                         case 'i':
00289                                 temp = (char*) xmlGetProp(node, "version");
00290                                 luau_parseInterface(&(currUpdate->interface), temp);
00291                                 xmlFree(temp);
00292                                 
00293                                 break;
00294                         case 'd':
00295                                 temp = (char*) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
00296                                 currUpdate->newDisplayVersion = g_strdup(lutil_parse_deleteWhitespace(temp));
00297                                 xmlFree(temp);
00298                                 break;
00299                 }
00300         }
00301 }
00302 
00303 static void
00304 parsePackage(xmlDocPtr doc, xmlNodePtr node) {
00305         GPtrArray *mirrors;
00306         APackage *pkg;
00307         char *loc, *percentage, *temp;
00308         int i, total;
00309         
00310         pkg = (APackage*) g_malloc(sizeof(APackage));
00311         g_ptr_array_add(currUpdate->packages, pkg);
00312         
00313         mirrors = g_ptr_array_new();
00314         pkg->mirrors = mirrors;
00315         
00316         temp = (char*) xmlGetProp(node, "md5");
00317         if (temp != NULL) {
00318                 strncpy(pkg->md5sum, temp, 33);
00319                 xmlFree(temp);
00320         } else {
00321                 pkg->md5sum[0] = '\0';
00322         }
00323         
00324         temp = (char*) xmlGetProp(node, "size");
00325         if (temp != NULL) {
00326                 pkg->size = atoi(temp);
00327                 xmlFree(temp);
00328         } else {
00329                 pkg->size = 0;
00330         }
00331         
00332         temp = (char*) xmlGetProp(node, "type");
00333         if (temp != NULL) {
00334                 pkg->type = luau_parsePkgType(temp);
00335                 xmlFree(temp);
00336         } else {
00337                 pkg->type = LUAU_UNKNOWN;
00338         }
00339         
00340         currUpdate->availableFormats = (currUpdate->availableFormats | pkg->type);
00341         
00342         temp = (char*) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
00343         loc = g_strdup(lutil_parse_deleteWhitespace(temp));
00344         xmlFree(temp);
00345         
00346         if (loc == NULL || loc[0] != '\0') {
00347                 g_ptr_array_add(mirrors, GINT_TO_POINTER (100));
00348                 g_ptr_array_add(mirrors, loc);
00349         } else if (node->xmlChildrenNode != NULL) {
00350                 nnull_g_free(loc);
00351                 
00352                 total = 0;
00353                 for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
00354                         if (lutil_streq(node->name, "mirror")) {
00355                                 percentage = (char*) xmlGetProp(node, "weight");
00356                                 if (percentage == NULL) {
00357                                         DBUGOUT("Weight for mirror not specified - using default");
00358                                         g_ptr_array_add(mirrors, GINT_TO_POINTER (100));
00359                                         total += 100;
00360                                 } else {
00361                                         i = atoi(percentage);
00362                                         if (i == 0) i = 1;
00363                                         g_ptr_array_add(mirrors, GINT_TO_POINTER (i));
00364                                         xmlFree(percentage);
00365                                         
00366                                         DBUGOUT("Weight for mirror: %d", i);
00367                                         
00368                                         total += i;
00369                                 }
00370                                 
00371                                 temp = (char*) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
00372                                 loc = g_strdup(lutil_parse_deleteWhitespace(temp));
00373                                 g_ptr_array_add(mirrors, loc);
00374                                 xmlFree(temp);
00375                                 
00376                                 DBUGOUT("Mirror location: %s", loc);
00377                         } else if (!lutil_streq(node->name, "text")) {
00378                                 ERROR("Invalid tag '<%s>' in <package> section (only '<mirror>' allowed)", node->name);
00379                         }
00380                 }
00381                 
00382                 if (total != 100) {
00383                         int n, sum;
00384                         float factor;
00385                         
00386                         factor = ((float)100 / total);
00387                         sum = 0;
00388                         
00389                         DBUGOUT("Rescaling mirror weights by factor of %.01f (total = %d)", factor, total);
00390                         for (i = 0; i < mirrors->len; i+=2) {
00391                                 if (i+2 == mirrors->len) /* last mirror */
00392                                         n = 100 - sum;
00393                                 else {
00394                                         n = GPOINTER_TO_INT (g_ptr_array_index(mirrors, i));
00395                                         n *= factor;
00396                                 }
00397                                 
00398                                 mirrors->pdata[i] = GINT_TO_POINTER (n);
00399                                 
00400                                 sum += n;
00401                         }
00402                 }
00403                 
00404 #ifdef DEBUG
00405                 for (i = 0; i < pkg->mirrors->len; i += 2)
00406                         DBUGOUT("URL: %s; weight: %d\n", (char*)g_ptr_array_index(mirrors, i+1), GPOINTER_TO_INT (g_ptr_array_index(mirrors, i)));
00407 #endif /*DEBUG*/
00408         } else {
00409                 nnull_g_free(loc);
00410                 ERROR("Package specified in software repository, but no URLs given!");
00411         }
00412 }
00413 
00414 
00415 
00416 static void
00417 parseMessage(xmlDocPtr doc, xmlNodePtr node) {
00418         /* Nothing to do here!  There are (currently) no XML tags specific to message updates */
00419 }
00420 
00421 static void
00422 parseLibupdate(xmlDocPtr doc, xmlNodePtr node) {
00423         static const char *symbols[ ] = { "set", "s",
00424                                           NULL };
00425         char result;
00426         
00427         for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
00428                 result = lutil_parse_parseSymbolArray((const char *)node->name, symbols);
00429                 switch (result) {
00430                         case 's':
00431                                 currUpdate->newURL = (char*) xmlGetProp(node, "url");
00432                                 break;
00433                 }
00434         }
00435 }
00436 
00437 static gboolean
00438 parseQuantData(void **data, char *str, AQuantDataType quantDataType) {
00439         gboolean result;
00440         
00441         if (quantDataType == LUAU_QUANT_DATA_VERSION || quantDataType == LUAU_QUANT_DATA_KEYWORD) {
00442                 *data = g_strdup(str);
00443                 result = TRUE;
00444         } else if (quantDataType == LUAU_QUANT_DATA_INTERFACE) {
00445                 *data = g_malloc(sizeof(AInterface));
00446                 result = luau_parseInterface((AInterface*) *data, str);
00447         } else if (quantDataType == LUAU_QUANT_DATA_DATE) {
00448                 *data = g_malloc(sizeof(ADate));
00449                 result = luau_parseDate((ADate*) *data, str);
00450         } else {
00451                 ERROR("Internal Error: Unrecognized quantifier data type (%d)", quantDataType);
00452                 result = FALSE;
00453         }
00454         
00455         return result;
00456 }
00457 

Generated on Mon Apr 12 22:17:11 2004 for luau by doxygen 1.3.2