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