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.h>
00069 #include <discover-xml.h>
00070
00071 #include "load-url.h"
00072 #include "device.h"
00073 #include "utils.h"
00074 #include "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(busclass != NULL);
00176 assert(model_id != NULL);
00177 assert(model_name != NULL);
00178 assert(vendor_id != NULL);
00179
00180 vendor_name = discover_xml_vendor_id2name(context->vendors, vendor_id);
00181 assert(vendor_name != NULL);
00182
00183 context->stack = discover_xml_stack_new();
00184
00185 new_device = discover_device_new();
00186 new_device->busclasses = context->busclasses;
00187 new_device->vendors = context->vendors;
00188 new_device->busclass = _discover_xstrdup(busclass);
00189 new_device->model_id = _discover_xstrdup(model_id);
00190 new_device->model_name = _discover_xstrdup(model_name);
00191 new_device->vendor_id = _discover_xstrdup(vendor_id);
00192 new_device->vendor_name = _discover_xstrdup(vendor_name);
00193 new_device->data = NULL;
00194 new_device->next = NULL;
00195
00196 if (*(context->dhead)) {
00197 context->dtail->next = new_device;
00198 context->dtail = new_device;
00199 } else {
00200 *(context->dhead) = new_device;
00201 context->dtail = new_device;
00202 }
00203 }
00204
00205 static void
00206 create_data(struct context *context, const XML_Char *attrs[])
00207 {
00208 discover_data_t *new_data, *current_data;
00209 discover_xml_stack *stack;
00210 int i;
00211 char *discover_class, *version;
00212
00213 assert(context != NULL);
00214 assert(attrs != NULL);
00215
00216 new_data = discover_data_new();
00217 new_data->text = NULL;
00218 new_data->next = new_data->prev = new_data->child = NULL;
00219
00220
00221 discover_class = version = NULL;
00222 for (i = 0; attrs[i]; i += 2) {
00223 if (strcmp(attrs[i], "class") == 0) {
00224 discover_class = (char *)attrs[i + 1];
00225 } else if (strcmp(attrs[i], "version") == 0) {
00226 version = (char *)attrs[i + 1];
00227 }
00228 }
00229
00230 assert(discover_class != NULL);
00231
00232 new_data->discover_class = _discover_xstrdup(discover_class);
00233 if (version) {
00234 new_data->version = _discover_xstrdup(version);
00235 }
00236
00237 stack = context->stack;
00238
00239 assert(stack != NULL);
00240
00241 current_data = discover_xml_stack_get(stack);
00242
00243 if(current_data) {
00244
00245 if(stack->depth > context->nesting) {
00246 discover_xml_stack_pop(&stack);
00247
00248 new_data->prev = current_data;
00249 new_data->prev->next = new_data;
00250 if(context->nesting) {
00251 new_data->parent =
00252 discover_xml_stack_getbynum(stack, context->nesting);
00253 }
00254 } else {
00255
00256 new_data->parent = current_data;
00257 new_data->parent->child = new_data;
00258 }
00259 }
00260
00261 discover_xml_stack_push(&stack, new_data);
00262 context->stack = stack;
00263 }
00264
00265 static void
00266 start_element(void *ctx, const XML_Char *name, const XML_Char *attrs[])
00267 {
00268 struct context *context = ctx;
00269
00270 assert(context != NULL);
00271 assert(name != NULL);
00272 assert(attrs != NULL);
00273
00274
00275 if (unknown_device_element(name)) {
00276 context->unknown_level++;
00277 return;
00278 }
00279
00280 if (context->unknown_level > 0) {
00281 return;
00282 }
00283
00284 switch (context->state) {
00285 case FINISH:
00286 return;
00287
00288 case START:
00289 if (strcmp(name, "device") == 0) {
00290 context->state = DEVICE;
00291 create_device(context, attrs);
00292 context->stack = discover_xml_stack_new();
00293 }
00294 break;
00295
00296 case DEVICE:
00297 if (strcmp(name, "data") == 0) {
00298 context->nesting = context->last_nesting = 0;
00299 context->state = DATA;
00300 }
00301
00302
00303 case DATA:
00304 if (strcmp(name, "data") == 0) {
00305 create_data(context, attrs);
00306 context->last_nesting = context->nesting;
00307 context->nesting++;
00308 }
00309 break;
00310 }
00311 }
00312
00313 static void
00314 end_element(void *ctx, const XML_Char *name)
00315 {
00316 struct context *context = ctx;
00317 discover_device_t *device;
00318 discover_data_t *current_data;
00319 discover_xml_stack *stack;
00320
00321
00322 assert(context != NULL);
00323 assert(name != NULL);
00324
00325
00326 if (unknown_device_element(name)) {
00327 context->unknown_level--;
00328 return;
00329 }
00330
00331 if (context->unknown_level > 0) {
00332 return;
00333 }
00334
00335 switch (context->state) {
00336 case FINISH:
00337 case START:
00338 break;
00339
00340 case DEVICE:
00341 context->state = START;
00342 device = context->dtail;
00343 stack = context->stack;
00344 current_data = discover_xml_stack_get(stack);
00345 device->data = discover_data_get_first(current_data);
00346 break;
00347
00348 case DATA:
00349 context->nesting--;
00350 stack = context->stack;
00351 if((context->nesting + 2) <= stack->depth) {
00352 while((context->nesting + 1 < stack->depth) &&
00353 stack->depth > 1) {
00354 discover_xml_stack_pop(&stack);
00355 }
00356 context->stack = stack;
00357 }
00358
00359 if (context->nesting == 0) {
00360 context->state = DEVICE;
00361 }
00362 }
00363 }
00364
00365 static void
00366 cdata(void *ctx, const XML_Char *data, int len)
00367 {
00368 struct context *context = ctx;
00369 size_t old_len;
00370 discover_data_t *current_data;
00371
00372 assert(context != NULL);
00373 assert(data != NULL);
00374
00375 if (context->state == DATA
00376 && context->nesting > context->last_nesting) {
00377 assert(context->stack != NULL);
00378 current_data = context->stack->data;
00379 assert(current_data != NULL);
00380
00381 if (!current_data->text) {
00382 old_len = 0;
00383 current_data->text = _discover_xmalloc(1);
00384 current_data->text[0] = '\0';
00385 } else {
00386 old_len = strlen(current_data->text);
00387 }
00388 current_data->text
00389 = _discover_xrealloc(current_data->text,
00390 old_len + len + 1);
00391 strncat(current_data->text,
00392 (const char *)data,
00393 (unsigned int)len);
00394 }
00395 }
00396
00411
00412
00413
00414
00415
00416
00417 void
00418 discover_xml_merge_device_url(discover_device_t **dlist, char *url,
00419 discover_xml_busclass_t *busclasses,
00420 discover_xml_vendor_t *vendors,
00421 discover_error_t *status)
00422 {
00423 XML_Parser parser;
00424 struct context context;
00425
00426 assert(url != NULL);
00427 assert(busclasses != NULL);
00428 assert(vendors != NULL);
00429 assert(status != NULL);
00430
00431 context.state = START;
00432 context.dhead = dlist;
00433 if (*(context.dhead)) {
00434 discover_device_t *next = *(context.dhead);
00435 while(next->next != NULL) {
00436 next = next->next;
00437 }
00438 context.dtail = next;
00439 } else {
00440 context.dtail = NULL;
00441 }
00442
00443 context.busclasses = busclasses;
00444 context.vendors = vendors;
00445 context.unknown_level = 0;
00446
00447 parser = XML_ParserCreate(NULL);
00448 XML_SetElementHandler(parser, start_element, end_element);
00449 XML_SetCharacterDataHandler(parser, cdata);
00450 XML_SetUserData(parser, &context);
00451
00452 if (!_discover_load_url(url, parser)) {
00453 XML_ParserFree(parser);
00454 status->code = DISCOVER_EIO;
00455 return;
00456 }
00457
00458 if (!XML_Parse(parser, "", 0, 1)) {
00459 XML_ParserFree(parser);
00460 status->code = DISCOVER_EXML;
00461 return;
00462 }
00463
00464 XML_ParserFree(parser);
00465
00466 return;
00467 }
00468
00475 discover_device_t *
00476 discover_xml_get_devices(discover_bus_t bus, discover_error_t *status)
00477 {
00478 discover_xml_url_t *urls, *i;
00479 char *url;
00480 discover_xml_busclass_t *busclasses;
00481 discover_xml_vendor_t *vendors;
00482
00483 assert(status != NULL);
00484
00485 status->code = 0;
00486
00487 if (!devices_xml[bus]) {
00488 urls = discover_xml_get_data_urls(bus, DEVICE, status);
00489 if (status->code != 0) {
00490 return NULL;
00491 }
00492
00493 busclasses = discover_xml_get_busclasses(bus, status);
00494 if (status->code != 0) {
00495 return NULL;
00496 }
00497
00498 vendors = discover_xml_get_vendors(bus, status);
00499 if (status->code != 0) {
00500 return NULL;
00501 }
00502
00503 for (i = urls;
00504 i;
00505 i = discover_xml_url_get_next(i)) {
00506 url = discover_xml_url_get_url(i);
00507 discover_xml_merge_device_url(&(devices_xml[bus]), url,
00508 busclasses, vendors, status);
00509 if (status->code != 0) {
00510 get_data_failure_handler(&status, url);
00511 }
00512 }
00513 }
00514
00515
00516 return devices_xml[bus];
00517 }
00518
00522 void
00523 discover_xml_free_devices(void)
00524 {
00525 int i;
00526 for (i = 0; i < BUS_COUNT; i++) {
00527 discover_device_free(devices_xml[i], 1);
00528 devices_xml[i] = NULL;
00529 }
00530 }
00531
00541 discover_device_t *
00542 discover_xml_find_device(discover_device_t *xml_devices,
00543 char *target_vendor, char *target_model,
00544 discover_error_t *status)
00545 {
00546 discover_device_t *device;
00547
00548 assert(target_vendor || target_model);
00549
00550 for (device = xml_devices;
00551 device;
00552 device = device->next) {
00553 if (target_vendor && target_model) {
00554 if (strcmp(device->model_id, target_model) == 0
00555 && strcmp(device->vendor_id, target_vendor) == 0) {
00556 break;
00557 }
00558 } else if (target_vendor) {
00559 if (strcmp(device->vendor_id, target_vendor) == 0) {
00560 break;
00561 }
00562 } else {
00563
00564 if (strcmp(device->model_id, target_model) == 0) {
00565 break;
00566 }
00567 }
00568 }
00569
00570 return device;
00571 }
00572
00585 discover_device_t *
00586 discover_xml_find_next_device(discover_device_t *xml_devices,
00587 char *target_vendor, char *target_model,
00588 discover_error_t *status)
00589 {
00590 return discover_xml_find_device(xml_devices->next,
00591 target_vendor, target_model,
00592 status);
00593 }
00594
00595
00605 discover_device_t *
00606 discover_xml_get_matching_devices(discover_device_t *xml_devices,
00607 char *target_vendor, char *target_model,
00608 discover_error_t *status)
00609 {
00610 discover_device_t *device, *last, *copy;
00611 discover_device_t *head_device = NULL;
00612
00613 device = discover_xml_find_device(xml_devices, target_vendor,
00614 target_model, status);
00615 last = NULL;
00616
00617 while(device) {
00618 copy = discover_device_new();
00619 discover_device_copy(device, copy);
00620 copy->next = NULL;
00621
00622 if (last) {
00623 last->extra = copy;
00624 } else {
00625 head_device = copy;
00626 }
00627
00628 last = copy;
00629
00630 device = discover_xml_find_next_device(device, target_vendor,
00631 target_model, status);
00632 }
00633
00634 return head_device;
00635 }
00636
00639
00640
00641
00642
00643
00644
00645