css_error node_has_attribute_prefix(void *pw, void *n, const css_qname *qname, lwc_string *value, bool *match) { node *node = n; uint32_t i; UNUSED(pw); *match = false; for (i = 0; i < node->n_attrs; i++) { assert(lwc_string_caseless_isequal( node->attrs[i].name, qname->name, match) == lwc_error_ok); if (*match == true) break; } if (*match == true) { size_t len = lwc_string_length(node->attrs[i].value); const char *data = lwc_string_data(node->attrs[i].value); size_t vlen = lwc_string_length(value); const char *vdata = lwc_string_data(value); if (len < vlen) *match = false; else *match = (strncasecmp(data, vdata, vlen) == 0); } return CSS_OK; }
/** * 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; }
/** * 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; }
css_fixed css__number_from_lwc_string(lwc_string *string, bool int_only, size_t *consumed) { if (string == NULL || lwc_string_length(string) == 0 || consumed == NULL) return 0; return css__number_from_string( (uint8_t *)lwc_string_data(string), lwc_string_length(string), int_only, consumed); }
/** * 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; }
/** * Try and find the correct RISC OS filetype from a download context. */ static nserror download_ro_filetype(download_context *ctx, bits *ftype_out) { nsurl *url = download_context_get_url(ctx); bits ftype = 0; lwc_string *scheme; /* If the file is local try and read its filetype */ scheme = nsurl_get_component(url, NSURL_SCHEME); if (scheme != NULL) { bool filescheme; if (lwc_string_isequal(scheme, corestring_lwc_file, &filescheme) != lwc_error_ok) { filescheme = false; } if (filescheme) { lwc_string *path = nsurl_get_component(url, NSURL_PATH); if (path != NULL && lwc_string_length(path) != 0) { char *raw_path; if (url_unescape(lwc_string_data(path), lwc_string_length(path), &raw_path) == NSERROR_OK) { ftype = ro_filetype_from_unix_path(raw_path); free(raw_path); } } } } /* If we still don't have a filetype (i.e. failed reading local * one or fetching a remote object), then use the MIME type. */ if (ftype == 0) { /* convert MIME type to RISC OS file type */ os_error *error; const char *mime_type; mime_type = download_context_get_mime_type(ctx); error = xmimemaptranslate_mime_type_to_filetype(mime_type, &ftype); if (error) { LOG("xmimemaptranslate_mime_type_to_filetype: 0x%x: %s", error->errnum, error->errmess); ro_warn_user("MiscError", error->errmess); ftype = 0xffd; } } *ftype_out = ftype; return NSERROR_OK; }
/** * Parse a hash colour (#rgb or #rrggbb) * * \param data Pointer to colour string * \param result Pointer to location to receive result (AARRGGBB) * \return CSS_OK on success, * CSS_INVALID if the input is invalid */ css_error css__parse_hash_colour(lwc_string *data, uint32_t *result) { uint8_t r = 0, g = 0, b = 0, a = 0xff; size_t len = lwc_string_length(data); const char *input = lwc_string_data(data); if (len == 3 && isHex(input[0]) && isHex(input[1]) && isHex(input[2])) { r = charToHex(input[0]); g = charToHex(input[1]); b = charToHex(input[2]); r |= (r << 4); g |= (g << 4); b |= (b << 4); } else if (len == 6 && isHex(input[0]) && isHex(input[1]) && isHex(input[2]) && isHex(input[3]) && isHex(input[4]) && isHex(input[5])) { r = (charToHex(input[0]) << 4); r |= charToHex(input[1]); g = (charToHex(input[2]) << 4); g |= charToHex(input[3]); b = (charToHex(input[4]) << 4); b |= charToHex(input[5]); } else return CSS_INVALID; *result = (a << 24) | (r << 16) | (g << 8) | b; return CSS_OK; }
css_error node_has_attribute_substring(void *pw, void *n, const css_qname *qname, lwc_string *value, bool *match) { node *node = n; uint32_t i; UNUSED(pw); *match = false; for (i = 0; i < node->n_attrs; i++) { assert(lwc_string_caseless_isequal( node->attrs[i].name, qname->name, match) == lwc_error_ok); if (*match == true) break; } if (*match == true) { size_t len = lwc_string_length(node->attrs[i].value); const char *data = lwc_string_data(node->attrs[i].value); size_t vlen = lwc_string_length(value); const char *vdata = lwc_string_data(value); const char *last_start = data + len - vlen; if (len < vlen) *match = false; else { while (data <= last_start) { if (strncasecmp(data, vdata, vlen) == 0) { *match = true; break; } data++; } if (data > last_start) *match = false; } } return CSS_OK; }
/** * Initialise a CSS content * * \param c Content to initialise * \param params Content-Type parameters * \return true on success, false on failure */ nserror nscss_create(const content_handler *handler, lwc_string *imime_type, const http_parameter *params, llcache_handle *llcache, const char *fallback_charset, bool quirks, struct content **c) { nscss_content *result; const char *charset = NULL; const char *xnsbase = NULL; lwc_string *charset_value = NULL; union content_msg_data msg_data; nserror error; result = calloc(1, sizeof(nscss_content)); if (result == NULL) return NSERROR_NOMEM; error = content__init(&result->base, handler, imime_type, params, llcache, fallback_charset, quirks); if (error != NSERROR_OK) { free(result); return error; } /* Find charset specified on HTTP layer, if any */ error = http_parameter_list_find_item(params, css_charset, &charset_value); if (error != NSERROR_OK || lwc_string_length(charset_value) == 0) { /* No charset specified, use fallback, if any */ /** \todo libcss will take this as gospel, which is wrong */ charset = fallback_charset; } else { charset = lwc_string_data(charset_value); } /* Compute base URL for stylesheet */ xnsbase = llcache_handle_get_header(llcache, "X-NS-Base"); if (xnsbase == NULL) { xnsbase = nsurl_access(content_get_url(&result->base)); } error = nscss_create_css_data(&result->data, xnsbase, charset, result->base.quirks, nscss_content_done, result); if (error != NSERROR_OK) { msg_data.error = messages_get("NoMemory"); content_broadcast(&result->base, CONTENT_MSG_ERROR, msg_data); if (charset_value != NULL) lwc_string_unref(charset_value); free(result); return error; } if (charset_value != NULL) lwc_string_unref(charset_value); *c = (struct content *) result; return NSERROR_OK; }
static void netsurf_lwc_iterator(lwc_string *str, void *pw) { fprintf(stderr, "[%3u] %.*s", str->refcnt, (int)lwc_string_length(str), lwc_string_data(str)); }
static void printing_lwc_iterator(lwc_string *str, void *pw) { UNUSED(pw); printf(" DICT: %*s\n", (int)(lwc_string_length(str)), lwc_string_data(str)); fail_because_lwc_leaked = true; }
css_error node_has_attribute_dashmatch(void *pw, void *n, const css_qname *qname, lwc_string *value, bool *match) { node *node = n; uint32_t i; size_t vlen = lwc_string_length(value); UNUSED(pw); *match = false; for (i = 0; i < node->n_attrs; i++) { assert(lwc_string_caseless_isequal( node->attrs[i].name, qname->name, match) == lwc_error_ok); if (*match == true) break; } if (*match == true) { const char *p; const char *start = lwc_string_data(node->attrs[i].value); const char *end = start + lwc_string_length(node->attrs[i].value); *match = false; for (p = start; p < end; p++) { if (*p == '-') { if ((size_t) (p - start) == vlen && strncasecmp(start, lwc_string_data(value), vlen) == 0) { *match = true; break; } start = p + 1; } } } return CSS_OK; }
END_TEST START_TEST (test_lwc_extract_data_ok) { fail_unless(memcmp("one", lwc_string_data(intern_one), lwc_string_length(intern_one)) == 0, "Extracting data ptr etc failed"); }
/** Get the byte length of this dom_string * * \param str The dom_string object */ size_t dom_string_byte_length(const dom_string *str) { dom_string_internal *istr = (dom_string_internal *) str; if (istr->type == DOM_STRING_CDATA) { return istr->data.cdata.len; } else { return lwc_string_length(istr->data.intern); } }
END_TEST START_TEST (test_lwc_string_is_nul_terminated) { lwc_string *new_ONE; fail_unless(lwc_intern_string("ONE", 3, &new_ONE) == lwc_error_ok, "Failure interning 'ONE'"); fail_unless(lwc_string_data(new_ONE)[lwc_string_length(new_ONE)] == '\0', "Interned string isn't NUL terminated"); }
/** * Callback to determine if a node has an attribute with given name and value. * * \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_equal(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); *match = dom_string_caseless_lwc_isequal(atr_val, value); dom_string_unref(atr_val); return CSS_OK; }
/** * Parse widows * * \param c Parsing context * \param vector Vector of tokens to process * \param ctx Pointer to vector iteration context * \param result resulting style * \return CSS_OK on success, * CSS_NOMEM on memory exhaustion, * CSS_INVALID if the input is not valid * * Post condition: \a *ctx is updated with the next token to process * If the input is invalid, then \a *ctx remains unchanged. */ css_error css__parse_widows(css_language *c, const parserutils_vector *vector, int *ctx, css_style *result) { int orig_ctx = *ctx; css_error error; const css_token *token; bool match; token = parserutils_vector_iterate(vector, ctx); if ((token == NULL) || ((token->type != CSS_TOKEN_IDENT) && (token->type != CSS_TOKEN_NUMBER))) { *ctx = orig_ctx; return CSS_INVALID; } if ((token->type == CSS_TOKEN_IDENT) && (lwc_string_caseless_isequal(token->idata, c->strings[INHERIT], &match) == lwc_error_ok && match)) { error = css_stylesheet_style_inherit(result, CSS_PROP_WIDOWS); } else if (token->type == CSS_TOKEN_NUMBER) { css_fixed num = 0; size_t consumed = 0; num = css__number_from_lwc_string(token->idata, true, &consumed); /* Invalid if there are trailing characters */ if (consumed != lwc_string_length(token->idata)) { *ctx = orig_ctx; return CSS_INVALID; } if (num<0) { *ctx = orig_ctx; return CSS_INVALID; } error = css__stylesheet_style_appendOPV(result, CSS_PROP_WIDOWS, 0, WIDOWS_SET); if (error != CSS_OK) { *ctx = orig_ctx; return error; } error = css__stylesheet_style_append(result, num); } else { error = CSS_INVALID; } if (error != CSS_OK) *ctx = orig_ctx; return error; }
css_error node_has_name(void *pw, void *n, const css_qname *qname, bool *match) { node *node = n; UNUSED(pw); if (lwc_string_length(qname->name) == 1 && lwc_string_data(qname->name)[0] == '*') *match = true; else assert(lwc_string_caseless_isequal(node->name, qname->name, match) == lwc_error_ok); return CSS_OK; }
/** * Case insensitively 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_caseless_lwc_isequal(const dom_string *s1, lwc_string *s2) { size_t len; const uint8_t *d1 = NULL; const uint8_t *d2 = NULL; dom_string_internal *is1 = (dom_string_internal *) s1; if (s1 == NULL || s2 == NULL) return false; if (is1->type == DOM_STRING_INTERNED) { bool match; if (lwc_string_caseless_isequal(is1->data.intern, s2, &match) != lwc_error_ok) return false; return match; } len = dom_string_byte_length(s1); if (len != lwc_string_length(s2)) return false; d1 = (const uint8_t *) dom_string_data(s1); d2 = (const uint8_t *) lwc_string_data(s2); 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. * * \param pw HTML document * \param node DOM node * \param qname Name 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(void *pw, void *node, const css_qname *qname, bool *match) { dom_node *n = node; dom_string *name; dom_exception err; 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_has_attribute(n, name, match); if (err != DOM_NO_ERR) { dom_string_unref(name); return CSS_OK; } dom_string_unref(name); return CSS_OK; }
/** * 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); }
END_TEST START_TEST (test_lwc_string_length_aborts) { lwc_string_length(NULL); }
void ro_gui_401login_open(nsurl *url, lwc_string *host, const char *realm, nserror (*cb)(bool proceed, void *pw), void *cbpw) { struct session_401 *session; wimp_w w; const char *auth; session = calloc(1, sizeof(struct session_401)); if (!session) { warn_user("NoMemory", 0); return; } session->url = nsurl_ref(url); if (realm == NULL) realm = "Secure Area"; auth = urldb_get_auth_details(session->url, realm); if (auth == NULL) { session->uname[0] = '\0'; session->pwd[0] = '\0'; } else { const char *pwd; size_t pwd_len; pwd = strchr(auth, ':'); assert(pwd && pwd < auth + sizeof(session->uname)); memcpy(session->uname, auth, pwd - auth); session->uname[pwd - auth] = '\0'; ++pwd; pwd_len = strlen(pwd); assert(pwd_len < sizeof(session->pwd)); memcpy(session->pwd, pwd, pwd_len); session->pwd[pwd_len] = '\0'; } session->host = lwc_string_ref(host); session->realm = strdup(realm); session->cb = cb; session->cbpw = cbpw; if (!session->realm) { nsurl_unref(session->url); lwc_string_unref(session->host); free(session); warn_user("NoMemory", 0); return; } /* fill in download window icons */ dialog_401_template->icons[ICON_401LOGIN_HOST].data. indirected_text.text = (char *)lwc_string_data(session->host); dialog_401_template->icons[ICON_401LOGIN_HOST].data. indirected_text.size = lwc_string_length(session->host) + 1; dialog_401_template->icons[ICON_401LOGIN_REALM].data. indirected_text.text = session->realm; dialog_401_template->icons[ICON_401LOGIN_REALM].data. indirected_text.size = strlen(session->realm) + 1; dialog_401_template->icons[ICON_401LOGIN_USERNAME].data. indirected_text.text = session->uname; dialog_401_template->icons[ICON_401LOGIN_USERNAME].data. indirected_text.size = sizeof(session->uname); dialog_401_template->icons[ICON_401LOGIN_PASSWORD].data. indirected_text.text = session->pwd; dialog_401_template->icons[ICON_401LOGIN_PASSWORD].data. indirected_text.size = sizeof(session->pwd); /* create and open the window */ w = wimp_create_window(dialog_401_template); ro_gui_wimp_event_register_text_field(w, ICON_401LOGIN_USERNAME); ro_gui_wimp_event_register_text_field(w, ICON_401LOGIN_PASSWORD); ro_gui_wimp_event_register_cancel(w, ICON_401LOGIN_CANCEL); ro_gui_wimp_event_register_ok(w, ICON_401LOGIN_LOGIN, ro_gui_401login_apply); ro_gui_wimp_event_register_close_window(w, ro_gui_401login_close); ro_gui_wimp_event_set_user_data(w, session); ro_gui_dialog_open_persistent(NULL, w, false); }
/** * Parse line-height * * \param c Parsing context * \param vector Vector of tokens to process * \param ctx Pointer to vector iteration context * \param result Pointer to location to receive resulting style * \return CSS_OK on success, * CSS_NOMEM on memory exhaustion, * CSS_INVALID if the input is not valid * * Post condition: \a *ctx is updated with the next token to process * If the input is invalid, then \a *ctx remains unchanged. */ css_error parse_line_height(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) { int orig_ctx = *ctx; css_error error; const css_token *token; uint8_t flags = 0; uint16_t value = 0; uint32_t opv; css_fixed length = 0; uint32_t unit = 0; uint32_t required_size; bool match; /* number | length | percentage | IDENT(normal, inherit) */ token = parserutils_vector_peek(vector, *ctx); if (token == NULL) { *ctx = orig_ctx; return CSS_INVALID; } if (token->type == CSS_TOKEN_IDENT && (lwc_string_caseless_isequal( token->idata, c->strings[INHERIT], &match) == lwc_error_ok && match)) { parserutils_vector_iterate(vector, ctx); flags = FLAG_INHERIT; } else if (token->type == CSS_TOKEN_IDENT && (lwc_string_caseless_isequal( token->idata, c->strings[NORMAL], &match) == lwc_error_ok && match)) { parserutils_vector_iterate(vector, ctx); value = LINE_HEIGHT_NORMAL; } else if (token->type == CSS_TOKEN_NUMBER) { size_t consumed = 0; length = number_from_lwc_string(token->idata, false, &consumed); if (consumed != lwc_string_length(token->idata)) { *ctx = orig_ctx; return CSS_INVALID; } /* Negative values are illegal */ if (length < 0) { *ctx = orig_ctx; return CSS_INVALID; } parserutils_vector_iterate(vector, ctx); value = LINE_HEIGHT_NUMBER; } else { error = parse_unit_specifier(c, vector, ctx, UNIT_PX, &length, &unit); if (error != CSS_OK) { *ctx = orig_ctx; return error; } if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { *ctx = orig_ctx; return CSS_INVALID; } /* Negative values are illegal */ if (length < 0) { *ctx = orig_ctx; return CSS_INVALID; } value = LINE_HEIGHT_DIMENSION; } opv = buildOPV(CSS_PROP_LINE_HEIGHT, flags, value); required_size = sizeof(opv); if ((flags & FLAG_INHERIT) == false && value == LINE_HEIGHT_NUMBER) required_size += sizeof(length); else if ((flags & FLAG_INHERIT) == false && value == LINE_HEIGHT_DIMENSION) required_size += sizeof(length) + sizeof(unit); /* Allocate result */ error = css_stylesheet_style_create(c->sheet, required_size, result); if (error != CSS_OK) { *ctx = orig_ctx; return error; } /* Copy the bytecode to it */ memcpy((*result)->bytecode, &opv, sizeof(opv)); if ((flags & FLAG_INHERIT) == false && (value == LINE_HEIGHT_NUMBER || value == LINE_HEIGHT_DIMENSION)) memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), &length, sizeof(length)); if ((flags & FLAG_INHERIT) == false && value == LINE_HEIGHT_DIMENSION) memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + sizeof(length), &unit, sizeof(unit)); return CSS_OK; }
int main(int argc, char **argv) { css_stylesheet_params params; css_stylesheet *sheet; FILE *fp; size_t len, origlen; #define CHUNK_SIZE (4096) uint8_t buf[CHUNK_SIZE]; css_error error; int count; if (argc != 2) { printf("Usage: %s <filename>\n", argv[0]); return 1; } params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1; params.level = CSS_LEVEL_21; params.charset = "UTF-8"; params.url = argv[1]; params.title = NULL; params.allow_quirks = false; params.inline_style = false; params.resolve = resolve_url; params.resolve_pw = NULL; params.import = NULL; params.import_pw = NULL; params.color = NULL; params.color_pw = NULL; params.font = NULL; params.font_pw = NULL; for (count = 0; count < ITERATIONS; count++) { assert(css_stylesheet_create(¶ms, myrealloc, NULL, &sheet) == CSS_OK); fp = fopen(argv[1], "rb"); if (fp == NULL) { printf("Failed opening %s\n", argv[1]); return 1; } fseek(fp, 0, SEEK_END); origlen = len = ftell(fp); fseek(fp, 0, SEEK_SET); while (len >= CHUNK_SIZE) { size_t read = fread(buf, 1, CHUNK_SIZE, fp); assert(read == CHUNK_SIZE); error = css_stylesheet_append_data(sheet, buf, CHUNK_SIZE); assert(error == CSS_OK || error == CSS_NEEDDATA); len -= CHUNK_SIZE; } if (len > 0) { size_t read = fread(buf, 1, len, fp); assert(read == len); error = css_stylesheet_append_data(sheet, buf, len); assert(error == CSS_OK || error == CSS_NEEDDATA); len = 0; } fclose(fp); error = css_stylesheet_data_done(sheet); assert(error == CSS_OK || error == CSS_IMPORTS_PENDING); while (error == CSS_IMPORTS_PENDING) { lwc_string *url; uint64_t media; error = css_stylesheet_next_pending_import(sheet, &url, &media); assert(error == CSS_OK || error == CSS_INVALID); if (error == CSS_OK) { css_stylesheet *import; char *buf = alloca(lwc_string_length(url) + 1); memcpy(buf, lwc_string_data(url), lwc_string_length(url)); buf[lwc_string_length(url)] = '\0'; params.url = buf; assert(css_stylesheet_create(¶ms, myrealloc, NULL, &import) == CSS_OK); assert(css_stylesheet_data_done(import) == CSS_OK); assert(css_stylesheet_register_import(sheet, import) == CSS_OK); css_stylesheet_destroy(import); error = CSS_IMPORTS_PENDING; } } #if DUMP_CSS { #ifndef max #define max(a,b) ((a) > (b) ? (a) : (b)) #endif char *out; size_t outsize = max(16384, origlen * 8); size_t outlen = outsize; size_t written; out = malloc(outsize); assert(out != NULL); dump_sheet(sheet, out, &outlen); written = fwrite(out, 1, outsize - outlen, stdout); assert(written == outsize - outlen); free(out); } #endif css_stylesheet_destroy(sheet); } printf("PASS\n"); return 0; }
/** * Parse a unit specifier * * \param c Parsing context * \param vector Vector of tokens to process * \param ctx Pointer to current vector iteration context * \param default_unit The default unit to use if none specified * \param length Pointer to location to receive length * \param unit Pointer to location to receive unit * \return CSS_OK on success, * CSS_INVALID if the tokens do not form a valid unit * * Post condition: \a *ctx is updated with the next token to process * If the input is invalid, then \a *ctx remains unchanged. */ css_error css__parse_unit_specifier(css_language *c, const parserutils_vector *vector, int *ctx, uint32_t default_unit, css_fixed *length, uint32_t *unit) { int orig_ctx = *ctx; const css_token *token; css_fixed num; size_t consumed = 0; css_error error; consumeWhitespace(vector, ctx); token = parserutils_vector_iterate(vector, ctx); if (token == NULL || (token->type != CSS_TOKEN_DIMENSION && token->type != CSS_TOKEN_NUMBER && token->type != CSS_TOKEN_PERCENTAGE)) { *ctx = orig_ctx; return CSS_INVALID; } num = css__number_from_lwc_string(token->idata, false, &consumed); if (token->type == CSS_TOKEN_DIMENSION) { size_t len = lwc_string_length(token->idata); const char *data = lwc_string_data(token->idata); css_unit temp_unit = CSS_UNIT_PX; error = css__parse_unit_keyword(data + consumed, len - consumed, &temp_unit); if (error != CSS_OK) { *ctx = orig_ctx; return error; } *unit = (uint32_t) temp_unit; } else if (token->type == CSS_TOKEN_NUMBER) { /* Non-zero values are permitted in quirks mode */ if (num != 0) { if (c->sheet->quirks_allowed) { c->sheet->quirks_used = true; } else { *ctx = orig_ctx; return CSS_INVALID; } } *unit = default_unit; if (c->sheet->quirks_allowed) { /* Also, in quirks mode, we need to cater for * dimensions separated from their units by whitespace * (e.g. "0 px") */ int temp_ctx = *ctx; css_unit temp_unit; consumeWhitespace(vector, &temp_ctx); /* Try to parse the unit keyword, ignoring errors */ token = parserutils_vector_iterate(vector, &temp_ctx); if (token != NULL && token->type == CSS_TOKEN_IDENT) { error = css__parse_unit_keyword( lwc_string_data(token->idata), lwc_string_length(token->idata), &temp_unit); if (error == CSS_OK) { c->sheet->quirks_used = true; *ctx = temp_ctx; *unit = (uint32_t) temp_unit; } } } } else { /* Percentage -- number must be entire token data */ if (consumed != lwc_string_length(token->idata)) { *ctx = orig_ctx; return CSS_INVALID; } *unit = UNIT_PCT; } *length = num; return CSS_OK; }
void nsbeos_gui_view_source(struct hlcache_handle *content) { char *temp_name; bool done = false; BPath path; status_t err; size_t size; const char *source = content_get_source_data(content, &size); if (!content || !source) { warn_user("MiscError", "No document source"); return; } /* try to load local files directly. */ temp_name = url_to_path(nsurl_access(hlcache_handle_get_url(content))); if (temp_name) { path.SetTo(temp_name); BEntry entry; if (entry.SetTo(path.Path()) >= B_OK && entry.Exists() && entry.IsFile()) done = true; } if (!done) { /* We cannot release the requested filename until after it * has finished being used. As we can't easily find out when * this is, we simply don't bother releasing it and simply * allow it to be re-used next time NetSurf is started. The * memory overhead from doing this is under 1 byte per * filename. */ const char *filename = filename_request(); if (!filename) { warn_user("NoMemory", 0); return; } path.SetTo(TEMP_FILENAME_PREFIX); path.Append(filename); BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE); err = file.InitCheck(); if (err < B_OK) { warn_user("IOError", strerror(err)); return; } err = file.Write(source, size); if (err < B_OK) { warn_user("IOError", strerror(err)); return; } lwc_string *mime = content_get_mime_type(content); if (mime) { file.WriteAttr("BEOS:TYPE", B_MIME_STRING_TYPE, 0LL, lwc_string_data(mime), lwc_string_length(mime) + 1); lwc_string_unref(mime); } } entry_ref ref; if (get_ref_for_path(path.Path(), &ref) < B_OK) return; BMessage m(B_REFS_RECEIVED); m.AddRef("refs", &ref); // apps to try const char *editorSigs[] = { "application/x-vnd.beunited.pe", "application/x-vnd.XEmacs", "application/x-vnd.Haiku-StyledEdit", "application/x-vnd.Be-STEE", "application/x-vnd.yT-STEE", NULL }; int i; for (i = 0; editorSigs[i]; i++) { team_id team = -1; { BMessenger msgr(editorSigs[i], team); if (msgr.SendMessage(&m) >= B_OK) break; } err = be_roster->Launch(editorSigs[i], (BMessage *)&m, &team); if (err >= B_OK) break; } }
/** * Parse a colour specifier * * \param c Parsing context * \param vector Vector of tokens to process * \param ctx Pointer to vector iteration context * \param value Pointer to location to receive value * \param result Pointer to location to receive result (AARRGGBB) * \return CSS_OK on success, * CSS_INVALID if the input is invalid * * Post condition: \a *ctx is updated with the next token to process * If the input is invalid, then \a *ctx remains unchanged. */ css_error css__parse_colour_specifier(css_language *c, const parserutils_vector *vector, int *ctx, uint16_t *value, uint32_t *result) { int orig_ctx = *ctx; const css_token *token; bool match; css_error error; consumeWhitespace(vector, ctx); /* IDENT(<colour name>) | * HASH(rgb | rrggbb) | * FUNCTION(rgb) [ [ NUMBER | PERCENTAGE ] ',' ] {3} ')' * FUNCTION(rgba) [ [ NUMBER | PERCENTAGE ] ',' ] {4} ')' * FUNCTION(hsl) ANGLE ',' PERCENTAGE ',' PERCENTAGE ')' * FUNCTION(hsla) ANGLE ',' PERCENTAGE ',' PERCENTAGE ',' NUMBER ')' * * For quirks, NUMBER | DIMENSION | IDENT, too * I.E. "123456" -> NUMBER, "1234f0" -> DIMENSION, "f00000" -> IDENT */ token = parserutils_vector_iterate(vector, ctx); if (token == NULL || (token->type != CSS_TOKEN_IDENT && token->type != CSS_TOKEN_HASH && token->type != CSS_TOKEN_FUNCTION)) { if (c->sheet->quirks_allowed == false || token == NULL || (token->type != CSS_TOKEN_NUMBER && token->type != CSS_TOKEN_DIMENSION)) goto invalid; } if (token->type == CSS_TOKEN_IDENT) { if ((lwc_string_caseless_isequal( token->idata, c->strings[TRANSPARENT], &match) == lwc_error_ok && match)) { *value = COLOR_TRANSPARENT; *result = 0; /* black transparent */ return CSS_OK; } else if ((lwc_string_caseless_isequal( token->idata, c->strings[CURRENTCOLOR], &match) == lwc_error_ok && match)) { *value = COLOR_CURRENT_COLOR; *result = 0; return CSS_OK; } error = css__parse_named_colour(c, token->idata, result); if (error != CSS_OK && c->sheet->quirks_allowed) { error = css__parse_hash_colour(token->idata, result); if (error == CSS_OK) c->sheet->quirks_used = true; } if (error != CSS_OK) goto invalid; } else if (token->type == CSS_TOKEN_HASH) { error = css__parse_hash_colour(token->idata, result); if (error != CSS_OK) goto invalid; } else if (c->sheet->quirks_allowed && token->type == CSS_TOKEN_NUMBER) { error = css__parse_hash_colour(token->idata, result); if (error == CSS_OK) c->sheet->quirks_used = true; else goto invalid; } else if (c->sheet->quirks_allowed && token->type == CSS_TOKEN_DIMENSION) { error = css__parse_hash_colour(token->idata, result); if (error == CSS_OK) c->sheet->quirks_used = true; else goto invalid; } else if (token->type == CSS_TOKEN_FUNCTION) { uint8_t r = 0, g = 0, b = 0, a = 0xff; int colour_channels = 0; if ((lwc_string_caseless_isequal( token->idata, c->strings[RGB], &match) == lwc_error_ok && match)) { colour_channels = 3; } else if ((lwc_string_caseless_isequal( token->idata, c->strings[RGBA], &match) == lwc_error_ok && match)) { colour_channels = 4; } if ((lwc_string_caseless_isequal( token->idata, c->strings[HSL], &match) == lwc_error_ok && match)) { colour_channels = 5; } else if ((lwc_string_caseless_isequal( token->idata, c->strings[HSLA], &match) == lwc_error_ok && match)) { colour_channels = 6; } if (colour_channels == 3 || colour_channels == 4) { int i; css_token_type valid = CSS_TOKEN_NUMBER; uint8_t *components[4] = { &r, &g, &b, &a }; for (i = 0; i < colour_channels; i++) { uint8_t *component; css_fixed num; size_t consumed = 0; int32_t intval; bool int_only; component = components[i]; consumeWhitespace(vector, ctx); token = parserutils_vector_peek(vector, *ctx); if (token == NULL || (token->type != CSS_TOKEN_NUMBER && token->type != CSS_TOKEN_PERCENTAGE)) goto invalid; if (i == 0) valid = token->type; else if (i < 3 && token->type != valid) goto invalid; /* The alpha channel may be a float */ if (i < 3) int_only = (valid == CSS_TOKEN_NUMBER); else int_only = false; num = css__number_from_lwc_string(token->idata, int_only, &consumed); if (consumed != lwc_string_length(token->idata)) goto invalid; if (valid == CSS_TOKEN_NUMBER) { if (i == 3) { /* alpha channel */ intval = FIXTOINT( FMUL(num, F_255)); } else { /* colour channels */ intval = FIXTOINT(num); } } else { intval = FIXTOINT( FDIV(FMUL(num, F_255), F_100)); } if (intval > 255) *component = 255; else if (intval < 0) *component = 0; else *component = intval; parserutils_vector_iterate(vector, ctx); consumeWhitespace(vector, ctx); token = parserutils_vector_peek(vector, *ctx); if (token == NULL) goto invalid; if (i != (colour_channels - 1) && tokenIsChar(token, ',')) { parserutils_vector_iterate(vector, ctx); } else if (i == (colour_channels - 1) && tokenIsChar(token, ')')) { parserutils_vector_iterate(vector, ctx); } else { goto invalid; } } } else if (colour_channels == 5 || colour_channels == 6) { /* hue - saturation - lightness */ size_t consumed = 0; css_fixed hue, sat, lit; int32_t alpha = 255; /* hue is a number without a unit representing an * angle (0-360) degrees */ consumeWhitespace(vector, ctx); token = parserutils_vector_iterate(vector, ctx); if ((token == NULL) || (token->type != CSS_TOKEN_NUMBER)) goto invalid; hue = css__number_from_lwc_string(token->idata, false, &consumed); if (consumed != lwc_string_length(token->idata)) goto invalid; /* failed to consume the whole string as a number */ /* Normalise hue to the range [0, 360) */ while (hue < 0) hue += F_360; while (hue >= F_360) hue -= F_360; consumeWhitespace(vector, ctx); token = parserutils_vector_iterate(vector, ctx); if (!tokenIsChar(token, ',')) goto invalid; /* saturation */ consumeWhitespace(vector, ctx); token = parserutils_vector_iterate(vector, ctx); if ((token == NULL) || (token->type != CSS_TOKEN_PERCENTAGE)) goto invalid; sat = css__number_from_lwc_string(token->idata, false, &consumed); if (consumed != lwc_string_length(token->idata)) goto invalid; /* failed to consume the whole string as a number */ /* Normalise saturation to the range [0, 100] */ if (sat < INTTOFIX(0)) sat = INTTOFIX(0); else if (sat > INTTOFIX(100)) sat = INTTOFIX(100); consumeWhitespace(vector, ctx); token = parserutils_vector_iterate(vector, ctx); if (!tokenIsChar(token, ',')) goto invalid; /* lightness */ consumeWhitespace(vector, ctx); token = parserutils_vector_iterate(vector, ctx); if ((token == NULL) || (token->type != CSS_TOKEN_PERCENTAGE)) goto invalid; lit = css__number_from_lwc_string(token->idata, false, &consumed); if (consumed != lwc_string_length(token->idata)) goto invalid; /* failed to consume the whole string as a number */ /* Normalise lightness to the range [0, 100] */ if (lit < INTTOFIX(0)) lit = INTTOFIX(0); else if (lit > INTTOFIX(100)) lit = INTTOFIX(100); consumeWhitespace(vector, ctx); token = parserutils_vector_iterate(vector, ctx); if (colour_channels == 6) { /* alpha */ if (!tokenIsChar(token, ',')) goto invalid; consumeWhitespace(vector, ctx); token = parserutils_vector_iterate(vector, ctx); if ((token == NULL) || (token->type != CSS_TOKEN_NUMBER)) goto invalid; alpha = css__number_from_lwc_string(token->idata, false, &consumed); if (consumed != lwc_string_length(token->idata)) goto invalid; /* failed to consume the whole string as a number */ alpha = FIXTOINT(FMUL(alpha, F_255)); consumeWhitespace(vector, ctx); token = parserutils_vector_iterate(vector, ctx); } if (!tokenIsChar(token, ')')) goto invalid; /* have a valid HSV entry, convert to RGB */ HSL_to_RGB(hue, sat, lit, &r, &g, &b); /* apply alpha */ if (alpha > 255) a = 255; else if (alpha < 0) a = 0; else a = alpha; } else { goto invalid; } *result = (a << 24) | (r << 16) | (g << 8) | b; } *value = COLOR_SET; return CSS_OK; invalid: *ctx = orig_ctx; return CSS_INVALID; }
/** * Create a string from a list of IDENT/S tokens * * \param c Parsing context * \param vector Vector containing tokens * \param ctx Vector iteration context * \param reserved Callback to determine if an identifier is reserved * \param result Pointer to location to receive resulting string * \return CSS_OK on success, appropriate error otherwise. * * Post condition: \a *ctx is updated with the next token to process * If the input is invalid, then \a *ctx remains unchanged. * * The resulting string's reference is passed to the caller */ css_error css__ident_list_to_string(css_language *c, const parserutils_vector *vector, int *ctx, bool (*reserved)(css_language *c, const css_token *ident), lwc_string **result) { int orig_ctx = *ctx; const css_token *token; css_error error = CSS_OK; parserutils_buffer *buffer; parserutils_error perror; lwc_string *interned; lwc_error lerror; perror = parserutils_buffer_create((parserutils_alloc) c->alloc, c->pw, &buffer); if (perror != PARSERUTILS_OK) return css_error_from_parserutils_error(perror); /* We know this token exists, and is an IDENT */ token = parserutils_vector_iterate(vector, ctx); /* Consume all subsequent IDENT or S tokens */ while (token != NULL && (token->type == CSS_TOKEN_IDENT || token->type == CSS_TOKEN_S)) { if (token->type == CSS_TOKEN_IDENT) { /* IDENT -- if reserved, reject style */ if (reserved != NULL && reserved(c, token)) { error = CSS_INVALID; goto cleanup; } perror = parserutils_buffer_append(buffer, (const uint8_t *) lwc_string_data(token->idata), lwc_string_length(token->idata)); } else { /* S */ perror = parserutils_buffer_append(buffer, (const uint8_t *) " ", 1); } if (perror != PARSERUTILS_OK) { error = css_error_from_parserutils_error(perror); goto cleanup; } token = parserutils_vector_iterate(vector, ctx); } /* Rewind context by one step if we consumed an unacceptable token */ if (token != NULL) *ctx = *ctx - 1; /* Strip trailing whitespace */ while (buffer->length > 0 && buffer->data[buffer->length - 1] == ' ') buffer->length--; /* Intern the buffer contents */ lerror = lwc_intern_string((char *) buffer->data, buffer->length, &interned); if (lerror != lwc_error_ok) { error = css_error_from_lwc_error(lerror); goto cleanup; } *result = interned; cleanup: parserutils_buffer_destroy(buffer); if (error != CSS_OK) *ctx = orig_ctx; return error; }
/* See mimesniff.h for documentation */ nserror mimesniff_compute_effective_type(llcache_handle *handle, const uint8_t *data, size_t len, bool sniff_allowed, bool image_only, lwc_string **effective_type) { #define S(s) { s, SLEN(s) } static const struct tt_s { const char *data; size_t len; } text_types[] = { S("text/plain"), S("text/plain; charset=ISO-8859-1"), S("text/plain; charset=iso-8859-1"), S("text/plain; charset=UTF-8"), { NULL, 0 } }; #undef S const char *content_type_header; size_t content_type_header_len; http_content_type *ct; const struct tt_s *tt; bool match; nserror error; content_type_header = llcache_handle_get_header(handle, "Content-Type"); if (content_type_header == NULL) { if (sniff_allowed == false) return NSERROR_NOT_FOUND; /* No official type => unknown */ return mimesniff__compute_unknown(data, len, effective_type); } error = http_parse_content_type(content_type_header, &ct); if (error != NSERROR_OK) { if (sniff_allowed == false) return NSERROR_NOT_FOUND; /* Unparseable => unknown */ return mimesniff__compute_unknown(data, len, effective_type); } if (sniff_allowed == false) { *effective_type = lwc_string_ref(ct->media_type); http_content_type_destroy(ct); return NSERROR_OK; } if (image_only) { lwc_string *official_type; if (lwc_string_caseless_isequal(ct->media_type, image_svg, &match) == lwc_error_ok && match) { *effective_type = lwc_string_ref(image_svg); http_content_type_destroy(ct); return NSERROR_OK; } official_type = lwc_string_ref(ct->media_type); http_content_type_destroy(ct); return mimesniff__compute_image(official_type, data, len, effective_type); } content_type_header_len = strlen(content_type_header); /* Look for text types */ for (tt = text_types; tt->data != NULL; tt++) { if (tt->len == content_type_header_len && memcmp(tt->data, content_type_header, content_type_header_len) == 0) { http_content_type_destroy(ct); return mimesniff__compute_text_or_binary(data, len, effective_type); } } /* unknown/unknown, application/unknown, * / * */ if ((lwc_string_caseless_isequal(ct->media_type, unknown_unknown, &match) == lwc_error_ok && match) || (lwc_string_caseless_isequal(ct->media_type, application_unknown, &match) == lwc_error_ok && match) || (lwc_string_caseless_isequal(ct->media_type, any, &match) == lwc_error_ok && match)) { http_content_type_destroy(ct); return mimesniff__compute_unknown(data, len, effective_type); } /* +xml */ if (lwc_string_length(ct->media_type) > SLEN("+xml") && strncasecmp(lwc_string_data(ct->media_type) + lwc_string_length(ct->media_type) - SLEN("+xml"), "+xml", SLEN("+xml")) == 0) { /* Use official type */ *effective_type = lwc_string_ref(ct->media_type); http_content_type_destroy(ct); return NSERROR_OK; } /* text/xml, application/xml */ if ((lwc_string_caseless_isequal(ct->media_type, text_xml, &match) == lwc_error_ok && match) || (lwc_string_caseless_isequal(ct->media_type, application_xml, &match) == lwc_error_ok && match)) { /* Use official type */ *effective_type = lwc_string_ref(ct->media_type); http_content_type_destroy(ct); return NSERROR_OK; } /* Image types */ if (content_factory_type_from_mime_type(ct->media_type) == CONTENT_IMAGE) { lwc_string *official_type = lwc_string_ref(ct->media_type); http_content_type_destroy(ct); return mimesniff__compute_image(official_type, data, len, effective_type); } /* text/html */ if ((lwc_string_caseless_isequal(ct->media_type, text_html, &match) == lwc_error_ok && match)) { http_content_type_destroy(ct); return mimesniff__compute_feed_or_html(data, len, effective_type); } /* Use official type */ *effective_type = lwc_string_ref(ct->media_type); http_content_type_destroy(ct); return NSERROR_OK; }