/** * Adds an imagemap entry to the list * * \param n The xmlNode representing the entry to add * \param base_url Base URL for resolving relative URLs * \param entry Pointer to list of entries * \return false on memory exhaustion, true otherwise */ bool imagemap_addtolist(xmlNode *n, nsurl *base_url, struct mapentry **entry) { char *shape, *coords = NULL, *href, *target = NULL; struct mapentry *new_map, *temp; assert(n != NULL); assert(base_url != NULL); assert(entry != NULL); if (strcmp((const char *) n->name, "area") == 0) { xmlChar *nohref = xmlGetProp(n, (const xmlChar *) "nohref"); if (nohref != NULL) { /* nohref attribute present - ignore this entry */ xmlFree(nohref); return true; } } /* no href -> ignore */ if ((href = (char *) xmlGetProp(n, (const xmlChar *) "href")) == NULL) { return true; } target = (char *) xmlGetProp(n, (const xmlChar *) "target"); /* no shape -> shape is a rectangle */ if ((shape = (char *) xmlGetProp(n, (const xmlChar *) "shape")) == NULL) { shape = (char *) xmlMemStrdup("rect"); } if (strcasecmp(shape, "default") != 0) { /* no coords -> ignore */ if ((coords = (char *) xmlGetProp(n, (const xmlChar *) "coords")) == NULL) { if (target) xmlFree(target); xmlFree(href); xmlFree(shape); return true; } } new_map = calloc(1, sizeof(*new_map)); if (new_map == NULL) { if (target) xmlFree(target); xmlFree(href); xmlFree(shape); if (coords) xmlFree(coords); return false; } /* extract area shape */ if (strcasecmp(shape, "rect") == 0 || strcasecmp(shape, "rectangle") == 0) { new_map->type = IMAGEMAP_RECT; } else if (strcasecmp(shape, "circle") == 0) { new_map->type = IMAGEMAP_CIRCLE; } else if (strcasecmp(shape, "poly") == 0 || strcasecmp(shape, "polygon") == 0) { /* polygon shape name is not valid but sites use it */ new_map->type = IMAGEMAP_POLY; } else if (strcasecmp(shape, "default") == 0) { new_map->type = IMAGEMAP_DEFAULT; } else { /* unknown shape -> bail */ free(new_map); if (target) xmlFree(target); xmlFree(href); xmlFree(shape); if (coords) xmlFree(coords); return true; } if (box_extract_link(href, base_url, &new_map->url) == false) { free(new_map); if (target) xmlFree(target); xmlFree(href); xmlFree(shape); if (coords) xmlFree(coords); return false; } if (new_map->url == NULL) { /* non-fatal error -> ignore this entry */ free(new_map); if (target) xmlFree(target); xmlFree(href); xmlFree(shape); if (coords) xmlFree(coords); return true; } if (target) { new_map->target = strdup(target); if (new_map->target == NULL) { nsurl_unref(new_map->url); free(new_map); xmlFree(target); xmlFree(href); xmlFree(shape); if (coords) xmlFree(coords); return false; } /* no longer needed */ xmlFree(target); } if (new_map->type != IMAGEMAP_DEFAULT) { int x, y; float *xcoords, *ycoords; /* coordinates are a comma-separated list of values */ char *val = strtok(coords, ","); int num = 1; switch (new_map->type) { case IMAGEMAP_RECT: /* (left, top, right, bottom) */ while (val != NULL && num <= 4) { switch (num) { case 1: new_map->bounds.rect.x0 = atoi(val); break; case 2: new_map->bounds.rect.y0 = atoi(val); break; case 3: new_map->bounds.rect.x1 = atoi(val); break; case 4: new_map->bounds.rect.y1 = atoi(val); break; } num++; val = strtok('\0', ","); } break; case IMAGEMAP_CIRCLE: /* (x, y, radius ) */ while (val != NULL && num <= 3) { switch (num) { case 1: new_map->bounds.circle.x = atoi(val); break; case 2: new_map->bounds.circle.y = atoi(val); break; case 3: new_map->bounds.circle.r = atoi(val); break; } num++; val = strtok('\0', ","); } break; case IMAGEMAP_POLY: new_map->bounds.poly.xcoords = NULL; new_map->bounds.poly.ycoords = NULL; while (val != NULL) { x = atoi(val); val = strtok('\0', ","); if (val == NULL) break; y = atoi(val); xcoords = realloc(new_map->bounds.poly.xcoords, num * sizeof(float)); if (xcoords == NULL) { free(new_map->bounds.poly.ycoords); free(new_map->bounds.poly.xcoords); free(new_map->target); nsurl_unref(new_map->url); free(new_map); xmlFree(href); xmlFree(shape); xmlFree(coords); return false; } ycoords = realloc(new_map->bounds.poly.ycoords, num * sizeof(float)); if (ycoords == NULL) { free(xcoords); free(new_map->bounds.poly.ycoords); free(new_map->bounds.poly.xcoords); free(new_map->target); nsurl_unref(new_map->url); free(new_map); xmlFree(href); xmlFree(shape); xmlFree(coords); return false; } new_map->bounds.poly.xcoords = xcoords; new_map->bounds.poly.ycoords = ycoords; new_map->bounds.poly.xcoords[num - 1] = x; new_map->bounds.poly.ycoords[num - 1] = y; num++; val = strtok('\0', ","); } new_map->bounds.poly.num = num - 1; break; default: break; } } new_map->next = NULL; if (entry && *entry) { /* add to END of list */ for (temp = (*entry); temp->next != NULL; temp = temp->next) ; temp->next = new_map; } else { (*entry) = new_map; } xmlFree(href); xmlFree(shape); if (coords) xmlFree(coords); return true; }
/** * Adds an imagemap entry to the list * * \param c The html content that the imagemap belongs to * \param n The xmlNode representing the entry to add * \param base_url Base URL for resolving relative URLs * \param entry Pointer to list of entries * \param tagtype The type of tag * \return false on memory exhaustion, true otherwise */ static bool imagemap_addtolist(const struct html_content *c, dom_node *n, nsurl *base_url, struct mapentry **entry, dom_string *tagtype) { dom_exception exc; dom_string *href = NULL, *target = NULL, *shape = NULL; dom_string *coords = NULL; struct mapentry *new_map, *temp; bool ret = true; if (dom_string_caseless_isequal(tagtype, corestring_dom_area)) { bool nohref = false; exc = dom_element_has_attribute(n, corestring_dom_nohref, &nohref); if ((exc != DOM_NO_ERR) || nohref) /* Skip <area nohref="anything" /> */ goto ok_out; } exc = dom_element_get_attribute(n, corestring_dom_href, &href); if (exc != DOM_NO_ERR || href == NULL) { /* No href="" attribute, skip this element */ goto ok_out; } exc = dom_element_get_attribute(n, corestring_dom_target, &target); if (exc != DOM_NO_ERR) { goto ok_out; } exc = dom_element_get_attribute(n, corestring_dom_shape, &shape); if (exc != DOM_NO_ERR) { goto ok_out; } /* If there's no shape, we default to rectangles */ if (shape == NULL) shape = dom_string_ref(corestring_dom_rect); if (!dom_string_caseless_lwc_isequal(shape, corestring_lwc_default)) { /* If not 'default' and there's no 'coords' give up */ exc = dom_element_get_attribute(n, corestring_dom_coords, &coords); if (exc != DOM_NO_ERR || coords == NULL) { goto ok_out; } } new_map = calloc(1, sizeof(*new_map)); if (new_map == NULL) { goto bad_out; } if (dom_string_caseless_lwc_isequal(shape, corestring_lwc_rect) || dom_string_caseless_lwc_isequal(shape, corestring_lwc_rectangle)) new_map->type = IMAGEMAP_RECT; else if (dom_string_caseless_lwc_isequal(shape, corestring_lwc_circle)) new_map->type = IMAGEMAP_CIRCLE; else if (dom_string_caseless_lwc_isequal(shape, corestring_lwc_poly) || dom_string_caseless_lwc_isequal(shape, corestring_lwc_polygon)) new_map->type = IMAGEMAP_POLY; else if (dom_string_caseless_lwc_isequal(shape, corestring_lwc_default)) new_map->type = IMAGEMAP_DEFAULT; else goto bad_out; if (box_extract_link(c, href, base_url, &new_map->url) == false) goto bad_out; if (new_map->url == NULL) { /* non-fatal error -> ignore this */ goto ok_free_map_out; } if (target != NULL) { /* Copy target into the map */ new_map->target = malloc(dom_string_byte_length(target) + 1); if (new_map->target == NULL) goto bad_out; /* Safe, but relies on dom_strings being NULL terminated */ /* \todo Do this better */ strcpy(new_map->target, dom_string_data(target)); } if (new_map->type != IMAGEMAP_DEFAULT) { int x, y; float *xcoords, *ycoords; /* coordinates are a comma-separated list of values */ char *val = strtok((char *)dom_string_data(coords), ","); int num = 1; switch (new_map->type) { case IMAGEMAP_RECT: /* (left, top, right, bottom) */ while (val != NULL && num <= 4) { switch (num) { case 1: new_map->bounds.rect.x0 = atoi(val); break; case 2: new_map->bounds.rect.y0 = atoi(val); break; case 3: new_map->bounds.rect.x1 = atoi(val); break; case 4: new_map->bounds.rect.y1 = atoi(val); break; } num++; val = strtok(NULL, ","); } break; case IMAGEMAP_CIRCLE: /* (x, y, radius ) */ while (val != NULL && num <= 3) { switch (num) { case 1: new_map->bounds.circle.x = atoi(val); break; case 2: new_map->bounds.circle.y = atoi(val); break; case 3: new_map->bounds.circle.r = atoi(val); break; } num++; val = strtok(NULL, ","); } break; case IMAGEMAP_POLY: new_map->bounds.poly.xcoords = NULL; new_map->bounds.poly.ycoords = NULL; while (val != NULL) { x = atoi(val); val = strtok(NULL, ","); if (val == NULL) break; y = atoi(val); xcoords = realloc(new_map->bounds.poly.xcoords, num * sizeof(float)); if (xcoords == NULL) { goto bad_out; } new_map->bounds.poly.xcoords = xcoords; ycoords = realloc(new_map->bounds.poly.ycoords, num * sizeof(float)); if (ycoords == NULL) { goto bad_out; } new_map->bounds.poly.ycoords = ycoords; new_map->bounds.poly.xcoords[num - 1] = x; new_map->bounds.poly.ycoords[num - 1] = y; num++; val = strtok(NULL, ","); } new_map->bounds.poly.num = num - 1; break; default: break; } } new_map->next = NULL; if (*entry) { /* add to END of list */ for (temp = (*entry); temp->next != NULL; temp = temp->next) ; temp->next = new_map; } else { (*entry) = new_map; } /* All good, linked in, let's clean up */ goto ok_out; bad_out: ret = false; ok_free_map_out: if (new_map != NULL) { if (new_map->url != NULL) nsurl_unref(new_map->url); if (new_map->type == IMAGEMAP_POLY && new_map->bounds.poly.ycoords != NULL) free(new_map->bounds.poly.ycoords); if (new_map->type == IMAGEMAP_POLY && new_map->bounds.poly.xcoords != NULL) free(new_map->bounds.poly.xcoords); if (new_map->target != NULL) free(new_map->target); free(new_map); } ok_out: if (href != NULL) dom_string_unref(href); if (target != NULL) dom_string_unref(target); if (shape != NULL) dom_string_unref(shape); if (coords != NULL) dom_string_unref(coords); return ret; }