iconv: Bail out of the loop when an illegal sequence of bytes occurs.
[elinks/elinks-j605.git] / src / document / css / value.c
blob3d96285e54b5c319e24229a48cd674a71b8d4745
1 /** CSS property value parser
2 * @file */
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
8 #include <stdlib.h>
9 #include <string.h>
11 #include "elinks.h"
13 #include "document/css/property.h"
14 #include "document/css/scanner.h"
15 #include "document/css/value.h"
16 #include "util/color.h"
17 #include "util/error.h"
18 #include "util/memory.h"
19 #include "util/string.h"
22 int
23 css_parse_color_value(struct css_property_info *propinfo,
24 union css_property_value *value,
25 struct scanner *scanner)
27 struct scanner_token *token = get_scanner_token(scanner);
29 assert(propinfo->value_type == CSS_VT_COLOR);
31 if (token->type == CSS_TOKEN_RGB) {
32 /* RGB function */
33 int shift;
35 token = get_next_scanner_token(scanner);
37 /* First color component is shifted 16, next is shifted 8 and
38 * last is not shifted. */
39 for (shift = 16; token && shift >= 0; shift -= 8) {
40 /* The first two args are terminated by ',' and the
41 * last one by ')'. */
42 unsigned char paskynator = shift ? ',' : ')';
43 const unsigned char *nstring = token->string;
44 int part;
46 /* Are the current and next token valid? */
47 if ((token->type != CSS_TOKEN_NUMBER
48 && token->type != CSS_TOKEN_PERCENTAGE)
49 || !check_next_scanner_token(scanner, paskynator))
50 return 0;
52 /* Parse the digit */
53 part = strtol(token->string, (char **) &nstring, 10);
54 if (token->string == nstring)
55 return 0;
57 /* Adjust percentage values */
58 if (token->type == CSS_TOKEN_PERCENTAGE) {
59 int_bounds(&part, 0, 100);
60 part *= 255;
61 part /= 100;
64 /* Adjust color component value and add it */
65 int_bounds(&part, 0, 255);
66 value->color |= part << shift;
68 /* Paskynate the token arg and separator */
69 token = skip_css_tokens(scanner, paskynator);
72 return 1;
75 /* Just a color value we already know how to parse. */
76 if (token->type != CSS_TOKEN_IDENT
77 && token->type != CSS_TOKEN_HEX_COLOR)
78 return 0;
80 if (decode_color(token->string, token->length, &value->color) < 0) {
81 return 0;
84 skip_css_tokens(scanner, token->type);
85 return 1;
88 int
89 css_parse_background_value(struct css_property_info *propinfo,
90 union css_property_value *value,
91 struct scanner *scanner)
93 int success = 0;
95 assert(propinfo->value_type == CSS_VT_COLOR);
97 /* This is pretty naive, we just jump space by space, trying to parse
98 * each token as a color. */
100 while (scanner_has_tokens(scanner)) {
101 struct scanner_token *token = get_scanner_token(scanner);
103 if (!check_css_precedence(token->type, ';'))
104 break;
106 if (token->type == ','
107 || !css_parse_color_value(propinfo, value, scanner)) {
108 skip_scanner_token(scanner);
109 continue;
112 success++;
115 return success;
120 css_parse_font_style_value(struct css_property_info *propinfo,
121 union css_property_value *value,
122 struct scanner *scanner)
124 struct scanner_token *token = get_scanner_token(scanner);
126 assert(propinfo->value_type == CSS_VT_FONT_ATTRIBUTE);
128 if (token->type != CSS_TOKEN_IDENT) return 0;
130 if (scanner_token_contains(token, "italic")
131 || scanner_token_contains(token, "oblique")) {
132 value->font_attribute.add |= AT_ITALIC;
134 } else if (scanner_token_contains(token, "underline")) {
135 value->font_attribute.add |= AT_UNDERLINE;
137 } else if (scanner_token_contains(token, "normal")) {
138 value->font_attribute.rem |= AT_ITALIC;
140 } else {
141 return 0;
144 skip_css_tokens(scanner, CSS_TOKEN_IDENT);
145 return 1;
150 css_parse_font_weight_value(struct css_property_info *propinfo,
151 union css_property_value *value,
152 struct scanner *scanner)
154 struct scanner_token *token = get_scanner_token(scanner);
155 unsigned char *nstring;
156 int weight;
158 assert(propinfo->value_type == CSS_VT_FONT_ATTRIBUTE);
160 if (token->type == CSS_TOKEN_IDENT) {
161 if (scanner_token_contains(token, "bolder")) {
162 value->font_attribute.add |= AT_BOLD;
164 } else if (scanner_token_contains(token, "lighter")) {
165 value->font_attribute.rem |= AT_BOLD;
167 } else if (scanner_token_contains(token, "bold")) {
168 value->font_attribute.add |= AT_BOLD;
170 } else if (scanner_token_contains(token, "normal")) {
171 value->font_attribute.rem |= AT_BOLD;
173 } else {
174 return 0;
177 skip_css_tokens(scanner, CSS_TOKEN_IDENT);
178 return 1;
181 if (token->type != CSS_TOKEN_NUMBER) return 0;
183 /* TODO: Comma separated list of weights?! */
184 weight = strtol(token->string, (char **) &nstring, 10);
185 if (token->string == nstring) return 0;
187 skip_css_tokens(scanner, CSS_TOKEN_NUMBER);
188 /* The font weight(s) have values between 100 to 900. These
189 * values form an ordered sequence, where each number indicates
190 * a weight that is at least as dark as its predecessor.
192 * normal -> Same as '400'. bold Same as '700'.
194 int_bounds(&weight, 100, 900);
195 if (weight >= 700) value->font_attribute.add |= AT_BOLD;
196 return 1;
201 css_parse_list_style_value(struct css_property_info *propinfo,
202 union css_property_value *value,
203 struct scanner *scanner)
205 struct scanner_token *token = get_scanner_token(scanner);
207 assert(propinfo->value_type == CSS_VT_LIST_STYLE);
209 if (token->type != CSS_TOKEN_IDENT) return 0;
211 if (scanner_token_contains(token, "none")) {
212 value->list_style = CSS_LIST_NONE;
214 } else if (scanner_token_contains(token, "disc")) {
215 value->list_style = CSS_LIST_DISC;
217 } else if (scanner_token_contains(token, "circle")) {
218 value->list_style = CSS_LIST_CIRCLE;
220 } else if (scanner_token_contains(token, "square")) {
221 value->list_style = CSS_LIST_SQUARE;
223 } else if (scanner_token_contains(token, "decimal")) {
224 value->list_style = CSS_LIST_DECIMAL;
226 } else if (scanner_token_contains(token, "decimal-leading-zero")) {
227 value->list_style = CSS_LIST_DECIMAL_LEADING_ZERO;
229 } else if (scanner_token_contains(token, "lower-roman")) {
230 value->list_style = CSS_LIST_LOWER_ROMAN;
232 } else if (scanner_token_contains(token, "upper-roman")) {
233 value->list_style = CSS_LIST_UPPER_ROMAN;
235 } else if (scanner_token_contains(token, "lower-alpha")) {
236 value->list_style = CSS_LIST_LOWER_ALPHA;
238 } else if (scanner_token_contains(token, "upper-alpha")) {
239 value->list_style = CSS_LIST_UPPER_ALPHA;
241 } else if (scanner_token_contains(token, "lower-greek")) {
242 value->list_style = CSS_LIST_LOWER_GREEK;
244 } else if (scanner_token_contains(token, "lower-latin")) {
245 value->list_style = CSS_LIST_LOWER_LATIN;
247 } else if (scanner_token_contains(token, "upper-latin")) {
248 value->list_style = CSS_LIST_UPPER_LATIN;
250 } else if (scanner_token_contains(token, "hebrew")) {
251 value->list_style = CSS_LIST_HEBREW;
253 } else if (scanner_token_contains(token, "armenian")) {
254 value->list_style = CSS_LIST_ARMENIAN;
256 } else if (scanner_token_contains(token, "georgian")) {
257 value->list_style = CSS_LIST_GEORGIAN;
259 } else if (scanner_token_contains(token, "cjk-ideographic")) {
260 value->list_style = CSS_LIST_CJK_IDEOGRAPHIC;
262 } else if (scanner_token_contains(token, "hiragana")) {
263 value->list_style = CSS_LIST_HIRAGANA;
265 } else if (scanner_token_contains(token, "katakana")) {
266 value->list_style = CSS_LIST_KATAKANA;
268 } else if (scanner_token_contains(token, "hiragana-iroha")) {
269 value->list_style = CSS_LIST_HIRAGANA_IROHA;
271 } else if (scanner_token_contains(token, "katakana-iroha")) {
272 value->list_style = CSS_LIST_KATAKANA_IROHA;
274 } else {
275 return 0;
278 skip_css_tokens(scanner, CSS_TOKEN_IDENT);
279 return 1;
283 css_parse_text_align_value(struct css_property_info *propinfo,
284 union css_property_value *value,
285 struct scanner *scanner)
287 struct scanner_token *token = get_scanner_token(scanner);
289 assert(propinfo->value_type == CSS_VT_TEXT_ALIGN);
291 if (token->type != CSS_TOKEN_IDENT) return 0;
293 if (scanner_token_contains(token, "left")) {
294 value->text_align = ALIGN_LEFT;
296 } else if (scanner_token_contains(token, "right")) {
297 value->text_align = ALIGN_RIGHT;
299 } else if (scanner_token_contains(token, "center")) {
300 value->text_align = ALIGN_CENTER;
302 } else if (scanner_token_contains(token, "justify")) {
303 value->text_align = ALIGN_JUSTIFY;
305 } else {
306 return 0;
309 skip_css_tokens(scanner, CSS_TOKEN_IDENT);
310 return 1;
315 css_parse_text_decoration_value(struct css_property_info *propinfo,
316 union css_property_value *value,
317 struct scanner *scanner)
319 struct scanner_token *token = get_scanner_token(scanner);
321 assert(propinfo->value_type == CSS_VT_FONT_ATTRIBUTE);
323 if (token->type != CSS_TOKEN_IDENT) return 0;
325 /* TODO: It is possible to have multiple values here,
326 * 'background'-style. --pasky */
327 if (scanner_token_contains(token, "underline")) {
328 value->font_attribute.add |= AT_UNDERLINE;
330 } else if (scanner_token_contains(token, "none")) {
331 value->font_attribute.rem |= AT_UNDERLINE;
333 } else {
334 return 0;
337 skip_css_tokens(scanner, CSS_TOKEN_IDENT);
338 return 1;
342 css_parse_white_space_value(struct css_property_info *propinfo,
343 union css_property_value *value,
344 struct scanner *scanner)
346 struct scanner_token *token = get_scanner_token(scanner);
348 assert(propinfo->value_type == CSS_VT_FONT_ATTRIBUTE);
350 if (token->type != CSS_TOKEN_IDENT) return 0;
352 /* FIXME: nowrap */
353 if (scanner_token_contains(token, "pre")) {
354 value->font_attribute.add |= AT_PREFORMATTED;
356 } else if (scanner_token_contains(token, "normal")) {
357 value->font_attribute.rem |= AT_PREFORMATTED;
359 } else {
360 return 0;
363 skip_css_tokens(scanner, CSS_TOKEN_IDENT);
364 return 1;
368 css_parse_display_value(struct css_property_info *propinfo,
369 union css_property_value *value,
370 struct scanner *scanner)
372 struct scanner_token *token = get_scanner_token(scanner);
374 assert(propinfo->value_type == CSS_VT_DISPLAY);
376 if (token->type != CSS_TOKEN_IDENT) return 0;
378 /* FIXME: This is _very_ simplistic */
379 if (scanner_token_contains(token, "inline")) {
380 value->display = CSS_DISP_INLINE;
381 } else if (scanner_token_contains(token, "inline-block")) {
382 value->display = CSS_DISP_INLINE; /* XXX */
383 } else if (scanner_token_contains(token, "block")) {
384 value->display = CSS_DISP_BLOCK;
385 } else if (scanner_token_contains(token, "none")) {
386 value->display = CSS_DISP_NONE;
387 } else {
388 return 0;
391 skip_css_tokens(scanner, CSS_TOKEN_IDENT);
392 return 1;
397 css_parse_value(struct css_property_info *propinfo,
398 union css_property_value *value,
399 struct scanner *scanner)
401 struct scanner_token *token;
403 assert(scanner && value && propinfo);
404 assert(propinfo->parser);
406 /* Check that we actually have some token to pass on */
407 token = get_scanner_token(scanner);
408 if (!token) return 0;
410 return propinfo->parser(propinfo, value, scanner);