float svgtiny_parse_length(dom_string *s, int viewport_size, const struct svgtiny_parse_state state) { char *ss = strndup(dom_string_data(s), dom_string_byte_length(s)); float ret = _svgtiny_parse_length(ss, viewport_size, state); free(ss); return ret; }
/** * Callback to determine if a node has an attribute with the given name whose * value contains the substring given. * * \param pw HTML document * \param node DOM node * \param qname Name to match * \param value Value to match * \param match Pointer to location to receive result * \return CSS_OK on success, * CSS_NOMEM on memory exhaustion. * * \post \a match will contain true if the node matches and false otherwise. */ css_error node_has_attribute_substring(void *pw, void *node, const css_qname *qname, lwc_string *value, bool *match) { dom_node *n = node; dom_string *name; dom_string *atr_val; dom_exception err; size_t vlen = lwc_string_length(value); if (vlen == 0) { *match = false; return CSS_OK; } err = dom_string_create_interned( (const uint8_t *) lwc_string_data(qname->name), lwc_string_length(qname->name), &name); if (err != DOM_NO_ERR) return CSS_NOMEM; err = dom_element_get_attribute(n, name, &atr_val); if ((err != DOM_NO_ERR) || (atr_val == NULL)) { dom_string_unref(name); *match = false; return CSS_OK; } dom_string_unref(name); /* check for exact match */ *match = dom_string_caseless_lwc_isequal(atr_val, value); /* check for prefix match */ if (*match == false) { const char *vdata = lwc_string_data(value); const char *start = (const char *) dom_string_data(atr_val); size_t len = dom_string_byte_length(atr_val); const char *last_start = start + len - vlen; if (len >= vlen) { while (start <= last_start) { if (strncasecmp(start, vdata, vlen) == 0) { *match = true; break; } start++; } } } dom_string_unref(atr_val); return CSS_OK; }
/** * Case insensitively compare two DOM strings * * \param s1 The first string to compare * \param s2 The second string to compare * \return true if strings match, false otherwise */ bool dom_string_caseless_isequal(const dom_string *s1, const dom_string *s2) { const uint8_t *d1 = NULL; const uint8_t *d2 = NULL; size_t len; const dom_string_internal *is1 = (dom_string_internal *) s1; const dom_string_internal *is2 = (dom_string_internal *) s2; if (s1 == NULL) is1 = &empty_string; if (s2 == NULL) is2 = &empty_string; if (is1->type == DOM_STRING_INTERNED && is2->type == DOM_STRING_INTERNED) { bool match; if (lwc_string_caseless_isequal(is1->data.intern, is2->data.intern, &match) != lwc_error_ok) return false; return match; } len = dom_string_byte_length((dom_string *) is1); if (len != dom_string_byte_length((dom_string *)is2)) return false; d1 = (const uint8_t *) dom_string_data((dom_string *) is1); d2 = (const uint8_t *) dom_string_data((dom_string *)is2); while (len > 0) { if (dolower(*d1) != dolower(*d2)) return false; d1++; d2++; len--; } return true; }
/** * Callback to determine if a node has an attribute with the given name whose * value includes that given. * * \param pw HTML document * \param node DOM node * \param qname Name to match * \param value Value to match * \param match Pointer to location to receive result * \return CSS_OK on success, * CSS_NOMEM on memory exhaustion. * * \post \a match will contain true if the node matches and false otherwise. */ css_error node_has_attribute_includes(void *pw, void *node, const css_qname *qname, lwc_string *value, bool *match) { dom_node *n = node; dom_string *name; dom_string *atr_val; dom_exception err; size_t vlen = lwc_string_length(value); const char *p; const char *start; const char *end; *match = false; if (vlen == 0) { return CSS_OK; } err = dom_string_create_interned( (const uint8_t *) lwc_string_data(qname->name), lwc_string_length(qname->name), &name); if (err != DOM_NO_ERR) return CSS_NOMEM; err = dom_element_get_attribute(n, name, &atr_val); if ((err != DOM_NO_ERR) || (atr_val == NULL)) { dom_string_unref(name); *match = false; return CSS_OK; } dom_string_unref(name); /* check for match */ start = (const char *) dom_string_data(atr_val); end = start + dom_string_byte_length(atr_val); for (p = start; p <= end; p++) { if (*p == ' ' || *p == '\0') { if ((size_t) (p - start) == vlen && strncasecmp(start, lwc_string_data(value), vlen) == 0) { *match = true; break; } start = p + 1; } } dom_string_unref(atr_val); return CSS_OK; }
/** * Concatenate two dom strings * * \param s1 The first string * \param s2 The second string * \param result Pointer to location to receive result * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion * * The returned string will be referenced. The client * should dereference it once it has finished with it. */ dom_exception dom_string_concat(dom_string *s1, dom_string *s2, dom_string **result) { dom_string_internal *concat; const uint8_t *s1ptr, *s2ptr; size_t s1len, s2len; assert(s1 != NULL); assert(s2 != NULL); s1ptr = (const uint8_t *) dom_string_data(s1); s2ptr = (const uint8_t *) dom_string_data(s2); s1len = dom_string_byte_length(s1); s2len = dom_string_byte_length(s2); concat = malloc(sizeof(*concat)); if (concat == NULL) { return DOM_NO_MEM_ERR; } concat->data.cdata.ptr = malloc(s1len + s2len + 1); if (concat->data.cdata.ptr == NULL) { free(concat); return DOM_NO_MEM_ERR; } memcpy(concat->data.cdata.ptr, s1ptr, s1len); memcpy(concat->data.cdata.ptr + s1len, s2ptr, s2len); concat->data.cdata.ptr[s1len + s2len] = '\0'; concat->data.cdata.len = s1len + s2len; concat->base.refcnt = 1; concat->type = DOM_STRING_CDATA; *result = (dom_string *)concat; return DOM_NO_ERR; }
/** * Callback to determine if a node has an attribute with the given name whose * value dashmatches that given. * * \param pw HTML document * \param node DOM node * \param qname Name to match * \param value Value to match * \param match Pointer to location to receive result * \return CSS_OK on success, * CSS_NOMEM on memory exhaustion. * * \post \a match will contain true if the node matches and false otherwise. */ css_error node_has_attribute_dashmatch(void *pw, void *node, const css_qname *qname, lwc_string *value, bool *match) { dom_node *n = node; dom_string *name; dom_string *atr_val; dom_exception err; size_t vlen = lwc_string_length(value); if (vlen == 0) { *match = false; return CSS_OK; } err = dom_string_create_interned( (const uint8_t *) lwc_string_data(qname->name), lwc_string_length(qname->name), &name); if (err != DOM_NO_ERR) return CSS_NOMEM; err = dom_element_get_attribute(n, name, &atr_val); if ((err != DOM_NO_ERR) || (atr_val == NULL)) { dom_string_unref(name); *match = false; return CSS_OK; } dom_string_unref(name); /* check for exact match */ *match = dom_string_caseless_lwc_isequal(atr_val, value); /* check for dashmatch */ if (*match == false) { const char *vdata = lwc_string_data(value); const char *data = (const char *) dom_string_data(atr_val); size_t len = dom_string_byte_length(atr_val); if (len > vlen && data[vlen] == '-' && strncasecmp(data, vdata, vlen) == 0) { *match = true; } } dom_string_unref(atr_val); return CSS_OK; }
static struct form_control * parse_select_element(struct form *forms, dom_html_select_element *select) { struct form_control *control = NULL; dom_html_form_element *form = NULL; dom_string *ds_name = NULL; char *name = NULL; if (dom_html_select_element_get_form(select, &form) != DOM_NO_ERR) goto out; if (dom_html_select_element_get_name(select, &ds_name) != DOM_NO_ERR) goto out; if (ds_name != NULL) name = strndup(dom_string_data(ds_name), dom_string_byte_length(ds_name)); control = form_new_control(select, GADGET_SELECT); if (control == NULL) goto out; if (name != NULL) { /* Hand the name string over */ control->name = name; name = NULL; } dom_html_select_element_get_multiple(select, &(control->data.select.multiple)); if (form != NULL && control != NULL) form_add_control(find_form(forms, form), control); out: if (form != NULL) dom_node_unref(form); if (ds_name != NULL) dom_string_unref(ds_name); if (name != NULL) free(name); return control; }
/** * Calculate a hash value from a dom string * * \param str The string to calculate a hash of * \return The hash value associated with the string */ uint32_t dom_string_hash(dom_string *str) { const uint8_t *s = (const uint8_t *) dom_string_data(str); size_t slen = dom_string_byte_length(str); uint32_t hash = 0x811c9dc5; while (slen > 0) { hash *= 0x01000193; hash ^= *s; s++; slen--; } return hash; }
/** * Get the length, in characters, of a dom string * * \param str The string to measure the length of * \return The length of the string, in characters */ size_t dom_string_length(dom_string *str) { const uint8_t *s; size_t slen, clen; parserutils_error err; s = (const uint8_t *) dom_string_data(str); slen = dom_string_byte_length(str); err = parserutils_charset_utf8_length(s, slen, &clen); if (err != PARSERUTILS_OK) { return 0; } return clen; }
/** * Validate whether the string is a legal NCName. * Refer http://www.w3.org/TR/REC-xml-names/ for detail. * * \param str The name to validate * \return true if ::name is valid, false otherwise. */ bool _dom_validate_ncname(dom_string *name) { uint32_t ch; size_t clen, slen; parserutils_error err; const uint8_t *s; if (name == NULL) return false; slen = dom_string_length(name); if (slen == 0) return false; s = (const uint8_t *) dom_string_data(name); slen = dom_string_byte_length(name); err = parserutils_charset_utf8_to_ucs4(s, slen, &ch, &clen); if (err != PARSERUTILS_OK) { return false; } if (is_letter(ch) == false && ch != (uint32_t) '_') return false; s += clen; slen -= clen; while (slen > 0) { err = parserutils_charset_utf8_to_ucs4(s, slen, &ch, &clen); if (err != PARSERUTILS_OK) { return false; } if (is_name_char(ch) == false) return false; if (ch == (uint32_t) ':') return false; s += clen; slen -= clen; } return true; }
/** * Extract a substring from a dom string * * \param str The string to extract from * \param i1 The character index of the start of the substring * \param i2 The character index of the end of the substring * \param result Pointer to location to receive result * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion * * The returned string will have its reference count increased. The client * should dereference it once it has finished with it. */ dom_exception dom_string_substr(dom_string *str, off_t i1, off_t i2, dom_string **result) { const uint8_t *s; size_t slen; off_t b1, b2; parserutils_error err; /* target string is NULL equivalent to empty. */ if (str == NULL) str = (dom_string *)&empty_string; s = (const uint8_t *) dom_string_data(str); slen = dom_string_byte_length(str); /* Initialise the byte index of the start to 0 */ b1 = 0; /* Make the end a character offset from the start */ i2 -= i1; /* Calculate the byte index of the start */ while (i1 > 0) { err = parserutils_charset_utf8_next(s, slen, b1, &b1); if (err != PARSERUTILS_OK) { return DOM_NO_MEM_ERR; } i1--; } /* Initialise the byte index of the end to that of the start */ b2 = b1; /* Calculate the byte index of the end */ while (i2 > 0) { err = parserutils_charset_utf8_next(s, slen, b2, &b2); if (err != PARSERUTILS_OK) { return DOM_NO_MEM_ERR; } i2--; } /* Create a string from the specified byte range */ return dom_string_create(s + b1, (size_t)(b2 - b1), result); }
/** Convert the given string to lowercase * * \param source * \param ascii_only Whether to only convert [a-z] to [A-Z] * \param lower Result pointer for lowercase string. Caller owns ref * * \return DOM_NO_ERR on success. * * \note Right now, will return DOM_NOT_SUPPORTED_ERR if ascii_only is false. */ dom_exception dom_string_tolower(dom_string *source, bool ascii_only, dom_string **lower) { const uint8_t *orig_s = (const uint8_t *) dom_string_data(source); const size_t nbytes = dom_string_byte_length(source); uint8_t *copy_s; size_t index = 0, clen; parserutils_error err; dom_exception exc; if (ascii_only == false) return DOM_NOT_SUPPORTED_ERR; copy_s = malloc(nbytes); if (copy_s == NULL) return DOM_NO_MEM_ERR; memcpy(copy_s, orig_s, nbytes); while (index < nbytes) { err = parserutils_charset_utf8_char_byte_length(orig_s + index, &clen); if (err != PARSERUTILS_OK) { free(copy_s); /** \todo Find a better exception */ return DOM_NO_MEM_ERR; } if (clen == 1) { if (orig_s[index] >= 'A' && orig_s[index] <= 'Z') copy_s[index] += 'a' - 'A'; } index += clen; } if (((dom_string_internal*)source)->type == DOM_STRING_CDATA) { exc = dom_string_create(copy_s, nbytes, lower); } else { exc = dom_string_create_interned(copy_s, nbytes, lower); } free(copy_s); return exc; }
static struct form_control * parse_textarea_element(struct form *forms, dom_html_text_area_element *ta) { struct form_control *control = NULL; dom_html_form_element *form = NULL; dom_string *ds_name = NULL; char *name = NULL; if (dom_html_text_area_element_get_form(ta, &form) != DOM_NO_ERR) goto out; if (dom_html_text_area_element_get_name(ta, &ds_name) != DOM_NO_ERR) goto out; if (ds_name != NULL) name = strndup(dom_string_data(ds_name), dom_string_byte_length(ds_name)); control = form_new_control(ta, GADGET_TEXTAREA); if (control == NULL) goto out; if (name != NULL) { /* Hand the name string over */ control->name = name; name = NULL; } if (form != NULL && control != NULL) form_add_control(find_form(forms, form), control); out: if (form != NULL) dom_node_unref(form); if (ds_name != NULL) dom_string_unref(ds_name); if (name != NULL) free(name); return control; }
void svgtiny_parse_transform_attributes(dom_element *node, struct svgtiny_parse_state *state) { char *transform; dom_string *attr; dom_exception exc; exc = dom_element_get_attribute(node, state->interned_transform, &attr); if (exc == DOM_NO_ERR && attr != NULL) { transform = strndup(dom_string_data(attr), dom_string_byte_length(attr)); svgtiny_parse_transform(transform, &state->ctm.a, &state->ctm.b, &state->ctm.c, &state->ctm.d, &state->ctm.e, &state->ctm.f); free(transform); dom_string_unref(attr); } }
static bool save_complete_handle_attr(save_complete_ctx *ctx, dom_string *node_name, dom_attr *attr) { dom_string *name; const char *name_data; size_t name_len; dom_string *value; dom_exception error; error = dom_attr_get_name(attr, &name); if (error != DOM_NO_ERR) return false; if (name == NULL) return true; error = dom_attr_get_value(attr, &value); if (error != DOM_NO_ERR) { dom_string_unref(name); return false; } name_data = dom_string_data(name); name_len = dom_string_byte_length(name); fputc(' ', ctx->fp); fwrite(name_data, sizeof(*name_data), name_len, ctx->fp); if (value != NULL) { fputc('=', ctx->fp); if (save_complete_handle_attr_value(ctx, node_name, name, value) == false) { dom_string_unref(value); dom_string_unref(name); return false; } } dom_string_unref(name); return true; }
static dom_hubbub_error exec_inline_script(html_content *c, dom_node *node, dom_string *mimetype) { union content_msg_data msg_data; dom_string *script; dom_exception exc; /* returned by libdom functions */ struct lwc_string_s *lwcmimetype; script_handler_t *script_handler; struct html_script *nscript; /* does not appear to be a src so script is inline content */ exc = dom_node_get_text_content(node, &script); if ((exc != DOM_NO_ERR) || (script == NULL)) { return DOM_HUBBUB_OK; /* no contents, skip */ } nscript = html_process_new_script(c, mimetype, HTML_SCRIPT_INLINE); if (nscript == NULL) { dom_string_unref(script); msg_data.error = messages_get("NoMemory"); content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); return DOM_HUBBUB_NOMEM; } nscript->data.string = script; nscript->already_started = true; /* ensure script handler for content type */ dom_string_intern(mimetype, &lwcmimetype); script_handler = select_script_handler(content_factory_type_from_mime_type(lwcmimetype)); lwc_string_unref(lwcmimetype); if (script_handler != NULL) { script_handler(c->jscontext, dom_string_data(script), dom_string_byte_length(script)); } return DOM_HUBBUB_OK; }
/** * Get the UCS4 character at position index * * \param index The position of the charater * \param ch The UCS4 character * \return DOM_NO_ERR on success, appropriate dom_exception on failure. */ dom_exception dom_string_at(dom_string *str, uint32_t index, uint32_t *ch) { const uint8_t *s; size_t clen, slen; uint32_t c, i; parserutils_error err; s = (const uint8_t *) dom_string_data(str); slen = dom_string_byte_length(str); i = 0; while (slen > 0) { err = parserutils_charset_utf8_char_byte_length(s, &clen); if (err != PARSERUTILS_OK) { return (uint32_t) -1; } i++; if (i == index + 1) break; s += clen; slen -= clen; } if (i == index + 1) { err = parserutils_charset_utf8_to_ucs4(s, slen, &c, &clen); if (err != PARSERUTILS_OK) { return (uint32_t) -1; } *ch = c; return DOM_NO_ERR; } else { return DOM_DOMSTRING_SIZE_ERR; } }
/** * Case sensitively compare DOM string with lwc_string * * \param s1 The first string to compare * \param s2 The second string to compare * \return true if strings match, false otherwise * * Returns false if either are NULL. */ bool dom_string_lwc_isequal(const dom_string *s1, lwc_string *s2) { size_t len; dom_string_internal *is1 = (dom_string_internal *) s1; if (s1 == NULL || s2 == NULL) return false; if (is1->type == DOM_STRING_INTERNED) { bool match; (void) lwc_string_isequal(is1->data.intern, s2, &match); return match; } /* Handle non-interned case */ len = dom_string_byte_length(s1); if (len != lwc_string_length(s2)) return false; return 0 == memcmp(dom_string_data(s1), lwc_string_data(s2), len); }
static struct form_control * parse_button_element(struct form *forms, dom_html_button_element *button) { struct form_control *control = NULL; dom_exception err; dom_html_form_element *form = NULL; dom_string *ds_type = NULL; dom_string *ds_value = NULL; dom_string *ds_name = NULL; err = dom_html_button_element_get_form(button, &form); if (err != DOM_NO_ERR) goto out; err = dom_html_button_element_get_type(button, &ds_type); if (err != DOM_NO_ERR) goto out; if (ds_type == NULL) { control = form_new_control(button, GADGET_SUBMIT); } else { if (dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_submit)) { control = form_new_control(button, GADGET_SUBMIT); } else if (dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_reset)) { control = form_new_control(button, GADGET_RESET); } else { control = form_new_control(button, GADGET_BUTTON); } } if (control == NULL) goto out; err = dom_html_button_element_get_value(button, &ds_value); if (err != DOM_NO_ERR) goto out; err = dom_html_button_element_get_name(button, &ds_name); if (err != DOM_NO_ERR) goto out; if (ds_value != NULL) { control->value = strndup( dom_string_data(ds_value), dom_string_byte_length(ds_value)); if (control->value == NULL) { form_free_control(control); control = NULL; goto out; } } if (ds_name != NULL) { control->name = strndup( dom_string_data(ds_name), dom_string_byte_length(ds_name)); if (control->name == NULL) { form_free_control(control); control = NULL; goto out; } } if (form != NULL && control != NULL) form_add_control(find_form(forms, form), control); out: if (form != NULL) dom_node_unref(form); if (ds_type != NULL) dom_string_unref(ds_type); if (ds_value != NULL) dom_string_unref(ds_value); if (ds_name != NULL) dom_string_unref(ds_name); return control; }
svgtiny_code svgtiny_parse_text(dom_element *text, struct svgtiny_parse_state state) { float x, y, width, height; float px, py; dom_node *child; dom_exception exc; svgtiny_setup_state_local(&state); svgtiny_parse_position_attributes(text, state, &x, &y, &width, &height); svgtiny_parse_font_attributes(text, &state); svgtiny_parse_transform_attributes(text, &state); px = state.ctm.a * x + state.ctm.c * y + state.ctm.e; py = state.ctm.b * x + state.ctm.d * y + state.ctm.f; /* state.ctm.e = px - state.origin_x; */ /* state.ctm.f = py - state.origin_y; */ /*struct css_style style = state.style; style.font_size.value.length.value *= state.ctm.a;*/ exc = dom_node_get_first_child(text, &child); if (exc != DOM_NO_ERR) { return svgtiny_LIBDOM_ERROR; svgtiny_cleanup_state_local(&state); } while (child != NULL) { dom_node *next; dom_node_type nodetype; svgtiny_code code = svgtiny_OK; exc = dom_node_get_node_type(child, &nodetype); if (exc != DOM_NO_ERR) { dom_node_unref(child); svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } if (nodetype == DOM_ELEMENT_NODE) { dom_string *nodename; exc = dom_node_get_node_name(child, &nodename); if (exc != DOM_NO_ERR) { dom_node_unref(child); svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } if (dom_string_caseless_isequal(nodename, state.interned_tspan)) code = svgtiny_parse_text((dom_element *)child, state); dom_string_unref(nodename); } else if (nodetype == DOM_TEXT_NODE) { struct svgtiny_shape *shape = svgtiny_add_shape(&state); dom_string *content; if (shape == NULL) { dom_node_unref(child); svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; } exc = dom_text_get_whole_text(child, &content); if (exc != DOM_NO_ERR) { dom_node_unref(child); svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } if (content != NULL) { shape->text = strndup(dom_string_data(content), dom_string_byte_length(content)); dom_string_unref(content); } else { shape->text = strdup(""); } shape->text_x = px; shape->text_y = py; state.diagram->shape_count++; } if (code != svgtiny_OK) { dom_node_unref(child); svgtiny_cleanup_state_local(&state); return code; } exc = dom_node_get_next_sibling(child, &next); dom_node_unref(child); if (exc != DOM_NO_ERR) { svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } child = next; } svgtiny_cleanup_state_local(&state); return svgtiny_OK; }
/* exported function documented in string.h */ dom_exception dom_string_whitespace_op(dom_string *s, enum dom_whitespace_op op, dom_string **ret) { const uint8_t *src_text = (const uint8_t *) dom_string_data(s); size_t len = dom_string_byte_length(s); const uint8_t *src_pos; const uint8_t *src_end; dom_exception exc; uint8_t *temp_pos; uint8_t *temp; if (len == 0) { *ret = dom_string_ref(s); } temp = malloc(len); if (temp == NULL) { return DOM_NO_MEM_ERR; } src_pos = src_text; src_end = src_text + len; temp_pos = temp; if (op & DOM_WHITESPACE_STRIP_LEADING) { while (src_pos < src_end) { if (*src_pos == ' ' || *src_pos == '\t' || *src_pos == '\n' || *src_pos == '\r' || *src_pos == '\f') src_pos++; else break; } } while (src_pos < src_end) { if ((op & DOM_WHITESPACE_COLLAPSE) && (*src_pos == ' ' || *src_pos == '\t' || *src_pos == '\n' || *src_pos == '\r' || *src_pos == '\f')) { /* Got a whitespace character */ do { /* Skip all adjacent whitespace */ src_pos++; } while (src_pos < src_end && (*src_pos == ' ' || *src_pos == '\t' || *src_pos == '\n' || *src_pos == '\r' || *src_pos == '\f')); /* Gets replaced with single space in output */ *temp_pos++ = ' '; } else { /* Otherwise, copy to output */ *temp_pos++ = *src_pos++; } } if (op & DOM_WHITESPACE_STRIP_TRAILING) { while (temp_pos > temp) { temp_pos--; if (*temp_pos != ' ' && *temp_pos != '\t' && *temp_pos != '\n' && *temp_pos != '\r' && *temp_pos != '\f') { temp_pos++; break; } } } /* New length */ len = temp_pos - temp; /* Make new string */ if (((dom_string_internal *) s)->type == DOM_STRING_CDATA) { exc = dom_string_create(temp, len, ret); } else { exc = dom_string_create_interned(temp, len, ret); } free(temp); return exc; }
static bool save_complete_handle_element(save_complete_ctx *ctx, dom_node *node, save_complete_event_type event_type) { dom_string *name; dom_namednodemap *attrs; const char *name_data; size_t name_len; bool process = true; dom_exception error; ctx->iter_state = STATE_NORMAL; error = dom_node_get_node_name(node, &name); if (error != DOM_NO_ERR) return false; if (name == NULL) return true; name_data = dom_string_data(name); name_len = dom_string_byte_length(name); if (name_len == SLEN("base") && strncasecmp(name_data, "base", name_len) == 0) { /* Elide BASE elements from the output */ process = false; } else if (name_len == SLEN("meta") && strncasecmp(name_data, "meta", name_len) == 0) { /* Don't emit close tags for META elements */ if (event_type == EVENT_LEAVE) { process = false; } else { /* Elide meta charsets */ dom_string *value; error = dom_element_get_attribute(node, corestring_dom_http_equiv, &value); if (error != DOM_NO_ERR) { dom_string_unref(name); return false; } if (value != NULL) { if (dom_string_length(value) == SLEN("Content-Type") && strncasecmp(dom_string_data(value), "Content-Type", SLEN("Content-Type")) == 0) process = false; dom_string_unref(value); } else { bool yes; error = dom_element_has_attribute(node, corestring_dom_charset, &yes); if (error != DOM_NO_ERR) { dom_string_unref(name); return false; } if (yes) process = false; } } } else if (event_type == EVENT_LEAVE && ((name_len == SLEN("link") && strncasecmp(name_data, "link", name_len) == 0))) { /* Don't emit close tags for void elements */ process = false; } if (process == false) { dom_string_unref(name); return true; } fputc('<', ctx->fp); if (event_type == EVENT_LEAVE) fputc('/', ctx->fp); fwrite(name_data, sizeof(*name_data), name_len, ctx->fp); if (event_type == EVENT_ENTER) { error = dom_node_get_attributes(node, &attrs); if (error != DOM_NO_ERR) { dom_string_unref(name); return false; } if (save_complete_handle_attrs(ctx, name, attrs) == false) { dom_namednodemap_unref(attrs); dom_string_unref(name); return false; } dom_namednodemap_unref(attrs); } fputc('>', ctx->fp); /* Rewrite contents of style elements */ if (event_type == EVENT_ENTER && name_len == SLEN("style") && strncasecmp(name_data, "style", name_len) == 0) { dom_string *content; error = dom_node_get_text_content(node, &content); if (error != DOM_NO_ERR) { dom_string_unref(name); return false; } if (content != NULL) { char *rewritten; unsigned long len; /* Rewrite @import rules */ rewritten = save_complete_rewrite_stylesheet_urls( ctx, dom_string_data(content), dom_string_byte_length(content), ctx->base, &len); if (rewritten == NULL) { dom_string_unref(content); dom_string_unref(name); return false; } dom_string_unref(content); fwrite(rewritten, sizeof(*rewritten), len, ctx->fp); free(rewritten); } ctx->iter_state = STATE_IN_STYLE; } else if (event_type == EVENT_ENTER && name_len == SLEN("head") && strncasecmp(name_data, "head", name_len) == 0) { /* If this is a HEAD element, insert a meta charset */ fputs("<META http-equiv=\"Content-Type\" " "content=\"text/html; charset=utf-8\">", ctx->fp); } dom_string_unref(name); return true; }
svgtiny_code svgtiny_parse_poly(dom_element *poly, struct svgtiny_parse_state state, bool polygon) { svgtiny_code err; dom_string *points_str; dom_exception exc; char *s, *points; float *p; unsigned int i; svgtiny_setup_state_local(&state); svgtiny_parse_paint_attributes(poly, &state); svgtiny_parse_transform_attributes(poly, &state); exc = dom_element_get_attribute(poly, state.interned_points, &points_str); if (exc != DOM_NO_ERR) { svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } if (points_str == NULL) { state.diagram->error_line = -1; /* poly->line; */ state.diagram->error_message = "polyline/polygon: missing points attribute"; svgtiny_cleanup_state_local(&state); return svgtiny_SVG_ERROR; } s = points = strndup(dom_string_data(points_str), dom_string_byte_length(points_str)); dom_string_unref(points_str); /* read points attribute */ if (s == NULL) { svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; } /* allocate space for path: it will never have more elements than s */ p = malloc(sizeof p[0] * strlen(s)); if (!p) { free(points); svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; } /* parse s and build path */ for (i = 0; s[i]; i++) if (s[i] == ',') s[i] = ' '; i = 0; while (*s) { float x, y; int n; if (sscanf(s, "%f %f %n", &x, &y, &n) == 2) { if (i == 0) p[i++] = svgtiny_PATH_MOVE; else p[i++] = svgtiny_PATH_LINE; p[i++] = x; p[i++] = y; s += n; } else { break; } } if (polygon) p[i++] = svgtiny_PATH_CLOSE; free(points); err = svgtiny_add_path(p, i, &state); svgtiny_cleanup_state_local(&state); return err; }
svgtiny_code svgtiny_parse_svg(dom_element *svg, struct svgtiny_parse_state state) { float x, y, width, height; dom_string *view_box; dom_element *child; dom_exception exc; svgtiny_setup_state_local(&state); svgtiny_parse_position_attributes(svg, state, &x, &y, &width, &height); svgtiny_parse_paint_attributes(svg, &state); svgtiny_parse_font_attributes(svg, &state); exc = dom_element_get_attribute(svg, state.interned_viewBox, &view_box); if (exc != DOM_NO_ERR) { svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } if (view_box) { char *s = strndup(dom_string_data(view_box), dom_string_byte_length(view_box)); float min_x, min_y, vwidth, vheight; if (sscanf(s, "%f,%f,%f,%f", &min_x, &min_y, &vwidth, &vheight) == 4 || sscanf(s, "%f %f %f %f", &min_x, &min_y, &vwidth, &vheight) == 4) { state.ctm.a = (float) state.viewport_width / vwidth; state.ctm.d = (float) state.viewport_height / vheight; state.ctm.e += -min_x * state.ctm.a; state.ctm.f += -min_y * state.ctm.d; } free(s); dom_string_unref(view_box); } svgtiny_parse_transform_attributes(svg, &state); exc = dom_node_get_first_child(svg, (dom_node **) (void *) &child); if (exc != DOM_NO_ERR) { svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } while (child != NULL) { dom_element *next; dom_node_type nodetype; svgtiny_code code = svgtiny_OK; exc = dom_node_get_node_type(child, &nodetype); if (exc != DOM_NO_ERR) { dom_node_unref(child); return svgtiny_LIBDOM_ERROR; } if (nodetype == DOM_ELEMENT_NODE) { dom_string *nodename; exc = dom_node_get_node_name(child, &nodename); if (exc != DOM_NO_ERR) { dom_node_unref(child); svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } if (dom_string_caseless_isequal(state.interned_svg, nodename)) code = svgtiny_parse_svg(child, state); else if (dom_string_caseless_isequal(state.interned_g, nodename)) code = svgtiny_parse_svg(child, state); else if (dom_string_caseless_isequal(state.interned_a, nodename)) code = svgtiny_parse_svg(child, state); else if (dom_string_caseless_isequal(state.interned_path, nodename)) code = svgtiny_parse_path(child, state); else if (dom_string_caseless_isequal(state.interned_rect, nodename)) code = svgtiny_parse_rect(child, state); else if (dom_string_caseless_isequal(state.interned_circle, nodename)) code = svgtiny_parse_circle(child, state); else if (dom_string_caseless_isequal(state.interned_ellipse, nodename)) code = svgtiny_parse_ellipse(child, state); else if (dom_string_caseless_isequal(state.interned_line, nodename)) code = svgtiny_parse_line(child, state); else if (dom_string_caseless_isequal(state.interned_polyline, nodename)) code = svgtiny_parse_poly(child, state, false); else if (dom_string_caseless_isequal(state.interned_polygon, nodename)) code = svgtiny_parse_poly(child, state, true); else if (dom_string_caseless_isequal(state.interned_text, nodename)) code = svgtiny_parse_text(child, state); dom_string_unref(nodename); } if (code != svgtiny_OK) { dom_node_unref(child); svgtiny_cleanup_state_local(&state); return code; } exc = dom_node_get_next_sibling(child, (dom_node **) (void *) &next); dom_node_unref(child); if (exc != DOM_NO_ERR) { svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } child = next; } svgtiny_cleanup_state_local(&state); return svgtiny_OK; }
/** * process form element from dom */ static struct form * parse_form_element(const char *docenc, dom_node *node) { dom_string *ds_action = NULL; dom_string *ds_charset = NULL; dom_string *ds_target = NULL; dom_string *ds_method = NULL; dom_string *ds_enctype = NULL; char *action = NULL, *charset = NULL, *target = NULL; form_method method; dom_html_form_element *formele = (dom_html_form_element *)(node); struct form * ret = NULL; /* Retrieve the attributes from the node */ if (dom_html_form_element_get_action(formele, &ds_action) != DOM_NO_ERR) goto out; if (dom_html_form_element_get_accept_charset(formele, &ds_charset) != DOM_NO_ERR) goto out; if (dom_html_form_element_get_target(formele, &ds_target) != DOM_NO_ERR) goto out; if (dom_html_form_element_get_method(formele, &ds_method) != DOM_NO_ERR) goto out; if (dom_html_form_element_get_enctype(formele, &ds_enctype) != DOM_NO_ERR) goto out; /* Extract the plain attributes ready for use. We have to do this * because we cannot guarantee that the dom_strings are NULL terminated * and thus we copy them. */ if (ds_action != NULL) action = strndup(dom_string_data(ds_action), dom_string_byte_length(ds_action)); if (ds_charset != NULL) charset = strndup(dom_string_data(ds_charset), dom_string_byte_length(ds_charset)); if (ds_target != NULL) target = strndup(dom_string_data(ds_target), dom_string_byte_length(ds_target)); /* Determine the method */ method = method_GET; if (ds_method != NULL) { if (dom_string_caseless_lwc_isequal(ds_method, corestring_lwc_post)) { method = method_POST_URLENC; if (ds_enctype != NULL) { if (dom_string_caseless_lwc_isequal(ds_enctype, corestring_lwc_multipart_form_data)) { method = method_POST_MULTIPART; } } } } /* Construct the form object */ ret = form_new(node, action, target, method, charset, docenc); out: if (ds_action != NULL) dom_string_unref(ds_action); if (ds_charset != NULL) dom_string_unref(ds_charset); if (ds_target != NULL) dom_string_unref(ds_target); if (ds_method != NULL) dom_string_unref(ds_method); if (ds_enctype != NULL) dom_string_unref(ds_enctype); if (action != NULL) free(action); if (charset != NULL) free(charset); if (target != NULL) free(target); return ret; }
static struct form_control * parse_input_element(struct form *forms, dom_html_input_element *input) { struct form_control *control = NULL; dom_html_form_element *form = NULL; dom_string *ds_type = NULL; dom_string *ds_name = NULL; dom_string *ds_value = NULL; char *name = NULL; if (dom_html_input_element_get_form(input, &form) != DOM_NO_ERR) goto out; if (dom_html_input_element_get_type(input, &ds_type) != DOM_NO_ERR) goto out; if (dom_html_input_element_get_name(input, &ds_name) != DOM_NO_ERR) goto out; if (ds_name != NULL) name = strndup(dom_string_data(ds_name), dom_string_byte_length(ds_name)); if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_password)) { control = form_new_control(input, GADGET_PASSWORD); } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_file)) { control = form_new_control(input, GADGET_FILE); } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_hidden)) { control = form_new_control(input, GADGET_HIDDEN); } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_checkbox)) { control = form_new_control(input, GADGET_CHECKBOX); } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_radio)) { control = form_new_control(input, GADGET_RADIO); } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_submit)) { control = form_new_control(input, GADGET_SUBMIT); } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_reset)) { control = form_new_control(input, GADGET_RESET); } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_button)) { control = form_new_control(input, GADGET_BUTTON); } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type, corestring_lwc_image)) { control = form_new_control(input, GADGET_IMAGE); } else { control = form_new_control(input, GADGET_TEXTBOX); } if (control == NULL) goto out; if (name != NULL) { /* Hand the name string over */ control->name = name; name = NULL; } if (control->type == GADGET_CHECKBOX || control->type == GADGET_RADIO) { bool selected; if (dom_html_input_element_get_checked( input, &selected) == DOM_NO_ERR) { control->selected = selected; } } if (control->type == GADGET_PASSWORD || control->type == GADGET_TEXTBOX) { int32_t maxlength; if (dom_html_input_element_get_max_length( input, &maxlength) != DOM_NO_ERR) { maxlength = -1; } if (maxlength >= 0) { /* Got valid maxlength */ control->maxlength = maxlength; } else { /* Input has no maxlength attr, or * dom_html_input_element_get_max_length failed. * * Set it to something insane. */ control->maxlength = UINT_MAX; } } if (control->type != GADGET_FILE && control->type != GADGET_IMAGE) { if (dom_html_input_element_get_value( input, &ds_value) == DOM_NO_ERR) { if (ds_value != NULL) { control->value = strndup( dom_string_data(ds_value), dom_string_byte_length(ds_value)); if (control->value == NULL) { form_free_control(control); control = NULL; goto out; } control->length = strlen(control->value); } } if (control->type == GADGET_TEXTBOX || control->type == GADGET_PASSWORD) { if (control->value == NULL) { control->value = strdup(""); if (control->value == NULL) { form_free_control(control); control = NULL; goto out; } control->length = 0; } control->initial_value = strdup(control->value); if (control->initial_value == NULL) { form_free_control(control); control = NULL; goto out; } } } if (form != NULL && control != NULL) form_add_control(find_form(forms, form), control); out: if (form != NULL) dom_node_unref(form); if (ds_type != NULL) dom_string_unref(ds_type); if (ds_name != NULL) dom_string_unref(ds_name); if (ds_value != NULL) dom_string_unref(ds_value); if (name != NULL) free(name); return control; }
/** * Replace a section of a dom string * * \param target Pointer to string of which to replace a section * \param source Pointer to replacement string * \param i1 Character index of start of region to replace * \param i2 Character index of end of region to replace * \param result Pointer to location to receive result * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion. * * The returned string will have its reference count increased. The client * should dereference it once it has finished with it. */ dom_exception dom_string_replace(dom_string *target, dom_string *source, off_t i1, off_t i2, dom_string **result) { dom_string_internal *res; const uint8_t *t, *s; size_t tlen, slen; off_t b1, b2; parserutils_error err; /* target string is NULL equivalent to empty. */ if (target == NULL) target = (dom_string *)&empty_string; t = (const uint8_t *) dom_string_data(target); tlen = dom_string_byte_length(target); s = (const uint8_t *) dom_string_data(source); slen = dom_string_byte_length(source); /* Initialise the byte index of the start to 0 */ b1 = 0; /* Make the end a character offset from the start */ i2 -= i1; /* Calculate the byte index of the start */ while (i1 > 0) { err = parserutils_charset_utf8_next(t, tlen, b1, &b1); if (err != PARSERUTILS_OK) { return DOM_NO_MEM_ERR; } i1--; } /* Initialise the byte index of the end to that of the start */ b2 = b1; /* Calculate the byte index of the end */ while (i2 > 0) { err = parserutils_charset_utf8_next(t, tlen, b2, &b2); if (err != PARSERUTILS_OK) { return DOM_NO_MEM_ERR; } i2--; } /* Allocate result string */ res = malloc(sizeof(*res)); if (res == NULL) { return DOM_NO_MEM_ERR; } /* Allocate data buffer for result contents */ res->data.cdata.ptr = malloc((unsigned long)(tlen + slen - (b2 - b1) + 1)); if (res->data.cdata.ptr == NULL) { free(res); return DOM_NO_MEM_ERR; } /* Copy initial portion of target, if any, into result */ if (b1 > 0) { memcpy(res->data.cdata.ptr, t, (unsigned long)b1); } /* Copy replacement data into result */ if (slen > 0) { memcpy(res->data.cdata.ptr + b1, s, slen); } /* Copy remainder of target, if any, into result */ if (tlen - b2 > 0) { memcpy(res->data.cdata.ptr + b1 + slen, t + b2, (unsigned long)(tlen - b2)); } res->data.cdata.ptr[tlen + slen - (b2 - b1)] = '\0'; res->data.cdata.len = (size_t)(tlen + slen - (b2 - b1)); res->base.refcnt = 1; res->type = DOM_STRING_CDATA; *result = (dom_string *)res; return DOM_NO_ERR; }
static bool save_complete_node_handler(dom_node *node, save_complete_event_type event_type, void *ctxin) { save_complete_ctx *ctx = ctxin; dom_node_type type; dom_exception error; utf8_convert_ret ret; error = dom_node_get_node_type(node, &type); if (error != DOM_NO_ERR) return false; if (type == DOM_ELEMENT_NODE) { return save_complete_handle_element(ctx, node, event_type); } else if (type == DOM_TEXT_NODE || type == DOM_COMMENT_NODE) { if (event_type != EVENT_ENTER) return true; if (ctx->iter_state != STATE_IN_STYLE) { /* Emit text content */ dom_string *text; const char *text_data; size_t text_len; error = dom_characterdata_get_data(node, &text); if (error != DOM_NO_ERR) { return false; } if (type == DOM_COMMENT_NODE) fwrite("<!--", 1, sizeof("<!--") - 1, ctx->fp); if (text != NULL) { char *escaped; text_data = dom_string_data(text); text_len = dom_string_byte_length(text); ret = utf8_to_html(text_data, "UTF-8", text_len, &escaped); if (ret != UTF8_CONVERT_OK) return false; fwrite(escaped, sizeof(*escaped), strlen(escaped), ctx->fp); free(escaped); dom_string_unref(text); } if (type == DOM_COMMENT_NODE) { fwrite("-->", 1, sizeof("-->") - 1, ctx->fp); } } } else if (type == DOM_DOCUMENT_TYPE_NODE) { dom_string *name; const char *name_data; size_t name_len; if (event_type != EVENT_ENTER) return true; error = dom_document_type_get_name(node, &name); if (error != DOM_NO_ERR) return false; if (name == NULL) return true; name_data = dom_string_data(name); name_len = dom_string_byte_length(name); fputs("<!DOCTYPE ", ctx->fp); fwrite(name_data, sizeof(*name_data), name_len, ctx->fp); dom_string_unref(name); error = dom_document_type_get_public_id(node, &name); if (error != DOM_NO_ERR) return false; if (name != NULL) { name_data = dom_string_data(name); name_len = dom_string_byte_length(name); if (name_len > 0) fprintf(ctx->fp, " PUBLIC \"%.*s\"", (int) name_len, name_data); dom_string_unref(name); } error = dom_document_type_get_system_id(node, &name); if (error != DOM_NO_ERR) return false; if (name != NULL) { name_data = dom_string_data(name); name_len = dom_string_byte_length(name); if (name_len > 0) fprintf(ctx->fp, " \"%.*s\"", (int) name_len, name_data); dom_string_unref(name); } fputc('>', ctx->fp); } else if (type == DOM_DOCUMENT_NODE) { /* Do nothing */ } else { LOG(("Unhandled node type: %d", type)); } return true; }
svgtiny_code svgtiny_parse_path(dom_element *path, struct svgtiny_parse_state state) { svgtiny_code err; dom_string *path_d_str; dom_exception exc; char *s, *path_d; float *p; unsigned int i; float last_x = 0, last_y = 0; float last_cubic_x = 0, last_cubic_y = 0; float last_quad_x = 0, last_quad_y = 0; svgtiny_setup_state_local(&state); svgtiny_parse_paint_attributes(path, &state); svgtiny_parse_transform_attributes(path, &state); /* read d attribute */ exc = dom_element_get_attribute(path, state.interned_d, &path_d_str); if (exc != DOM_NO_ERR) { state.diagram->error_line = -1; /* path->line; */ state.diagram->error_message = "path: error retrieving d attribute"; svgtiny_cleanup_state_local(&state); return svgtiny_SVG_ERROR; } if (path_d_str == NULL) { state.diagram->error_line = -1; /* path->line; */ state.diagram->error_message = "path: missing d attribute"; svgtiny_cleanup_state_local(&state); return svgtiny_SVG_ERROR; } s = path_d = strndup(dom_string_data(path_d_str), dom_string_byte_length(path_d_str)); dom_string_unref(path_d_str); if (s == NULL) { svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; } /* allocate space for path: it will never have more elements than d */ p = malloc(sizeof p[0] * strlen(s)); if (!p) { free(path_d); svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; } /* parse d and build path */ for (i = 0; s[i]; i++) if (s[i] == ',') s[i] = ' '; i = 0; while (*s) { char command[2]; int plot_command; float x, y, x1, y1, x2, y2, rx, ry, rotation, large_arc, sweep; int n; /* moveto (M, m), lineto (L, l) (2 arguments) */ if (sscanf(s, " %1[MmLl] %f %f %n", command, &x, &y, &n) == 3) { /*LOG(("moveto or lineto"));*/ if (*command == 'M' || *command == 'm') plot_command = svgtiny_PATH_MOVE; else plot_command = svgtiny_PATH_LINE; do { p[i++] = plot_command; if ('a' <= *command) { x += last_x; y += last_y; } p[i++] = last_cubic_x = last_quad_x = last_x = x; p[i++] = last_cubic_y = last_quad_y = last_y = y; s += n; plot_command = svgtiny_PATH_LINE; } while (sscanf(s, "%f %f %n", &x, &y, &n) == 2); /* closepath (Z, z) (no arguments) */ } else if (sscanf(s, " %1[Zz] %n", command, &n) == 1) { /*LOG(("closepath"));*/ p[i++] = svgtiny_PATH_CLOSE; s += n; /* horizontal lineto (H, h) (1 argument) */ } else if (sscanf(s, " %1[Hh] %f %n", command, &x, &n) == 2) { /*LOG(("horizontal lineto"));*/ do { p[i++] = svgtiny_PATH_LINE; if (*command == 'h') x += last_x; p[i++] = last_cubic_x = last_quad_x = last_x = x; p[i++] = last_cubic_y = last_quad_y = last_y; s += n; } while (sscanf(s, "%f %n", &x, &n) == 1); /* vertical lineto (V, v) (1 argument) */ } else if (sscanf(s, " %1[Vv] %f %n", command, &y, &n) == 2) { /*LOG(("vertical lineto"));*/ do { p[i++] = svgtiny_PATH_LINE; if (*command == 'v') y += last_y; p[i++] = last_cubic_x = last_quad_x = last_x; p[i++] = last_cubic_y = last_quad_y = last_y = y; s += n; } while (sscanf(s, "%f %n", &x, &n) == 1); /* curveto (C, c) (6 arguments) */ } else if (sscanf(s, " %1[Cc] %f %f %f %f %f %f %n", command, &x1, &y1, &x2, &y2, &x, &y, &n) == 7) { /*LOG(("curveto"));*/ do { p[i++] = svgtiny_PATH_BEZIER; if (*command == 'c') { x1 += last_x; y1 += last_y; x2 += last_x; y2 += last_y; x += last_x; y += last_y; } p[i++] = x1; p[i++] = y1; p[i++] = last_cubic_x = x2; p[i++] = last_cubic_y = y2; p[i++] = last_quad_x = last_x = x; p[i++] = last_quad_y = last_y = y; s += n; } while (sscanf(s, "%f %f %f %f %f %f %n", &x1, &y1, &x2, &y2, &x, &y, &n) == 6); /* shorthand/smooth curveto (S, s) (4 arguments) */ } else if (sscanf(s, " %1[Ss] %f %f %f %f %n", command, &x2, &y2, &x, &y, &n) == 5) { /*LOG(("shorthand/smooth curveto"));*/ do { p[i++] = svgtiny_PATH_BEZIER; x1 = last_x + (last_x - last_cubic_x); y1 = last_y + (last_y - last_cubic_y); if (*command == 's') { x2 += last_x; y2 += last_y; x += last_x; y += last_y; } p[i++] = x1; p[i++] = y1; p[i++] = last_cubic_x = x2; p[i++] = last_cubic_y = y2; p[i++] = last_quad_x = last_x = x; p[i++] = last_quad_y = last_y = y; s += n; } while (sscanf(s, "%f %f %f %f %n", &x2, &y2, &x, &y, &n) == 4); /* quadratic Bezier curveto (Q, q) (4 arguments) */ } else if (sscanf(s, " %1[Qq] %f %f %f %f %n", command, &x1, &y1, &x, &y, &n) == 5) { /*LOG(("quadratic Bezier curveto"));*/ do { p[i++] = svgtiny_PATH_BEZIER; last_quad_x = x1; last_quad_y = y1; if (*command == 'q') { x1 += last_x; y1 += last_y; x += last_x; y += last_y; } p[i++] = 1./3 * last_x + 2./3 * x1; p[i++] = 1./3 * last_y + 2./3 * y1; p[i++] = 2./3 * x1 + 1./3 * x; p[i++] = 2./3 * y1 + 1./3 * y; p[i++] = last_cubic_x = last_x = x; p[i++] = last_cubic_y = last_y = y; s += n; } while (sscanf(s, "%f %f %f %f %n", &x1, &y1, &x, &y, &n) == 4); /* shorthand/smooth quadratic Bezier curveto (T, t) (2 arguments) */ } else if (sscanf(s, " %1[Tt] %f %f %n", command, &x, &y, &n) == 3) { /*LOG(("shorthand/smooth quadratic Bezier curveto"));*/ do { p[i++] = svgtiny_PATH_BEZIER; x1 = last_x + (last_x - last_quad_x); y1 = last_y + (last_y - last_quad_y); last_quad_x = x1; last_quad_y = y1; if (*command == 't') { x1 += last_x; y1 += last_y; x += last_x; y += last_y; } p[i++] = 1./3 * last_x + 2./3 * x1; p[i++] = 1./3 * last_y + 2./3 * y1; p[i++] = 2./3 * x1 + 1./3 * x; p[i++] = 2./3 * y1 + 1./3 * y; p[i++] = last_cubic_x = last_x = x; p[i++] = last_cubic_y = last_y = y; s += n; } while (sscanf(s, "%f %f %n", &x, &y, &n) == 2); /* elliptical arc (A, a) (7 arguments) */ } else if (sscanf(s, " %1[Aa] %f %f %f %f %f %f %f %n", command, &rx, &ry, &rotation, &large_arc, &sweep, &x, &y, &n) == 8) { do { p[i++] = svgtiny_PATH_LINE; if (*command == 'a') { x += last_x; y += last_y; } p[i++] = last_cubic_x = last_quad_x = last_x = x; p[i++] = last_cubic_y = last_quad_y = last_y = y; s += n; } while (sscanf(s, "%f %f %f %f %f %f %f %n", &rx, &ry, &rotation, &large_arc, &sweep, &x, &y, &n) == 7); } else { fprintf(stderr, "parse failed at \"%s\"\n", s); break; } } free(path_d); if (i <= 4) { /* no real segments in path */ free(p); svgtiny_cleanup_state_local(&state); return svgtiny_OK; } err = svgtiny_add_path(p, i, &state); svgtiny_cleanup_state_local(&state); return err; }
/** * Insert data into a dom string at the given location * * \param target Pointer to string to insert into * \param source Pointer to string to insert * \param offset Character offset of location to insert at * \param result Pointer to location to receive result * \return DOM_NO_ERR on success, * DOM_NO_MEM_ERR on memory exhaustion, * DOM_INDEX_SIZE_ERR if ::offset > len(::target). * * The returned string will have its reference count increased. The client * should dereference it once it has finished with it. */ dom_exception dom_string_insert(dom_string *target, dom_string *source, off_t offset, dom_string **result) { dom_string_internal *res; const uint8_t *t, *s; size_t tlen, slen, clen; off_t ins = 0; parserutils_error err; /* target string is NULL equivalent to empty. */ if (target == NULL) target = (dom_string *)&empty_string; t = (const uint8_t *) dom_string_data(target); tlen = dom_string_byte_length(target); s = (const uint8_t *) dom_string_data(source); slen = dom_string_byte_length(source); clen = dom_string_length(target); if (offset > clen) return DOM_INDEX_SIZE_ERR; /* Calculate the byte index of the insertion point */ if (offset == clen) { /* Optimisation for append */ ins = tlen; } else { while (offset > 0) { err = parserutils_charset_utf8_next(t, tlen, ins, &ins); if (err != PARSERUTILS_OK) { return DOM_NO_MEM_ERR; } offset--; } } /* Allocate result string */ res = malloc(sizeof(*res)); if (res == NULL) { return DOM_NO_MEM_ERR; } /* Allocate data buffer for result contents */ res->data.cdata.ptr = malloc(tlen + slen + 1); if (res->data.cdata.ptr == NULL) { free(res); return DOM_NO_MEM_ERR; } /* Copy initial portion of target, if any, into result */ if (ins > 0) { memcpy(res->data.cdata.ptr, t, (unsigned long)ins); } /* Copy inserted data into result */ memcpy(res->data.cdata.ptr + ins, s, slen); /* Copy remainder of target, if any, into result */ if (tlen - ins > 0) { memcpy(res->data.cdata.ptr + ins + slen, t + ins, (unsigned long)(tlen - ins)); } res->data.cdata.ptr[tlen + slen] = '\0'; res->data.cdata.len = tlen + slen; res->base.refcnt = 1; res->type = DOM_STRING_CDATA; *result = (dom_string *)res; return DOM_NO_ERR; }