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 context->stack = discover_xml_stack_new();
00296 }
00297 break;
00298
00299 case DEVICE:
00300 if (strcmp(name, "data") == 0) {
00301 context->nesting = context->last_nesting = 0;
00302 context->state = DATA;
00303 }
00304
00305
00306 case DATA:
00307 if (strcmp(name, "data") == 0) {
00308 create_data(context, attrs);
00309 context->last_nesting = context->nesting;
00310 context->nesting++;
00311 }
00312 break;
00313 }
00314 }
00315
00316 static void
00317 end_element(void *ctx, const XML_Char *name)
00318 {
00319 struct context *context = ctx;
00320 discover_device_t *device;
00321 discover_data_t *current_data;
00322 discover_xml_stack *stack;
00323
00324
00325 assert(context != NULL);
00326 assert(name != NULL);
00327
00328
00329 if (unknown_device_element(name)) {
00330 context->unknown_level--;
00331 return;
00332 }
00333
00334 if (context->unknown_level > 0) {
00335 return;
00336 }
00337
00338 switch (context->state) {
00339 case FINISH:
00340 case START:
00341 break;
00342
00343 case DEVICE:
00344 context->state = START;
00345 device = context->dtail;
00346 stack = context->stack;
00347 current_data = discover_xml_stack_get(stack);
00348 device->data = discover_data_get_first(current_data);
00349 break;
00350
00351 case DATA:
00352 context->nesting--;
00353 stack = context->stack;
00354 if((context->nesting + 2) <= stack->depth) {
00355 while((context->nesting + 1 < stack->depth) &&
00356 stack->depth > 1) {
00357 discover_xml_stack_pop(&stack);
00358 }
00359 context->stack = stack;
00360 }
00361
00362 if (context->nesting == 0) {
00363 context->state = DEVICE;
00364 }
00365 }
00366 }
00367
00368 static void
00369 cdata(void *ctx, const XML_Char *data, int len)
00370 {
00371 struct context *context = ctx;
00372 size_t old_len;
00373 discover_data_t *current_data;
00374
00375 assert(context != NULL);
00376 assert(data != NULL);
00377
00378 if (context->state == DATA
00379 && context->nesting > context->last_nesting) {
00380 assert(context->stack != NULL);
00381 current_data = context->stack->data;
00382 assert(current_data != NULL);
00383
00384 if (!current_data->text) {
00385 old_len = 0;
00386 current_data->text = _discover_xmalloc(1);
00387 current_data->text[0] = '\0';
00388 } else {
00389 old_len = strlen(current_data->text);
00390 }
00391 current_data->text
00392 = _discover_xrealloc(current_data->text,
00393 old_len + len + 1);
00394 strncat(current_data->text,
00395 (const char *)data,
00396 (unsigned int)len);
00397 }
00398 }
00399
00414
00415
00416
00417
00418
00419
00420 void
00421 discover_xml_merge_device_url(discover_device_t **dlist, char *url,
00422 discover_xml_busclass_t *busclasses,
00423 discover_xml_vendor_t *vendors,
00424 discover_error_t *status)
00425 {
00426 XML_Parser parser;
00427 struct context context;
00428
00429 assert(url != NULL);
00430 assert(busclasses != NULL);
00431 assert(vendors != NULL);
00432 assert(status != NULL);
00433
00434 context.state = START;
00435 context.dhead = dlist;
00436 if (*(context.dhead)) {
00437 discover_device_t *next = *(context.dhead);
00438 while(next->next != NULL) {
00439 next = next->next;
00440 }
00441 context.dtail = next;
00442 } else {
00443 context.dtail = NULL;
00444 }
00445
00446 context.busclasses = busclasses;
00447 context.vendors = vendors;
00448 context.unknown_level = 0;
00449
00450 parser = XML_ParserCreate(NULL);
00451 XML_SetElementHandler(parser, start_element, end_element);
00452 XML_SetCharacterDataHandler(parser, cdata);
00453 XML_SetUserData(parser, &context);
00454
00455 if (!_discover_load_url(url, parser)) {
00456 XML_ParserFree(parser);
00457 status->code = DISCOVER_EIO;
00458 return;
00459 }
00460
00461 if (!XML_Parse(parser, "", 0, 1)) {
00462 XML_ParserFree(parser);
00463 status->code = DISCOVER_EXML;
00464 return;
00465 }
00466
00467 XML_ParserFree(parser);
00468
00469 return;
00470 }
00471
00478 discover_device_t *
00479 discover_xml_get_devices(discover_bus_t bus, discover_error_t *status)
00480 {
00481 discover_xml_url_t *urls, *i;
00482 char *url;
00483 discover_xml_busclass_t *busclasses;
00484 discover_xml_vendor_t *vendors;
00485
00486 assert(status != NULL);
00487
00488 status->code = 0;
00489
00490 if (!devices_xml[bus]) {
00491 urls = discover_xml_get_data_urls(bus, DEVICE, status);
00492 if (status->code != 0) {
00493 return NULL;
00494 }
00495
00496 busclasses = discover_xml_get_busclasses(bus, status);
00497 if (status->code != 0) {
00498 return NULL;
00499 }
00500
00501 vendors = discover_xml_get_vendors(bus, status);
00502 if (status->code != 0) {
00503 return NULL;
00504 }
00505
00506 for (i = urls;
00507 i;
00508 i = discover_xml_url_get_next(i)) {
00509 url = discover_xml_url_get_url(i);
00510 discover_xml_merge_device_url(&(devices_xml[bus]), url,
00511 busclasses, vendors, status);
00512 if (status->code != 0) {
00513 get_data_failure_handler(&status, url);
00514 }
00515 }
00516 }
00517
00518
00519 return devices_xml[bus];
00520 }
00521
00525 void
00526 discover_xml_free_devices(void)
00527 {
00528 int i;
00529 for (i = 0; i < BUS_COUNT; i++) {
00530 discover_device_free(devices_xml[i], 1);
00531 devices_xml[i] = NULL;
00532 }
00533 }
00534
00544 discover_device_t *
00545 discover_xml_find_device(discover_device_t *xml_devices,
00546 char *target_vendor, char *target_model,
00547 discover_error_t *status)
00548 {
00549 discover_device_t *device;
00550
00551 assert(target_vendor || target_model);
00552
00553 for (device = xml_devices;
00554 device;
00555 device = device->next) {
00556 if (target_vendor && target_model) {
00557 if (strcmp(device->model_id, target_model) == 0
00558 && strcmp(device->vendor_id, target_vendor) == 0) {
00559 break;
00560 }
00561 } else if (target_vendor) {
00562 if (strcmp(device->vendor_id, target_vendor) == 0) {
00563 break;
00564 }
00565 } else {
00566
00567 if (strcmp(device->model_id, target_model) == 0) {
00568 break;
00569 }
00570 }
00571 }
00572
00573 return device;
00574 }
00575
00588 discover_device_t *
00589 discover_xml_find_next_device(discover_device_t *xml_devices,
00590 char *target_vendor, char *target_model,
00591 discover_error_t *status)
00592 {
00593 return discover_xml_find_device(xml_devices->next,
00594 target_vendor, target_model,
00595 status);
00596 }
00597
00598
00608 discover_device_t *
00609 discover_xml_get_matching_devices(discover_device_t *xml_devices,
00610 char *target_vendor, char *target_model,
00611 discover_error_t *status)
00612 {
00613 discover_device_t *device, *last, *copy;
00614 discover_device_t *head_device = NULL;
00615
00616 device = discover_xml_find_device(xml_devices, target_vendor,
00617 target_model, status);
00618 last = NULL;
00619
00620 while(device) {
00621 copy = discover_device_new();
00622 discover_device_copy(device, copy);
00623 copy->next = NULL;
00624
00625 if (last) {
00626 last->extra = copy;
00627 } else {
00628 head_device = copy;
00629 }
00630
00631 last = copy;
00632
00633 device = discover_xml_find_next_device(device, target_vendor,
00634 target_model, status);
00635 }
00636
00637 return head_device;
00638 }
00639
00642
00643
00644
00645
00646
00647
00648