Example #1
0
/**
 * 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;
}
Example #2
0
/**
 * 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;
}