00001 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 
00054 
00055 #include "config.h"
00056 
00057 #include <sys/types.h>
00058 
00059 #include <assert.h>
00060 #include <ctype.h>
00061 #include <limits.h>
00062 #include <stdbool.h>
00063 #include <string.h>
00064 #include <errno.h>
00065 
00066 #include <expat.h>
00067 
00068 #include <discover/discover.h>
00069 #include <discover/discover-xml.h>
00070 
00071 #include <discover/load-url.h>
00072 #include <discover/device.h>
00073 #include <discover/utils.h>
00074 #include <discover/stack.h>
00075 
00077 #define IDLEN 5
00078 
00079 static discover_device_t *devices_xml[BUS_COUNT];
00080 
00082 enum state { START, FINISH, DEVICE, DATA };
00083 struct context {
00084     enum state state;
00085 
00086     discover_xml_busclass_t *busclasses;
00087     discover_xml_vendor_t *vendors;
00088 
00089     
00090     discover_device_t **dhead;
00091     discover_device_t *dtail;
00092 
00093     
00094     discover_xml_stack *stack;
00095 
00096 
00097 
00098 
00099     int nesting;
00100     int last_nesting;
00101 
00102     int unknown_level; 
00103 };
00104 
00105 static char *known_device_elements[] = {
00106     "data",
00107     "device",
00108     "device_list",
00109     NULL
00110 };
00111 
00112 static void
00113 get_data_failure_handler(discover_error_t **status, char *url)
00114 {
00115     char *errmsg;
00116     static int maxurlsize = 1024; 
00117 
00118 
00119     if((*status)->code == DISCOVER_EIO) {
00120         errmsg = _discover_xmalloc(maxurlsize + 1);
00121         snprintf(errmsg, maxurlsize, "Resource not found: %s", url);
00122         (*status)->create_message(status, errmsg);
00123         free(errmsg);
00124     } else {
00125         if (errno) {
00126             errmsg = _discover_xmalloc(maxurlsize + 1);
00127             snprintf(errmsg, maxurlsize, "Problem loading resource: %s: %s",
00128                      strerror(errno), url);
00129             (*status)->create_message(status, errmsg);
00130             free(errmsg);
00131         } else {
00132             (*status)->create_message(status,
00133                     "Unknown failure from system-dependent libraries");
00134         }
00135     }
00136 }
00137 
00138 static bool
00139 unknown_device_element(const XML_Char * const tag)
00140 {
00141     int i;
00142     for (i = 0; known_device_elements[i] != NULL; i++) {
00143         if (strcmp(tag, known_device_elements[i]) == 0)
00144             return false;
00145     }
00146     return true;
00147 }
00148 
00149 static void
00150 create_device(struct context *context, const XML_Char *attrs[])
00151 {
00152     int i;
00153     char *busclass, *model_id, *model_name, *vendor_id, *vendor_name;
00154     discover_device_t *new_device;
00155 
00156     assert(context != NULL);
00157     assert(attrs != NULL);
00158 
00159     busclass = model_id = model_name = vendor_id = NULL;
00160     for (i = 0; attrs[i]; i += 2) {
00161         if (strcmp(attrs[i], "busclass") == 0) {
00162             busclass = (char *)attrs[i + 1];
00163 
00164         } else if (strcmp(attrs[i], "model") == 0) {
00165             model_id = (char *)attrs[i + 1];
00166 
00167         } else if (strcmp(attrs[i], "model_name") == 0) {
00168             model_name = (char *)attrs[i + 1];
00169 
00170         } else if (strcmp(attrs[i], "vendor") == 0) {
00171             vendor_id = (char *)attrs[i + 1];
00172         }
00173     }
00174 
00175     assert(model_id != NULL);
00176     assert(model_name != NULL);
00177     assert(vendor_id != NULL);
00178 
00179     vendor_name = discover_xml_vendor_id2name(context->vendors, vendor_id);
00180     assert(vendor_name != NULL);
00181 
00182     context->stack = discover_xml_stack_new();
00183 
00184     new_device = discover_device_new();
00185     new_device->busclasses = context->busclasses;
00186     new_device->vendors = context->vendors;
00187     if (busclass) {
00188         new_device->busclass = _discover_xstrdup(busclass);
00189     } else {
00190         new_device->busclass = NULL;
00191     }
00192     new_device->model_id = _discover_xstrdup(model_id);
00193     new_device->model_name = _discover_xstrdup(model_name);
00194     new_device->vendor_id = _discover_xstrdup(vendor_id);
00195     new_device->vendor_name = _discover_xstrdup(vendor_name);
00196     new_device->data = NULL;
00197     new_device->next = NULL;
00198 
00199     if (*(context->dhead)) {
00200         context->dtail->next = new_device;
00201         context->dtail = new_device;
00202     } else {
00203         *(context->dhead) = new_device;
00204         context->dtail = new_device;
00205     }
00206 }
00207 
00208 static void
00209 create_data(struct context *context, const XML_Char *attrs[])
00210 {
00211     discover_data_t *new_data, *current_data;
00212     discover_xml_stack *stack;
00213     int i;
00214     char *discover_class, *version;
00215 
00216     assert(context != NULL);
00217     assert(attrs != NULL);
00218 
00219     new_data = discover_data_new();
00220     new_data->text = NULL;
00221     new_data->next = new_data->prev = new_data->child = NULL;
00222 
00223 
00224     discover_class = version = NULL;
00225     for (i = 0; attrs[i]; i += 2) {
00226         if (strcmp(attrs[i], "class") == 0) {
00227             discover_class = (char *)attrs[i + 1];
00228         } else if (strcmp(attrs[i], "version") == 0) {
00229             version = (char *)attrs[i + 1];
00230         }
00231     }
00232 
00233     assert(discover_class != NULL);
00234 
00235     new_data->discover_class = _discover_xstrdup(discover_class);
00236     if (version) {
00237         new_data->version = _discover_xstrdup(version);
00238     }
00239 
00240     stack = context->stack;
00241 
00242     assert(stack != NULL);
00243 
00244     current_data = discover_xml_stack_get(stack);
00245 
00246     if(current_data) { 
00247         
00248         if(stack->depth > context->nesting) {
00249             discover_xml_stack_pop(&stack);
00250             
00251             new_data->prev = current_data;
00252             new_data->prev->next = new_data;
00253             if(context->nesting) {
00254                 new_data->parent =
00255                     discover_xml_stack_getbynum(stack, context->nesting);
00256             }
00257         } else {
00258             
00259             new_data->parent = current_data;
00260             new_data->parent->child = new_data;
00261         }
00262     }
00263 
00264     discover_xml_stack_push(&stack, new_data);
00265     context->stack = stack;
00266 }
00267 
00268 static void
00269 start_element(void *ctx, const XML_Char *name, const XML_Char *attrs[])
00270 {
00271     struct context *context = ctx;
00272 
00273     assert(context != NULL);
00274     assert(name != NULL);
00275     assert(attrs != NULL);
00276 
00277 
00278     if (unknown_device_element(name)) {
00279         context->unknown_level++;
00280         return;
00281     }
00282 
00283     if (context->unknown_level > 0) {
00284         return;
00285     }
00286 
00287     switch (context->state) {
00288     case FINISH:
00289         return;
00290 
00291     case START:
00292         if (strcmp(name, "device") == 0) {
00293             context->state = DEVICE;
00294             create_device(context, attrs);
00295         }
00296         break;
00297 
00298     case DEVICE:
00299         if (strcmp(name, "data") == 0) {
00300             context->nesting = context->last_nesting = 0;
00301             context->state = DATA;
00302         }
00303         
00304 
00305     case DATA:
00306         if (strcmp(name, "data") == 0) {
00307             create_data(context, attrs);
00308             context->last_nesting = context->nesting;
00309             context->nesting++;
00310         }
00311         break;
00312     }
00313 }
00314 
00315 static void
00316 end_element(void *ctx, const XML_Char *name)
00317 {
00318     struct context *context = ctx;
00319     discover_device_t *device;
00320     discover_data_t *current_data;
00321     discover_xml_stack *stack;
00322 
00323 
00324     assert(context != NULL);
00325     assert(name != NULL);
00326 
00327 
00328     if (unknown_device_element(name)) {
00329         context->unknown_level--;
00330         return;
00331     }
00332 
00333     if (context->unknown_level > 0) {
00334         return;
00335     }
00336 
00337     switch (context->state) {
00338     case FINISH:
00339     case START:
00340         break;
00341 
00342     case DEVICE:
00343         context->state = START;
00344         device = context->dtail;
00345         stack = context->stack;
00346         current_data = discover_xml_stack_get(stack);
00347         device->data = discover_data_get_first(current_data);
00348 
00349         while (discover_xml_stack_pop(&(context->stack))) ;
00350         discover_xml_stack_destroy(context->stack);
00351         context->stack = NULL;
00352 
00353         break;
00354 
00355     case DATA:
00356         context->nesting--;
00357         stack = context->stack;
00358         if((context->nesting + 2) <= stack->depth) {
00359             while((context->nesting + 1 < stack->depth) &&
00360                     stack->depth > 1) {
00361                 discover_xml_stack_pop(&stack);
00362             }
00363             context->stack = stack;
00364         }
00365 
00366         if (context->nesting == 0) {
00367             context->state = DEVICE;
00368         }
00369     }
00370 }
00371 
00372 static void
00373 cdata(void *ctx, const XML_Char *data, int len)
00374 {
00375     struct context *context = ctx;
00376     size_t old_len;
00377     discover_data_t *current_data;
00378 
00379     assert(context != NULL);
00380     assert(data != NULL);
00381 
00382     if (context->state == DATA
00383         && context->nesting > context->last_nesting) {
00384         assert(context->stack != NULL);
00385         current_data = context->stack->data;
00386         assert(current_data != NULL);
00387 
00388         if (!current_data->text) {
00389             old_len = 0;
00390             current_data->text = _discover_xmalloc(1);
00391             current_data->text[0] = '\0';
00392         } else {
00393             old_len = strlen(current_data->text);
00394         }
00395         current_data->text
00396             = _discover_xrealloc(current_data->text,
00397                                  old_len + len + 1);
00398         strncat(current_data->text,
00399                 (const char *)data,
00400                 (unsigned int)len);
00401     }
00402 }
00403 
00418 
00419 
00420 
00421 
00422 
00423 
00424 void
00425 discover_xml_merge_device_url(discover_device_t **dlist, char *url,
00426                               discover_xml_busclass_t *busclasses,
00427                               discover_xml_vendor_t *vendors,
00428                               discover_error_t *status)
00429 {
00430     XML_Parser parser;
00431     struct context context;
00432 
00433     assert(url != NULL);
00434     assert(busclasses != NULL);
00435     assert(vendors != NULL);
00436     assert(status != NULL);
00437 
00438     context.state = START;
00439     context.dhead = dlist;
00440     if (*(context.dhead)) {
00441         discover_device_t *next = *(context.dhead);
00442         while(next->next != NULL) {
00443             next = next->next;
00444         }
00445         context.dtail = next;
00446     } else {
00447         context.dtail = NULL;
00448     }
00449 
00450     context.busclasses = busclasses;
00451     context.vendors = vendors;
00452     context.unknown_level = 0;
00453     context.stack = NULL;
00454 
00455     parser = XML_ParserCreate(NULL);
00456     XML_SetElementHandler(parser, start_element, end_element);
00457     XML_SetCharacterDataHandler(parser, cdata);
00458     XML_SetUserData(parser, &context);
00459 
00460     if (!_discover_load_url(url, parser)) {
00461         XML_ParserFree(parser);
00462         status->code = DISCOVER_EIO;
00463         return;
00464     }
00465 
00466     if (!XML_Parse(parser, "", 0, 1)) {
00467         XML_ParserFree(parser);
00468         status->code = DISCOVER_EXML;
00469         return;
00470     }
00471 
00472     XML_ParserFree(parser);
00473 
00474     return;
00475 }
00476 
00483 discover_device_t *
00484 discover_xml_get_devices(discover_bus_t bus, discover_error_t *status)
00485 {
00486     discover_xml_url_t *urls, *i;
00487     char *url;
00488     discover_xml_busclass_t *busclasses;
00489     discover_xml_vendor_t *vendors;
00490 
00491     assert(status != NULL);
00492 
00493     status->code = 0;
00494 
00495     if (!devices_xml[bus]) {
00496         urls = discover_xml_get_data_urls(bus, DEVICE, status);
00497         if (status->code != 0) {
00498             return NULL;
00499         }
00500 
00501         busclasses = discover_xml_get_busclasses(bus, status);
00502         if (status->code != 0) {
00503             return NULL;
00504         }
00505 
00506         vendors = discover_xml_get_vendors(bus, status);
00507         if (status->code != 0) {
00508             return NULL;
00509         }
00510 
00511         for (i = urls;
00512              i;
00513              i = discover_xml_url_get_next(i)) {
00514             url = discover_xml_url_get_url(i);
00515             discover_xml_merge_device_url(&(devices_xml[bus]), url,
00516                                           busclasses, vendors, status);
00517             if (status->code != 0) {
00518                 get_data_failure_handler(&status, url);
00519             }
00520         }
00521     }
00522 
00523 
00524     return devices_xml[bus];
00525 }
00526 
00530 void
00531 discover_xml_free_devices(void)
00532 {
00533     int i;
00534     for (i = 0; i < BUS_COUNT; i++) {
00535         discover_device_free(devices_xml[i], 1);
00536         devices_xml[i] = NULL;
00537     }
00538 }
00539 
00549 discover_device_t *
00550 discover_xml_find_device(discover_device_t *xml_devices,
00551                          char *target_vendor, char *target_model,
00552                          discover_error_t *status)
00553 {
00554     discover_device_t *device;
00555 
00556     assert(target_vendor || target_model);
00557 
00558     for (device = xml_devices;
00559          device;
00560          device = device->next) {
00561         if (target_vendor && target_model) {
00562             if (strcmp(device->model_id, target_model) == 0
00563                 && strcmp(device->vendor_id, target_vendor) == 0) {
00564                 break;
00565             }
00566         } else if (target_vendor) {
00567             if (strcmp(device->vendor_id, target_vendor) == 0) {
00568                 break;
00569             }
00570         } else {
00571             
00572             if (strcmp(device->model_id, target_model) == 0) {
00573                 break;
00574             }
00575         }
00576     }
00577 
00578     return device;
00579 }
00580 
00593 discover_device_t *
00594 discover_xml_find_next_device(discover_device_t *xml_devices,
00595                          char *target_vendor, char *target_model,
00596                          discover_error_t *status)
00597 {
00598     return discover_xml_find_device(xml_devices->next,
00599                                     target_vendor, target_model,
00600                                     status);
00601 }
00602 
00603 
00613 discover_device_t *
00614 discover_xml_get_matching_devices(discover_device_t *xml_devices,
00615                                   char *target_vendor, char *target_model,
00616                                   discover_error_t *status)
00617 {
00618     discover_device_t *device, *last, *copy;
00619     discover_device_t *head_device = NULL;
00620 
00621     device = discover_xml_find_device(xml_devices, target_vendor,
00622                                       target_model, status);
00623     last = NULL;
00624 
00625     while(device) {
00626         copy = discover_device_new();
00627         discover_device_copy(device, copy);
00628         copy->next = NULL;
00629         copy->extra = NULL;
00630 
00631         if (last) {
00632             last->extra = copy;
00633         } else {
00634             head_device = copy;
00635         }
00636 
00637         last = copy;
00638 
00639         device = discover_xml_find_next_device(device, target_vendor,
00640                                                target_model, status);
00641     }
00642 
00643     return head_device;
00644 }
00645 
00648 
00649 
00650 
00651 
00652 
00653 
00654