1 /* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
2
3 /*
4 * This file is part of The Croco Library
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2.1 of the GNU Lesser General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18 * USA
19 *
20 * Author: Dodji Seketeli
21 * See the COPYRIGHTS file for copyrights information.
22 */
23
24 /**
25 *@file
26 *The definition of the #CRTknzr (tokenizer)
27 *class.
28 */
29
30 #include "string.h"
31 #include "cr-tknzr.h"
32 #include "cr-doc-handler.h"
33
34 struct _CRTknzrPriv {
35 /**The parser input stream of bytes*/
36 CRInput *input;
37
38 /**
39 *A cache where tknzr_unget_token()
40 *puts back the token. tknzr_get_next_token()
41 *first look in this cache, and if and
42 *only if it's empty, fetches the next token
43 *from the input stream.
44 */
45 CRToken *token_cache;
46
47 /**
48 *The position of the end of the previous token
49 *or char fetched.
50 */
51 CRInputPos prev_pos;
52
53 CRDocHandler *sac_handler;
54
55 /**
56 *The reference count of the current instance
57 *of #CRTknzr. Is manipulated by cr_tknzr_ref()
58 *and cr_tknzr_unref().
59 */
60 glong ref_count;
61 };
62
63 #define PRIVATE(obj) ((obj)->priv)
64
65 /**
66 *return TRUE if the character is a number ([0-9]), FALSE otherwise
67 *@param a_char the char to test.
68 */
69 #define IS_NUM(a_char) (((a_char) >= '0' && (a_char) <= '9')?TRUE:FALSE)
70
71 /**
72 *Checks if 'status' equals CR_OK. If not, goto the 'error' label.
73 *
74 *@param status the status (of type enum CRStatus) to test.
75 *@param is_exception if set to FALSE, the final status returned the
76 *current function will be CR_PARSING_ERROR. If set to TRUE, the
77 *current status will be the current value of the 'status' variable.
78 *
79 */
80 #define CHECK_PARSING_STATUS(status, is_exception) \
81 if ((status) != CR_OK) \
82 { \
83 if (is_exception == FALSE) \
84 { \
85 status = CR_PARSING_ERROR ; \
86 } \
87 goto error ; \
88 }
89
90 /**
91 *Peeks the next char from the input stream of the current tokenizer.
92 *invokes CHECK_PARSING_STATUS on the status returned by
93 *cr_tknzr_input_peek_char().
94 *
95 *@param the current instance of #CRTkzr.
96 *@param to_char a pointer to the char where to store the
97 *char peeked.
98 */
99 #define PEEK_NEXT_CHAR(a_tknzr, a_to_char) \
100 {\
101 status = cr_tknzr_peek_char (a_tknzr, a_to_char) ; \
102 CHECK_PARSING_STATUS (status, TRUE) \
103 }
104
105 /**
106 *Reads the next char from the input stream of the current parser.
107 *In case of error, jumps to the "error:" label located in the
108 *function where this macro is called.
109 *@param parser the curent instance of #CRTknzr
110 *@param to_char a pointer to the guint32 char where to store
111 *the character read.
112 */
113 #define READ_NEXT_CHAR(a_tknzr, to_char) \
114 status = cr_tknzr_read_char (a_tknzr, to_char) ;\
115 CHECK_PARSING_STATUS (status, TRUE)
116
117 /**
118 *Gets information about the current position in
119 *the input of the parser.
120 *In case of failure, this macro returns from the
121 *calling function and
122 *returns a status code of type enum #CRStatus.
123 *@param parser the current instance of #CRTknzr.
124 *@param pos out parameter. A pointer to the position
125 *inside the current parser input. Must
126 */
127 #define RECORD_INITIAL_POS(a_tknzr, a_pos) \
128 status = cr_input_get_cur_pos (PRIVATE \
129 (a_tknzr)->input, a_pos) ; \
130 g_return_val_if_fail (status == CR_OK, status)
131
132 /**
133 *Gets the address of the current byte inside the
134 *parser input.
135 *@param parser the current instance of #CRTknzr.
136 *@param addr out parameter a pointer (guchar*)
137 *to where the address must be put.
138 */
139 #define RECORD_CUR_BYTE_ADDR(a_tknzr, a_addr) \
140 status = cr_input_get_cur_byte_addr \
141 (PRIVATE (a_tknzr)->input, a_addr) ; \
142 CHECK_PARSING_STATUS (status, TRUE)
143
144 /**
145 *Peeks a byte from the topmost parser input at
146 *a given offset from the current position.
147 *If it fails, goto the "error:" label.
148 *
149 *@param a_parser the current instance of #CRTknzr.
150 *@param a_offset the offset of the byte to peek, the
151 *current byte having the offset '0'.
152 *@param a_byte_ptr out parameter a pointer (guchar*) to
153 *where the peeked char is to be stored.
154 */
155 #define PEEK_BYTE(a_tknzr, a_offset, a_byte_ptr) \
156 status = cr_tknzr_peek_byte (a_tknzr, \
157 a_offset, \
158 a_byte_ptr) ; \
159 CHECK_PARSING_STATUS (status, TRUE) ;
160
161 #define BYTE(a_input, a_n, a_eof) \
162 cr_input_peek_byte2 (a_input, a_n, a_eof)
163
164 /**
165 *Reads a byte from the topmost parser input
166 *steam.
167 *If it fails, goto the "error" label.
168 *@param a_parser the current instance of #CRTknzr.
169 *@param a_byte_ptr the guchar * where to put the read char.
170 */
171 #define READ_NEXT_BYTE(a_tknzr, a_byte_ptr) \
172 status = \
173 cr_input_read_byte (PRIVATE (a_tknzr)->input, a_byte_ptr) ;\
174 CHECK_PARSING_STATUS (status, TRUE) ;
175
176 /**
177 *Skips a given number of byte in the topmost
178 *parser input. Don't update line and column number.
179 *In case of error, jumps to the "error:" label
180 *of the surrounding function.
181 *@param a_parser the current instance of #CRTknzr.
182 *@param a_nb_bytes the number of bytes to skip.
183 */
184 #define SKIP_BYTES(a_tknzr, a_nb_bytes) \
185 status = cr_input_seek_index (PRIVATE (a_tknzr)->input, \
186 CR_SEEK_CUR, a_nb_bytes) ; \
187 CHECK_PARSING_STATUS (status, TRUE) ;
188
189 /**
190 *Skip utf8 encoded characters.
191 *Updates line and column numbers.
192 *@param a_parser the current instance of #CRTknzr.
193 *@param a_nb_chars the number of chars to skip. Must be of
194 *type glong.
195 */
196 #define SKIP_CHARS(a_tknzr, a_nb_chars) \
197 { \
198 gulong nb_chars = a_nb_chars ; \
199 status = cr_input_consume_chars \
200 (PRIVATE (a_tknzr)->input,0, &nb_chars) ; \
201 CHECK_PARSING_STATUS (status, TRUE) ; \
202 }
203
204 /**
205 *Tests the condition and if it is false, sets
206 *status to "CR_PARSING_ERROR" and goto the 'error'
207 *label.
208 *@param condition the condition to test.
209 */
210 #define ENSURE_PARSING_COND(condition) \
211 if (! (condition)) {status = CR_PARSING_ERROR; goto error ;}
212
213 static enum CRStatus cr_tknzr_parse_nl (CRTknzr * a_this,
214 guchar ** a_start,
215 guchar ** a_end,
216 CRParsingLocation *a_location);
217
218 static enum CRStatus cr_tknzr_parse_w (CRTknzr * a_this,
219 guchar ** a_start,
220 guchar ** a_end,
221 CRParsingLocation *a_location) ;
222
223 static enum CRStatus cr_tknzr_parse_unicode_escape (CRTknzr * a_this,
224 guint32 * a_unicode,
225 CRParsingLocation *a_location) ;
226
227 static enum CRStatus cr_tknzr_parse_escape (CRTknzr * a_this,
228 guint32 * a_esc_code,
229 CRParsingLocation *a_location);
230
231 static enum CRStatus cr_tknzr_parse_string (CRTknzr * a_this,
232 CRString ** a_str);
233
234 static enum CRStatus cr_tknzr_parse_comment (CRTknzr * a_this,
235 CRString ** a_comment);
236
237 static enum CRStatus cr_tknzr_parse_nmstart (CRTknzr * a_this,
238 guint32 * a_char,
239 CRParsingLocation *a_location);
240
241 static enum CRStatus cr_tknzr_parse_num (CRTknzr * a_this,
242 CRNum ** a_num);
243
244 /**********************************
245 *PRIVATE methods
246 **********************************/
247
248 /**
249 *Parses a "w" as defined by the css spec at [4.1.1]:
250 * w ::= [ \t\r\n\f]*
251 *
252 *@param a_this the current instance of #CRTknzr.
253 *@param a_start out param. Upon successfull completion, points
254 *to the beginning of the parsed white space, points to NULL otherwise.
255 *Can also point to NULL is there is no white space actually.
256 *@param a_end out param. Upon successfull completion, points
257 *to the end of the parsed white space, points to NULL otherwise.
258 *Can also point to NULL is there is no white space actually.
259 */
260 static enum CRStatus
cr_tknzr_parse_w(CRTknzr * a_this,guchar ** a_start,guchar ** a_end,CRParsingLocation * a_location)261 cr_tknzr_parse_w (CRTknzr * a_this,
262 guchar ** a_start,
263 guchar ** a_end,
264 CRParsingLocation *a_location)
265 {
266 guint32 cur_char = 0;
267 CRInputPos init_pos;
268 enum CRStatus status = CR_OK;
269
270 g_return_val_if_fail (a_this && PRIVATE (a_this)
271 && PRIVATE (a_this)->input
272 && a_start && a_end,
273 CR_BAD_PARAM_ERROR);
274
275 RECORD_INITIAL_POS (a_this, &init_pos);
276
277 *a_start = NULL;
278 *a_end = NULL;
279
280 READ_NEXT_CHAR (a_this, &cur_char);
281
282 if (cr_utils_is_white_space (cur_char) == FALSE) {
283 status = CR_PARSING_ERROR;
284 goto error;
285 }
286 if (a_location) {
287 cr_tknzr_get_parsing_location (a_this,
288 a_location) ;
289 }
290 RECORD_CUR_BYTE_ADDR (a_this, a_start);
291 *a_end = *a_start;
292
293 for (;;) {
294 gboolean is_eof = FALSE;
295
296 cr_input_get_end_of_file (PRIVATE (a_this)->input, &is_eof);
297 if (is_eof)
298 break;
299
300 status = cr_tknzr_peek_char (a_this, &cur_char);
301 if (status == CR_END_OF_INPUT_ERROR) {
302 break;
303 } else if (status != CR_OK) {
304 goto error;
305 }
306
307 if (cr_utils_is_white_space (cur_char) == TRUE) {
308 READ_NEXT_CHAR (a_this, &cur_char);
309 RECORD_CUR_BYTE_ADDR (a_this, a_end);
310 } else {
311 break;
312 }
313 }
314
315 return CR_OK;
316
317 error:
318 cr_tknzr_set_cur_pos (a_this, &init_pos);
319
320 return status;
321 }
322
323 /**
324 *Parses a newline as defined in the css2 spec:
325 * nl ::= \n|\r\n|\r|\f
326 *
327 *@param a_this the "this pointer" of the current instance of #CRTknzr.
328 *@param a_start a pointer to the first character of the successfully
329 *parsed string.
330 *@param a_end a pointer to the last character of the successfully parsed
331 *string.
332 *@result CR_OK uppon successfull completion, an error code otherwise.
333 */
334 static enum CRStatus
cr_tknzr_parse_nl(CRTknzr * a_this,guchar ** a_start,guchar ** a_end,CRParsingLocation * a_location)335 cr_tknzr_parse_nl (CRTknzr * a_this,
336 guchar ** a_start,
337 guchar ** a_end,
338 CRParsingLocation *a_location)
339 {
340 CRInputPos init_pos;
341 guchar next_chars[2] = { 0 };
342 enum CRStatus status = CR_PARSING_ERROR;
343
344 g_return_val_if_fail (a_this && PRIVATE (a_this)
345 && a_start && a_end, CR_BAD_PARAM_ERROR);
346
347 RECORD_INITIAL_POS (a_this, &init_pos);
348
349 PEEK_BYTE (a_this, 1, &next_chars[0]);
350 PEEK_BYTE (a_this, 2, &next_chars[1]);
351
352 if ((next_chars[0] == '\r' && next_chars[1] == '\n')) {
353 SKIP_BYTES (a_this, 1);
354 if (a_location) {
355 cr_tknzr_get_parsing_location
356 (a_this, a_location) ;
357 }
358 SKIP_CHARS (a_this, 1);
359
360 RECORD_CUR_BYTE_ADDR (a_this, a_end);
361
362 status = CR_OK;
363 } else if (next_chars[0] == '\n'
364 || next_chars[0] == '\r' || next_chars[0] == '\f') {
365 SKIP_CHARS (a_this, 1);
366 if (a_location) {
367 cr_tknzr_get_parsing_location
368 (a_this, a_location) ;
369 }
370 RECORD_CUR_BYTE_ADDR (a_this, a_start);
371 *a_end = *a_start;
372 status = CR_OK;
373 } else {
374 status = CR_PARSING_ERROR;
375 goto error;
376 }
377 return CR_OK ;
378
379 error:
380 cr_tknzr_set_cur_pos (a_this, &init_pos) ;
381 return status;
382 }
383
384 /**
385 *Go ahead in the parser input, skipping all the spaces.
386 *If the next char if not a white space, this function does nothing.
387 *In any cases, it stops when it encounters a non white space character.
388 *
389 *@param a_this the current instance of #CRTknzr.
390 *@return CR_OK upon successfull completion, an error code otherwise.
391 */
392 static enum CRStatus
cr_tknzr_try_to_skip_spaces(CRTknzr * a_this)393 cr_tknzr_try_to_skip_spaces (CRTknzr * a_this)
394 {
395 enum CRStatus status = CR_ERROR;
396 guint32 cur_char = 0;
397
398 g_return_val_if_fail (a_this && PRIVATE (a_this)
399 && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
400
401 status = cr_input_peek_char (PRIVATE (a_this)->input, &cur_char);
402
403 if (status != CR_OK) {
404 if (status == CR_END_OF_INPUT_ERROR)
405 return CR_OK;
406 return status;
407 }
408
409 if (cr_utils_is_white_space (cur_char) == TRUE) {
410 gulong nb_chars = -1; /*consume all spaces */
411
412 status = cr_input_consume_white_spaces
413 (PRIVATE (a_this)->input, &nb_chars);
414 }
415
416 return status;
417 }
418
419 /**
420 *Parses a "comment" as defined in the css spec at [4.1.1]:
421 *COMMENT ::= \/\*[^*]*\*+([^/][^*]*\*+)*\/ .
422 *This complex regexp is just to say that comments start
423 *with the two chars '/''*' and ends with the two chars '*''/'.
424 *It also means that comments cannot be nested.
425 *So based on that, I've just tried to implement the parsing function
426 *simply and in a straight forward manner.
427 */
428 static enum CRStatus
cr_tknzr_parse_comment(CRTknzr * a_this,CRString ** a_comment)429 cr_tknzr_parse_comment (CRTknzr * a_this,
430 CRString ** a_comment)
431 {
432 enum CRStatus status = CR_OK;
433 CRInputPos init_pos;
434 guint32 cur_char = 0, next_char= 0;
435 CRString *comment = NULL;
436 CRParsingLocation loc = {0} ;
437
438 g_return_val_if_fail (a_this && PRIVATE (a_this)
439 && PRIVATE (a_this)->input,
440 CR_BAD_PARAM_ERROR);
441
442 RECORD_INITIAL_POS (a_this, &init_pos);
443 READ_NEXT_CHAR (a_this, &cur_char) ;
444 ENSURE_PARSING_COND (cur_char == '/');
445 cr_tknzr_get_parsing_location (a_this, &loc) ;
446
447 READ_NEXT_CHAR (a_this, &cur_char);
448 ENSURE_PARSING_COND (cur_char == '*');
449 comment = cr_string_new ();
450 for (;;) { /* [^*]* */
451 PEEK_NEXT_CHAR (a_this, &next_char);
452 if (next_char == '*')
453 break;
454 READ_NEXT_CHAR (a_this, &cur_char);
455 g_string_append_unichar (comment->stryng, cur_char);
456 }
457 /* Stop condition: next_char == '*' */
458 for (;;) { /* \*+ */
459 READ_NEXT_CHAR(a_this, &cur_char);
460 ENSURE_PARSING_COND (cur_char == '*');
461 g_string_append_unichar (comment->stryng, cur_char);
462 PEEK_NEXT_CHAR (a_this, &next_char);
463 if (next_char != '*')
464 break;
465 }
466 /* Stop condition: next_char != '*' */
467 for (;;) { /* ([^/][^*]*\*+)* */
468 if (next_char == '/')
469 break;
470 READ_NEXT_CHAR(a_this, &cur_char);
471 g_string_append_unichar (comment->stryng, cur_char);
472 for (;;) { /* [^*]* */
473 PEEK_NEXT_CHAR (a_this, &next_char);
474 if (next_char == '*')
475 break;
476 READ_NEXT_CHAR (a_this, &cur_char);
477 g_string_append_unichar (comment->stryng, cur_char);
478 }
479 /* Stop condition: next_char = '*', no need to verify, because peek and read exit to error anyway */
480 for (;;) { /* \*+ */
481 READ_NEXT_CHAR(a_this, &cur_char);
482 ENSURE_PARSING_COND (cur_char == '*');
483 g_string_append_unichar (comment->stryng, cur_char);
484 PEEK_NEXT_CHAR (a_this, &next_char);
485 if (next_char != '*')
486 break;
487 }
488 /* Continue condition: next_char != '*' */
489 }
490 /* Stop condition: next_char == '\/' */
491 READ_NEXT_CHAR(a_this, &cur_char);
492 g_string_append_unichar (comment->stryng, cur_char);
493
494 if (status == CR_OK) {
495 cr_parsing_location_copy (&comment->location,
496 &loc) ;
497 *a_comment = comment;
498 return CR_OK;
499 }
500 error:
501
502 if (comment) {
503 cr_string_destroy (comment);
504 comment = NULL;
505 }
506
507 cr_tknzr_set_cur_pos (a_this, &init_pos);
508
509 return status;
510 }
511
512 /**
513 *Parses an 'unicode' escape sequence defined
514 *in css spec at chap 4.1.1:
515 *unicode ::= \\[0-9a-f]{1,6}[ \n\r\t\f]?
516 *@param a_this the current instance of #CRTknzr.
517 *@param a_start out parameter. A pointer to the start
518 *of the unicode escape sequence. Must *NOT* be deleted by
519 *the caller.
520 *@param a_end out parameter. A pointer to the last character
521 *of the unicode escape sequence. Must *NOT* be deleted by the caller.
522 *@return CR_OK if parsing succeded, an error code otherwise.
523 *Error code can be either CR_PARSING_ERROR if the string
524 *parsed just doesn't
525 *respect the production or another error if a
526 *lower level error occurred.
527 */
528 static enum CRStatus
cr_tknzr_parse_unicode_escape(CRTknzr * a_this,guint32 * a_unicode,CRParsingLocation * a_location)529 cr_tknzr_parse_unicode_escape (CRTknzr * a_this,
530 guint32 * a_unicode,
531 CRParsingLocation *a_location)
532 {
533 guint32 cur_char;
534 CRInputPos init_pos;
535 glong occur = 0;
536 guint32 unicode = 0;
537 guchar *tmp_char_ptr1 = NULL,
538 *tmp_char_ptr2 = NULL;
539 enum CRStatus status = CR_OK;
540
541 g_return_val_if_fail (a_this && PRIVATE (a_this)
542 && a_unicode, CR_BAD_PARAM_ERROR);
543
544 /*first, let's backup the current position pointer */
545 RECORD_INITIAL_POS (a_this, &init_pos);
546
547 READ_NEXT_CHAR (a_this, &cur_char);
548
549 if (cur_char != '\\') {
550 status = CR_PARSING_ERROR;
551 goto error;
552 }
553 if (a_location) {
554 cr_tknzr_get_parsing_location
555 (a_this, a_location) ;
556 }
557 PEEK_NEXT_CHAR (a_this, &cur_char);
558
559 for (occur = 0, unicode = 0; ((cur_char >= '0' && cur_char <= '9')
560 || (cur_char >= 'a' && cur_char <= 'f')
561 || (cur_char >= 'A' && cur_char <= 'F'))
562 && occur < 6; occur++) {
563 gint cur_char_val = 0;
564
565 READ_NEXT_CHAR (a_this, &cur_char);
566
567 if ((cur_char >= '0' && cur_char <= '9')) {
568 cur_char_val = (cur_char - '0');
569 } else if ((cur_char >= 'a' && cur_char <= 'f')) {
570 cur_char_val = 10 + (cur_char - 'a');
571 } else if ((cur_char >= 'A' && cur_char <= 'F')) {
572 cur_char_val = 10 + (cur_char - 'A');
573 }
574
575 unicode = unicode * 16 + cur_char_val;
576
577 PEEK_NEXT_CHAR (a_this, &cur_char);
578 }
579
580 /* Eat a whitespace if possible. */
581 cr_tknzr_parse_w (a_this, &tmp_char_ptr1,
582 &tmp_char_ptr2, NULL);
583 *a_unicode = unicode;
584 return CR_OK;
585
586 error:
587 /*
588 *restore the initial position pointer backuped at
589 *the beginning of this function.
590 */
591 cr_tknzr_set_cur_pos (a_this, &init_pos);
592
593 return status;
594 }
595
596 /**
597 *parses an escape sequence as defined by the css spec:
598 *escape ::= {unicode}|\\[ -~\200-\4177777]
599 *@param a_this the current instance of #CRTknzr .
600 */
601 static enum CRStatus
cr_tknzr_parse_escape(CRTknzr * a_this,guint32 * a_esc_code,CRParsingLocation * a_location)602 cr_tknzr_parse_escape (CRTknzr * a_this, guint32 * a_esc_code,
603 CRParsingLocation *a_location)
604 {
605 enum CRStatus status = CR_OK;
606 guint32 cur_char = 0;
607 CRInputPos init_pos;
608 guchar next_chars[2];
609
610 g_return_val_if_fail (a_this && PRIVATE (a_this)
611 && a_esc_code, CR_BAD_PARAM_ERROR);
612
613 RECORD_INITIAL_POS (a_this, &init_pos);
614
615 PEEK_BYTE (a_this, 1, &next_chars[0]);
616 PEEK_BYTE (a_this, 2, &next_chars[1]);
617
618 if (next_chars[0] != '\\') {
619 status = CR_PARSING_ERROR;
620 goto error;
621 }
622
623 if ((next_chars[1] >= '0' && next_chars[1] <= '9')
624 || (next_chars[1] >= 'a' && next_chars[1] <= 'f')
625 || (next_chars[1] >= 'A' && next_chars[1] <= 'F')) {
626 status = cr_tknzr_parse_unicode_escape (a_this, a_esc_code,
627 a_location);
628 } else {
629 /*consume the '\' char */
630 READ_NEXT_CHAR (a_this, &cur_char);
631 if (a_location) {
632 cr_tknzr_get_parsing_location (a_this,
633 a_location) ;
634 }
635 /*then read the char after the '\' */
636 READ_NEXT_CHAR (a_this, &cur_char);
637
638 if (cur_char != ' ' && (cur_char < 200 || cur_char > 4177777)) {
639 status = CR_PARSING_ERROR;
640 goto error;
641 }
642 *a_esc_code = cur_char;
643
644 }
645 if (status == CR_OK) {
646 return CR_OK;
647 }
648 error:
649 cr_tknzr_set_cur_pos (a_this, &init_pos);
650 return status;
651 }
652
653 /**
654 *Parses a string type as defined in css spec [4.1.1]:
655 *
656 *string ::= {string1}|{string2}
657 *string1 ::= \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\"
658 *string2 ::= \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\'
659 *
660 *@param a_this the current instance of #CRTknzr.
661 *@param a_start out parameter. Upon successfull completion,
662 *points to the beginning of the string, points to an undefined value
663 *otherwise.
664 *@param a_end out parameter. Upon successfull completion, points to
665 *the beginning of the string, points to an undefined value otherwise.
666 *@return CR_OK upon successfull completion, an error code otherwise.
667 */
668 static enum CRStatus
cr_tknzr_parse_string(CRTknzr * a_this,CRString ** a_str)669 cr_tknzr_parse_string (CRTknzr * a_this, CRString ** a_str)
670 {
671 guint32 cur_char = 0,
672 delim = 0;
673 CRInputPos init_pos;
674 enum CRStatus status = CR_OK;
675 CRString *str = NULL;
676
677 g_return_val_if_fail (a_this && PRIVATE (a_this)
678 && PRIVATE (a_this)->input
679 && a_str, CR_BAD_PARAM_ERROR);
680
681 RECORD_INITIAL_POS (a_this, &init_pos);
682 READ_NEXT_CHAR (a_this, &cur_char);
683
684 if (cur_char == '"')
685 delim = '"';
686 else if (cur_char == '\'')
687 delim = '\'';
688 else {
689 status = CR_PARSING_ERROR;
690 goto error;
691 }
692 str = cr_string_new ();
693 if (str) {
694 cr_tknzr_get_parsing_location
695 (a_this, &str->location) ;
696 }
697 for (;;) {
698 guchar next_chars[2] = { 0 };
699
700 PEEK_BYTE (a_this, 1, &next_chars[0]);
701 PEEK_BYTE (a_this, 2, &next_chars[1]);
702
703 if (next_chars[0] == '\\') {
704 guchar *tmp_char_ptr1 = NULL,
705 *tmp_char_ptr2 = NULL;
706 guint32 esc_code = 0;
707
708 if (next_chars[1] == '\'' || next_chars[1] == '"') {
709 g_string_append_unichar (str->stryng,
710 next_chars[1]);
711 SKIP_BYTES (a_this, 2);
712 status = CR_OK;
713 } else {
714 status = cr_tknzr_parse_escape
715 (a_this, &esc_code, NULL);
716
717 if (status == CR_OK) {
718 g_string_append_unichar
719 (str->stryng,
720 esc_code);
721 }
722 }
723
724 if (status != CR_OK) {
725 /*
726 *consume the '\' char, and try to parse
727 *a newline.
728 */
729 READ_NEXT_CHAR (a_this, &cur_char);
730
731 status = cr_tknzr_parse_nl
732 (a_this, &tmp_char_ptr1,
733 &tmp_char_ptr2, NULL);
734 }
735
736 CHECK_PARSING_STATUS (status, FALSE);
737 } else if (strchr ("\t !#$%&", next_chars[0])
738 || (next_chars[0] >= '(' && next_chars[0] <= '~')) {
739 READ_NEXT_CHAR (a_this, &cur_char);
740 g_string_append_unichar (str->stryng,
741 cur_char);
742 status = CR_OK;
743 }
744
745 else if (cr_utils_is_nonascii (next_chars[0])) {
746 READ_NEXT_CHAR (a_this, &cur_char);
747 g_string_append_unichar (str->stryng, cur_char);
748 } else if (next_chars[0] == delim) {
749 READ_NEXT_CHAR (a_this, &cur_char);
750 break;
751 } else {
752 status = CR_PARSING_ERROR;
753 goto error;
754 }
755 }
756
757 if (status == CR_OK) {
758 if (*a_str == NULL) {
759 *a_str = str;
760 str = NULL;
761 } else {
762 (*a_str)->stryng = g_string_append_len
763 ((*a_str)->stryng,
764 str->stryng->str,
765 str->stryng->len);
766 cr_string_destroy (str);
767 }
768 return CR_OK;
769 }
770
771 error:
772
773 if (str) {
774 cr_string_destroy (str) ;
775 str = NULL;
776 }
777 cr_tknzr_set_cur_pos (a_this, &init_pos);
778 return status;
779 }
780
781 /**
782 *Parses the an nmstart as defined by the css2 spec [4.1.1]:
783 * nmstart [a-zA-Z]|{nonascii}|{escape}
784 *
785 *@param a_this the current instance of #CRTknzr.
786 *@param a_start out param. A pointer to the starting point of
787 *the token.
788 *@param a_end out param. A pointer to the ending point of the
789 *token.
790 *@param a_char out param. The actual parsed nmchar.
791 *@return CR_OK upon successfull completion,
792 *an error code otherwise.
793 */
794 static enum CRStatus
cr_tknzr_parse_nmstart(CRTknzr * a_this,guint32 * a_char,CRParsingLocation * a_location)795 cr_tknzr_parse_nmstart (CRTknzr * a_this,
796 guint32 * a_char,
797 CRParsingLocation *a_location)
798 {
799 CRInputPos init_pos;
800 enum CRStatus status = CR_OK;
801 guint32 cur_char = 0,
802 next_char = 0;
803
804 g_return_val_if_fail (a_this && PRIVATE (a_this)
805 && PRIVATE (a_this)->input
806 && a_char, CR_BAD_PARAM_ERROR);
807
808 RECORD_INITIAL_POS (a_this, &init_pos);
809
810 PEEK_NEXT_CHAR (a_this, &next_char);
811
812 if (next_char == '\\') {
813 status = cr_tknzr_parse_escape (a_this, a_char,
814 a_location);
815
816 if (status != CR_OK)
817 goto error;
818
819 } else if (cr_utils_is_nonascii (next_char) == TRUE
820 || ((next_char >= 'a') && (next_char <= 'z'))
821 || ((next_char >= 'A') && (next_char <= 'Z'))
822 ) {
823 READ_NEXT_CHAR (a_this, &cur_char);
824 if (a_location) {
825 cr_tknzr_get_parsing_location (a_this,
826 a_location) ;
827 }
828 *a_char = cur_char;
829 status = CR_OK;
830 } else {
831 status = CR_PARSING_ERROR;
832 goto error;
833 }
834
835 return CR_OK;
836
837 error:
838 cr_tknzr_set_cur_pos (a_this, &init_pos);
839
840 return status;
841
842 }
843
844 /**
845 *Parses an nmchar as described in the css spec at
846 *chap 4.1.1:
847 *nmchar ::= [a-z0-9-]|{nonascii}|{escape}
848 *
849 *Humm, I have added the possibility for nmchar to
850 *contain upper case letters.
851 *
852 *@param a_this the current instance of #CRTknzr.
853 *@param a_start out param. A pointer to the starting point of
854 *the token.
855 *@param a_end out param. A pointer to the ending point of the
856 *token.
857 *@param a_char out param. The actual parsed nmchar.
858 *@return CR_OK upon successfull completion,
859 *an error code otherwise.
860 */
861 static enum CRStatus
cr_tknzr_parse_nmchar(CRTknzr * a_this,guint32 * a_char,CRParsingLocation * a_location)862 cr_tknzr_parse_nmchar (CRTknzr * a_this, guint32 * a_char,
863 CRParsingLocation *a_location)
864 {
865 guint32 cur_char = 0,
866 next_char = 0;
867 enum CRStatus status = CR_OK;
868 CRInputPos init_pos;
869
870 g_return_val_if_fail (a_this && PRIVATE (a_this) && a_char,
871 CR_BAD_PARAM_ERROR);
872
873 RECORD_INITIAL_POS (a_this, &init_pos);
874
875 status = cr_input_peek_char (PRIVATE (a_this)->input,
876 &next_char) ;
877 if (status != CR_OK)
878 goto error;
879
880 if (next_char == '\\') {
881 status = cr_tknzr_parse_escape (a_this, a_char,
882 a_location);
883
884 if (status != CR_OK)
885 goto error;
886
887 } else if (cr_utils_is_nonascii (next_char) == TRUE
888 || ((next_char >= 'a') && (next_char <= 'z'))
889 || ((next_char >= 'A') && (next_char <= 'Z'))
890 || ((next_char >= '0') && (next_char <= '9'))
891 || (next_char == '-')
892 || (next_char == '_') /*'_' not allowed by the spec. */
893 ) {
894 READ_NEXT_CHAR (a_this, &cur_char);
895 *a_char = cur_char;
896 status = CR_OK;
897 if (a_location) {
898 cr_tknzr_get_parsing_location
899 (a_this, a_location) ;
900 }
901 } else {
902 status = CR_PARSING_ERROR;
903 goto error;
904 }
905 return CR_OK;
906
907 error:
908 cr_tknzr_set_cur_pos (a_this, &init_pos);
909 return status;
910 }
911
912 /**
913 *Parses an "ident" as defined in css spec [4.1.1]:
914 *ident ::= {nmstart}{nmchar}*
915 *
916 *Actually parses it using the css3 grammar:
917 *ident ::= -?{nmstart}{nmchar}*
918 *@param a_this the currens instance of #CRTknzr.
919 *
920 *@param a_str a pointer to parsed ident. If *a_str is NULL,
921 *this function allocates a new instance of CRString. If not,
922 *the function just appends the parsed string to the one passed.
923 *In both cases it is up to the caller to free *a_str.
924 *
925 *@return CR_OK upon successfull completion, an error code
926 *otherwise.
927 */
928 static enum CRStatus
cr_tknzr_parse_ident(CRTknzr * a_this,CRString ** a_str)929 cr_tknzr_parse_ident (CRTknzr * a_this, CRString ** a_str)
930 {
931 guint32 tmp_char = 0;
932 CRString *stringue = NULL ;
933 CRInputPos init_pos;
934 enum CRStatus status = CR_OK;
935 gboolean location_is_set = FALSE ;
936
937 g_return_val_if_fail (a_this && PRIVATE (a_this)
938 && PRIVATE (a_this)->input
939 && a_str, CR_BAD_PARAM_ERROR);
940
941 RECORD_INITIAL_POS (a_this, &init_pos);
942 PEEK_NEXT_CHAR (a_this, &tmp_char) ;
943 stringue = cr_string_new () ;
944 g_return_val_if_fail (stringue,
945 CR_OUT_OF_MEMORY_ERROR) ;
946
947 if (tmp_char == '-') {
948 READ_NEXT_CHAR (a_this, &tmp_char) ;
949 cr_tknzr_get_parsing_location
950 (a_this, &stringue->location) ;
951 location_is_set = TRUE ;
952 g_string_append_unichar (stringue->stryng,
953 tmp_char) ;
954 }
955 status = cr_tknzr_parse_nmstart (a_this, &tmp_char, NULL);
956 if (status != CR_OK) {
957 status = CR_PARSING_ERROR;
958 goto end ;
959 }
960 if (location_is_set == FALSE) {
961 cr_tknzr_get_parsing_location
962 (a_this, &stringue->location) ;
963 location_is_set = TRUE ;
964 }
965 g_string_append_unichar (stringue->stryng, tmp_char);
966 for (;;) {
967 status = cr_tknzr_parse_nmchar (a_this,
968 &tmp_char,
969 NULL);
970 if (status != CR_OK) {
971 status = CR_OK ;
972 break;
973 }
974 g_string_append_unichar (stringue->stryng, tmp_char);
975 }
976 if (status == CR_OK) {
977 if (!*a_str) {
978 *a_str = stringue ;
979
980 } else {
981 g_string_append_len ((*a_str)->stryng,
982 stringue->stryng->str,
983 stringue->stryng->len) ;
984 cr_string_destroy (stringue) ;
985 }
986 stringue = NULL ;
987 }
988
989 error:
990 end:
991 if (stringue) {
992 cr_string_destroy (stringue) ;
993 stringue = NULL ;
994 }
995 if (status != CR_OK ) {
996 cr_tknzr_set_cur_pos (a_this, &init_pos) ;
997 }
998 return status ;
999 }
1000
1001
1002 /**
1003 *Parses a "name" as defined by css spec [4.1.1]:
1004 *name ::= {nmchar}+
1005 *
1006 *@param a_this the current instance of #CRTknzr.
1007 *
1008 *@param a_str out parameter. A pointer to the successfully parsed
1009 *name. If *a_str is set to NULL, this function allocates a new instance
1010 *of CRString. If not, it just appends the parsed name to the passed *a_str.
1011 *In both cases, it is up to the caller to free *a_str.
1012 *
1013 *@return CR_OK upon successfull completion, an error code otherwise.
1014 */
1015 static enum CRStatus
cr_tknzr_parse_name(CRTknzr * a_this,CRString ** a_str)1016 cr_tknzr_parse_name (CRTknzr * a_this,
1017 CRString ** a_str)
1018 {
1019 guint32 tmp_char = 0;
1020 CRInputPos init_pos;
1021 enum CRStatus status = CR_OK;
1022 gboolean str_needs_free = FALSE,
1023 is_first_nmchar=TRUE ;
1024 glong i = 0;
1025 CRParsingLocation loc = {0} ;
1026
1027 g_return_val_if_fail (a_this && PRIVATE (a_this)
1028 && PRIVATE (a_this)->input
1029 && a_str,
1030 CR_BAD_PARAM_ERROR) ;
1031
1032 RECORD_INITIAL_POS (a_this, &init_pos);
1033
1034 if (*a_str == NULL) {
1035 *a_str = cr_string_new ();
1036 str_needs_free = TRUE;
1037 }
1038 for (i = 0;; i++) {
1039 if (is_first_nmchar == TRUE) {
1040 status = cr_tknzr_parse_nmchar
1041 (a_this, &tmp_char,
1042 &loc) ;
1043 is_first_nmchar = FALSE ;
1044 } else {
1045 status = cr_tknzr_parse_nmchar
1046 (a_this, &tmp_char, NULL) ;
1047 }
1048 if (status != CR_OK)
1049 break;
1050 g_string_append_unichar ((*a_str)->stryng,
1051 tmp_char);
1052 }
1053 if (i > 0) {
1054 cr_parsing_location_copy
1055 (&(*a_str)->location, &loc) ;
1056 return CR_OK;
1057 }
1058 if (str_needs_free == TRUE && *a_str) {
1059 cr_string_destroy (*a_str);
1060 *a_str = NULL;
1061 }
1062 cr_tknzr_set_cur_pos (a_this, &init_pos);
1063 return CR_PARSING_ERROR;
1064 }
1065
1066 /**
1067 *Parses a "hash" as defined by the css spec in [4.1.1]:
1068 *HASH ::= #{name}
1069 */
1070 static enum CRStatus
cr_tknzr_parse_hash(CRTknzr * a_this,CRString ** a_str)1071 cr_tknzr_parse_hash (CRTknzr * a_this, CRString ** a_str)
1072 {
1073 guint32 cur_char = 0;
1074 CRInputPos init_pos;
1075 enum CRStatus status = CR_OK;
1076 gboolean str_needs_free = FALSE;
1077 CRParsingLocation loc = {0} ;
1078
1079 g_return_val_if_fail (a_this && PRIVATE (a_this)
1080 && PRIVATE (a_this)->input,
1081 CR_BAD_PARAM_ERROR);
1082
1083 RECORD_INITIAL_POS (a_this, &init_pos);
1084 READ_NEXT_CHAR (a_this, &cur_char);
1085 if (cur_char != '#') {
1086 status = CR_PARSING_ERROR;
1087 goto error;
1088 }
1089 if (*a_str == NULL) {
1090 *a_str = cr_string_new ();
1091 str_needs_free = TRUE;
1092 }
1093 cr_tknzr_get_parsing_location (a_this,
1094 &loc) ;
1095 status = cr_tknzr_parse_name (a_this, a_str);
1096 cr_parsing_location_copy (&(*a_str)->location, &loc) ;
1097 if (status != CR_OK) {
1098 goto error;
1099 }
1100 return CR_OK;
1101
1102 error:
1103 if (str_needs_free == TRUE && *a_str) {
1104 cr_string_destroy (*a_str);
1105 *a_str = NULL;
1106 }
1107
1108 cr_tknzr_set_cur_pos (a_this, &init_pos);
1109 return status;
1110 }
1111
1112 /**
1113 *Parses an uri as defined by the css spec [4.1.1]:
1114 * URI ::= url\({w}{string}{w}\)
1115 * |url\({w}([!#$%&*-~]|{nonascii}|{escape})*{w}\)
1116 *
1117 *@param a_this the current instance of #CRTknzr.
1118 *@param a_str the successfully parsed url.
1119 *@return CR_OK upon successfull completion, an error code otherwise.
1120 */
1121 static enum CRStatus
cr_tknzr_parse_uri(CRTknzr * a_this,CRString ** a_str)1122 cr_tknzr_parse_uri (CRTknzr * a_this,
1123 CRString ** a_str)
1124 {
1125 guint32 cur_char = 0;
1126 CRInputPos init_pos;
1127 enum CRStatus status = CR_PARSING_ERROR;
1128 guchar tab[4] = { 0 }, *tmp_ptr1 = NULL, *tmp_ptr2 = NULL;
1129 CRString *str = NULL;
1130 CRParsingLocation location = {0} ;
1131
1132 g_return_val_if_fail (a_this
1133 && PRIVATE (a_this)
1134 && PRIVATE (a_this)->input
1135 && a_str,
1136 CR_BAD_PARAM_ERROR);
1137
1138 RECORD_INITIAL_POS (a_this, &init_pos);
1139
1140 PEEK_BYTE (a_this, 1, &tab[0]);
1141 PEEK_BYTE (a_this, 2, &tab[1]);
1142 PEEK_BYTE (a_this, 3, &tab[2]);
1143 PEEK_BYTE (a_this, 4, &tab[3]);
1144
1145 if (tab[0] != 'u' || tab[1] != 'r' || tab[2] != 'l' || tab[3] != '(') {
1146 status = CR_PARSING_ERROR;
1147 goto error;
1148 }
1149 /*
1150 *Here, we want to skip 4 bytes ('u''r''l''(').
1151 *But we also need to keep track of the parsing location
1152 *of the 'u'. So, we skip 1 byte, we record the parsing
1153 *location, then we skip the 3 remaining bytes.
1154 */
1155 SKIP_CHARS (a_this, 1);
1156 cr_tknzr_get_parsing_location (a_this, &location) ;
1157 SKIP_CHARS (a_this, 3);
1158 cr_tknzr_try_to_skip_spaces (a_this);
1159 status = cr_tknzr_parse_string (a_this, a_str);
1160
1161 if (status == CR_OK) {
1162 guint32 next_char = 0;
1163 status = cr_tknzr_parse_w (a_this, &tmp_ptr1,
1164 &tmp_ptr2, NULL);
1165 cr_tknzr_try_to_skip_spaces (a_this);
1166 PEEK_NEXT_CHAR (a_this, &next_char);
1167 if (next_char == ')') {
1168 READ_NEXT_CHAR (a_this, &cur_char);
1169 status = CR_OK;
1170 } else {
1171 status = CR_PARSING_ERROR;
1172 }
1173 }
1174 if (status != CR_OK) {
1175 str = cr_string_new ();
1176 for (;;) {
1177 guint32 next_char = 0;
1178 PEEK_NEXT_CHAR (a_this, &next_char);
1179 if (strchr ("!#$%&", next_char)
1180 || (next_char >= '*' && next_char <= '~')
1181 || (cr_utils_is_nonascii (next_char) == TRUE)) {
1182 READ_NEXT_CHAR (a_this, &cur_char);
1183 g_string_append_unichar
1184 (str->stryng, cur_char);
1185 status = CR_OK;
1186 } else {
1187 guint32 esc_code = 0;
1188 status = cr_tknzr_parse_escape
1189 (a_this, &esc_code, NULL);
1190 if (status == CR_OK) {
1191 g_string_append_unichar
1192 (str->stryng,
1193 esc_code);
1194 } else {
1195 status = CR_OK;
1196 break;
1197 }
1198 }
1199 }
1200 cr_tknzr_try_to_skip_spaces (a_this);
1201 READ_NEXT_CHAR (a_this, &cur_char);
1202 if (cur_char == ')') {
1203 status = CR_OK;
1204 } else {
1205 status = CR_PARSING_ERROR;
1206 goto error;
1207 }
1208 if (str) {
1209 if (*a_str == NULL) {
1210 *a_str = str;
1211 str = NULL;
1212 } else {
1213 g_string_append_len
1214 ((*a_str)->stryng,
1215 str->stryng->str,
1216 str->stryng->len);
1217 cr_string_destroy (str);
1218 }
1219 }
1220 }
1221
1222 cr_parsing_location_copy
1223 (&(*a_str)->location,
1224 &location) ;
1225 return CR_OK ;
1226 error:
1227 if (str) {
1228 cr_string_destroy (str);
1229 str = NULL;
1230 }
1231 cr_tknzr_set_cur_pos (a_this, &init_pos);
1232 return status;
1233 }
1234
1235 /**
1236 *parses an RGB as defined in the css2 spec.
1237 *rgb: rgb '('S*{num}%?S* ',' {num}#?S*,S*{num}#?S*')'
1238 *
1239 *@param a_this the "this pointer" of the current instance of
1240 *@param a_rgb out parameter the parsed rgb.
1241 *@return CR_OK upon successfull completion, an error code otherwise.
1242 */
1243 static enum CRStatus
cr_tknzr_parse_rgb(CRTknzr * a_this,CRRgb ** a_rgb)1244 cr_tknzr_parse_rgb (CRTknzr * a_this, CRRgb ** a_rgb)
1245 {
1246 enum CRStatus status = CR_OK;
1247 CRInputPos init_pos;
1248 CRNum *num = NULL;
1249 guchar next_bytes[3] = { 0 }, cur_byte = 0;
1250 glong red = 0,
1251 green = 0,
1252 blue = 0,
1253 i = 0;
1254 gboolean is_percentage = FALSE;
1255 CRParsingLocation location = {0} ;
1256
1257 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
1258
1259 RECORD_INITIAL_POS (a_this, &init_pos);
1260
1261 PEEK_BYTE (a_this, 1, &next_bytes[0]);
1262 PEEK_BYTE (a_this, 2, &next_bytes[1]);
1263 PEEK_BYTE (a_this, 3, &next_bytes[2]);
1264
1265 if (((next_bytes[0] == 'r') || (next_bytes[0] == 'R'))
1266 && ((next_bytes[1] == 'g') || (next_bytes[1] == 'G'))
1267 && ((next_bytes[2] == 'b') || (next_bytes[2] == 'B'))) {
1268 SKIP_CHARS (a_this, 1);
1269 cr_tknzr_get_parsing_location (a_this, &location) ;
1270 SKIP_CHARS (a_this, 2);
1271 } else {
1272 status = CR_PARSING_ERROR;
1273 goto error;
1274 }
1275 READ_NEXT_BYTE (a_this, &cur_byte);
1276 ENSURE_PARSING_COND (cur_byte == '(');
1277
1278 cr_tknzr_try_to_skip_spaces (a_this);
1279 status = cr_tknzr_parse_num (a_this, &num);
1280 ENSURE_PARSING_COND ((status == CR_OK) && (num != NULL));
1281
1282 if (num->val > G_MAXLONG) {
1283 status = CR_PARSING_ERROR;
1284 goto error;
1285 }
1286
1287 red = num->val;
1288 cr_num_destroy (num);
1289 num = NULL;
1290
1291 PEEK_BYTE (a_this, 1, &next_bytes[0]);
1292 if (next_bytes[0] == '%') {
1293 SKIP_CHARS (a_this, 1);
1294 is_percentage = TRUE;
1295 }
1296 cr_tknzr_try_to_skip_spaces (a_this);
1297
1298 for (i = 0; i < 2; i++) {
1299 READ_NEXT_BYTE (a_this, &cur_byte);
1300 ENSURE_PARSING_COND (cur_byte == ',');
1301
1302 cr_tknzr_try_to_skip_spaces (a_this);
1303 status = cr_tknzr_parse_num (a_this, &num);
1304 ENSURE_PARSING_COND ((status == CR_OK) && (num != NULL));
1305
1306 if (num->val > G_MAXLONG) {
1307 status = CR_PARSING_ERROR;
1308 goto error;
1309 }
1310
1311 PEEK_BYTE (a_this, 1, &next_bytes[0]);
1312 if (next_bytes[0] == '%') {
1313 SKIP_CHARS (a_this, 1);
1314 is_percentage = 1;
1315 }
1316
1317 if (i == 0) {
1318 green = num->val;
1319 } else if (i == 1) {
1320 blue = num->val;
1321 }
1322
1323 if (num) {
1324 cr_num_destroy (num);
1325 num = NULL;
1326 }
1327 cr_tknzr_try_to_skip_spaces (a_this);
1328 }
1329
1330 READ_NEXT_BYTE (a_this, &cur_byte);
1331 if (*a_rgb == NULL) {
1332 *a_rgb = cr_rgb_new_with_vals (red, green, blue,
1333 is_percentage);
1334
1335 if (*a_rgb == NULL) {
1336 status = CR_ERROR;
1337 goto error;
1338 }
1339 status = CR_OK;
1340 } else {
1341 (*a_rgb)->red = red;
1342 (*a_rgb)->green = green;
1343 (*a_rgb)->blue = blue;
1344 (*a_rgb)->is_percentage = is_percentage;
1345
1346 status = CR_OK;
1347 }
1348
1349 if (status == CR_OK) {
1350 if (a_rgb && *a_rgb) {
1351 cr_parsing_location_copy
1352 (&(*a_rgb)->location,
1353 &location) ;
1354 }
1355 return CR_OK;
1356 }
1357
1358 error:
1359 if (num) {
1360 cr_num_destroy (num);
1361 num = NULL;
1362 }
1363
1364 cr_tknzr_set_cur_pos (a_this, &init_pos);
1365 return CR_OK;
1366 }
1367
1368 /**
1369 *Parses a atkeyword as defined by the css spec in [4.1.1]:
1370 *ATKEYWORD ::= @{ident}
1371 *
1372 *@param a_this the "this pointer" of the current instance of
1373 *#CRTknzr.
1374 *
1375 *@param a_str out parameter. The parsed atkeyword. If *a_str is
1376 *set to NULL this function allocates a new instance of CRString and
1377 *sets it to the parsed atkeyword. If not, this function just appends
1378 *the parsed atkeyword to the end of *a_str. In both cases it is up to
1379 *the caller to free *a_str.
1380 *
1381 *@return CR_OK upon successfull completion, an error code otherwise.
1382 */
1383 static enum CRStatus
cr_tknzr_parse_atkeyword(CRTknzr * a_this,CRString ** a_str)1384 cr_tknzr_parse_atkeyword (CRTknzr * a_this,
1385 CRString ** a_str)
1386 {
1387 guint32 cur_char = 0;
1388 CRInputPos init_pos;
1389 gboolean str_needs_free = FALSE;
1390 enum CRStatus status = CR_OK;
1391
1392 g_return_val_if_fail (a_this && PRIVATE (a_this)
1393 && PRIVATE (a_this)->input
1394 && a_str, CR_BAD_PARAM_ERROR);
1395
1396 RECORD_INITIAL_POS (a_this, &init_pos);
1397
1398 READ_NEXT_CHAR (a_this, &cur_char);
1399
1400 if (cur_char != '@') {
1401 status = CR_PARSING_ERROR;
1402 goto error;
1403 }
1404
1405 if (*a_str == NULL) {
1406 *a_str = cr_string_new ();
1407 str_needs_free = TRUE;
1408 }
1409 status = cr_tknzr_parse_ident (a_this, a_str);
1410 if (status != CR_OK) {
1411 goto error;
1412 }
1413 return CR_OK;
1414 error:
1415
1416 if (str_needs_free == TRUE && *a_str) {
1417 cr_string_destroy (*a_str);
1418 *a_str = NULL;
1419 }
1420 cr_tknzr_set_cur_pos (a_this, &init_pos);
1421 return status;
1422 }
1423
1424 static enum CRStatus
cr_tknzr_parse_important(CRTknzr * a_this,CRParsingLocation * a_location)1425 cr_tknzr_parse_important (CRTknzr * a_this,
1426 CRParsingLocation *a_location)
1427 {
1428 guint32 cur_char = 0;
1429 CRInputPos init_pos;
1430 enum CRStatus status = CR_OK;
1431
1432 g_return_val_if_fail (a_this && PRIVATE (a_this)
1433 && PRIVATE (a_this)->input,
1434 CR_BAD_PARAM_ERROR);
1435
1436 RECORD_INITIAL_POS (a_this, &init_pos);
1437 READ_NEXT_CHAR (a_this, &cur_char);
1438 ENSURE_PARSING_COND (cur_char == '!');
1439 if (a_location) {
1440 cr_tknzr_get_parsing_location (a_this,
1441 a_location) ;
1442 }
1443 cr_tknzr_try_to_skip_spaces (a_this);
1444
1445 if (BYTE (PRIVATE (a_this)->input, 1, NULL) == 'i'
1446 && BYTE (PRIVATE (a_this)->input, 2, NULL) == 'm'
1447 && BYTE (PRIVATE (a_this)->input, 3, NULL) == 'p'
1448 && BYTE (PRIVATE (a_this)->input, 4, NULL) == 'o'
1449 && BYTE (PRIVATE (a_this)->input, 5, NULL) == 'r'
1450 && BYTE (PRIVATE (a_this)->input, 6, NULL) == 't'
1451 && BYTE (PRIVATE (a_this)->input, 7, NULL) == 'a'
1452 && BYTE (PRIVATE (a_this)->input, 8, NULL) == 'n'
1453 && BYTE (PRIVATE (a_this)->input, 9, NULL) == 't') {
1454 SKIP_BYTES (a_this, 9);
1455 if (a_location) {
1456 cr_tknzr_get_parsing_location (a_this,
1457 a_location) ;
1458 }
1459 return CR_OK;
1460 } else {
1461 status = CR_PARSING_ERROR;
1462 }
1463
1464 error:
1465 cr_tknzr_set_cur_pos (a_this, &init_pos);
1466
1467 return status;
1468 }
1469
1470 /**
1471 *Parses a num as defined in the css spec [4.1.1]:
1472 *[0-9]+|[0-9]*\.[0-9]+
1473 *@param a_this the current instance of #CRTknzr.
1474 *@param a_num out parameter. The parsed number.
1475 *@return CR_OK upon successfull completion,
1476 *an error code otherwise.
1477 *
1478 *The CSS specification says that numbers may be
1479 *preceeded by '+' or '-' to indicate the sign.
1480 *Technically, the "num" construction as defined
1481 *by the tokenizer doesn't allow this, but we parse
1482 *it here for simplicity.
1483 */
1484 static enum CRStatus
cr_tknzr_parse_num(CRTknzr * a_this,CRNum ** a_num)1485 cr_tknzr_parse_num (CRTknzr * a_this,
1486 CRNum ** a_num)
1487 {
1488 enum CRStatus status = CR_PARSING_ERROR;
1489 enum CRNumType val_type = NUM_GENERIC;
1490 gboolean parsing_dec, /* true iff seen decimal point. */
1491 parsed; /* true iff the substring seen so far is a valid CSS
1492 number, i.e. `[0-9]+|[0-9]*\.[0-9]+'. */
1493 guint32 cur_char = 0,
1494 next_char = 0;
1495 gdouble numerator, denominator = 1;
1496 CRInputPos init_pos;
1497 CRParsingLocation location = {0} ;
1498 int sign = 1;
1499
1500 g_return_val_if_fail (a_this && PRIVATE (a_this)
1501 && PRIVATE (a_this)->input,
1502 CR_BAD_PARAM_ERROR);
1503
1504 RECORD_INITIAL_POS (a_this, &init_pos);
1505 READ_NEXT_CHAR (a_this, &cur_char);
1506
1507 if (cur_char == '+' || cur_char == '-') {
1508 if (cur_char == '-') {
1509 sign = -1;
1510 }
1511 READ_NEXT_CHAR (a_this, &cur_char);
1512 }
1513
1514 if (IS_NUM (cur_char)) {
1515 numerator = (cur_char - '0');
1516 parsing_dec = FALSE;
1517 parsed = TRUE;
1518 } else if (cur_char == '.') {
1519 numerator = 0;
1520 parsing_dec = TRUE;
1521 parsed = FALSE;
1522 } else {
1523 status = CR_PARSING_ERROR;
1524 goto error;
1525 }
1526 cr_tknzr_get_parsing_location (a_this, &location) ;
1527
1528 for (;;) {
1529 status = cr_tknzr_peek_char (a_this, &next_char);
1530 if (status != CR_OK) {
1531 if (status == CR_END_OF_INPUT_ERROR)
1532 status = CR_OK;
1533 break;
1534 }
1535 if (next_char == '.') {
1536 if (parsing_dec) {
1537 status = CR_PARSING_ERROR;
1538 goto error;
1539 }
1540
1541 READ_NEXT_CHAR (a_this, &cur_char);
1542 parsing_dec = TRUE;
1543 parsed = FALSE; /* In CSS, there must be at least
1544 one digit after `.'. */
1545 } else if (IS_NUM (next_char)) {
1546 READ_NEXT_CHAR (a_this, &cur_char);
1547 parsed = TRUE;
1548
1549 numerator = numerator * 10 + (cur_char - '0');
1550 if (parsing_dec) {
1551 denominator *= 10;
1552 }
1553 } else {
1554 break;
1555 }
1556 }
1557
1558 if (!parsed) {
1559 status = CR_PARSING_ERROR;
1560 }
1561
1562 /*
1563 *Now, set the output param values.
1564 */
1565 if (status == CR_OK) {
1566 gdouble val = (numerator / denominator) * sign;
1567 if (*a_num == NULL) {
1568 *a_num = cr_num_new_with_val (val, val_type);
1569
1570 if (*a_num == NULL) {
1571 status = CR_ERROR;
1572 goto error;
1573 }
1574 } else {
1575 (*a_num)->val = val;
1576 (*a_num)->type = val_type;
1577 }
1578 cr_parsing_location_copy (&(*a_num)->location,
1579 &location) ;
1580 return CR_OK;
1581 }
1582
1583 error:
1584
1585 cr_tknzr_set_cur_pos (a_this, &init_pos);
1586
1587 return status;
1588 }
1589
1590 /*********************************************
1591 *PUBLIC methods
1592 ********************************************/
1593
1594 CRTknzr *
cr_tknzr_new(CRInput * a_input)1595 cr_tknzr_new (CRInput * a_input)
1596 {
1597 CRTknzr *result = NULL;
1598
1599 result = g_try_malloc (sizeof (CRTknzr));
1600
1601 if (result == NULL) {
1602 cr_utils_trace_info ("Out of memory");
1603 return NULL;
1604 }
1605
1606 memset (result, 0, sizeof (CRTknzr));
1607
1608 result->priv = g_try_malloc (sizeof (CRTknzrPriv));
1609
1610 if (result->priv == NULL) {
1611 cr_utils_trace_info ("Out of memory");
1612
1613 if (result) {
1614 g_free (result);
1615 result = NULL;
1616 }
1617
1618 return NULL;
1619 }
1620 memset (result->priv, 0, sizeof (CRTknzrPriv));
1621 if (a_input)
1622 cr_tknzr_set_input (result, a_input);
1623 return result;
1624 }
1625
1626 CRTknzr *
cr_tknzr_new_from_buf(guchar * a_buf,gulong a_len,enum CREncoding a_enc,gboolean a_free_at_destroy)1627 cr_tknzr_new_from_buf (guchar * a_buf, gulong a_len,
1628 enum CREncoding a_enc,
1629 gboolean a_free_at_destroy)
1630 {
1631 CRTknzr *result = NULL;
1632 CRInput *input = NULL;
1633
1634 input = cr_input_new_from_buf (a_buf, a_len, a_enc,
1635 a_free_at_destroy);
1636
1637 g_return_val_if_fail (input != NULL, NULL);
1638
1639 result = cr_tknzr_new (input);
1640
1641 return result;
1642 }
1643
1644 CRTknzr *
cr_tknzr_new_from_uri(const guchar * a_file_uri,enum CREncoding a_enc)1645 cr_tknzr_new_from_uri (const guchar * a_file_uri,
1646 enum CREncoding a_enc)
1647 {
1648 CRTknzr *result = NULL;
1649 CRInput *input = NULL;
1650
1651 input = cr_input_new_from_uri ((const gchar *) a_file_uri, a_enc);
1652 g_return_val_if_fail (input != NULL, NULL);
1653
1654 result = cr_tknzr_new (input);
1655
1656 return result;
1657 }
1658
1659 void
cr_tknzr_ref(CRTknzr * a_this)1660 cr_tknzr_ref (CRTknzr * a_this)
1661 {
1662 g_return_if_fail (a_this && PRIVATE (a_this));
1663
1664 PRIVATE (a_this)->ref_count++;
1665 }
1666
1667 gboolean
cr_tknzr_unref(CRTknzr * a_this)1668 cr_tknzr_unref (CRTknzr * a_this)
1669 {
1670 g_return_val_if_fail (a_this && PRIVATE (a_this), FALSE);
1671
1672 if (PRIVATE (a_this)->ref_count > 0) {
1673 PRIVATE (a_this)->ref_count--;
1674 }
1675
1676 if (PRIVATE (a_this)->ref_count == 0) {
1677 cr_tknzr_destroy (a_this);
1678 return TRUE;
1679 }
1680
1681 return FALSE;
1682 }
1683
1684 enum CRStatus
cr_tknzr_set_input(CRTknzr * a_this,CRInput * a_input)1685 cr_tknzr_set_input (CRTknzr * a_this, CRInput * a_input)
1686 {
1687 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
1688
1689 if (PRIVATE (a_this)->input) {
1690 cr_input_unref (PRIVATE (a_this)->input);
1691 }
1692
1693 PRIVATE (a_this)->input = a_input;
1694
1695 cr_input_ref (PRIVATE (a_this)->input);
1696
1697 return CR_OK;
1698 }
1699
1700 enum CRStatus
cr_tknzr_get_input(CRTknzr * a_this,CRInput ** a_input)1701 cr_tknzr_get_input (CRTknzr * a_this, CRInput ** a_input)
1702 {
1703 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
1704
1705 *a_input = PRIVATE (a_this)->input;
1706
1707 return CR_OK;
1708 }
1709
1710 /*********************************
1711 *Tokenizer input handling routines
1712 *********************************/
1713
1714 /**
1715 *Reads the next byte from the parser input stream.
1716 *@param a_this the "this pointer" of the current instance of
1717 *#CRParser.
1718 *@param a_byte out parameter the place where to store the byte
1719 *read.
1720 *@return CR_OK upon successfull completion, an error
1721 *code otherwise.
1722 */
1723 enum CRStatus
cr_tknzr_read_byte(CRTknzr * a_this,guchar * a_byte)1724 cr_tknzr_read_byte (CRTknzr * a_this, guchar * a_byte)
1725 {
1726 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
1727
1728 return cr_input_read_byte (PRIVATE (a_this)->input, a_byte);
1729
1730 }
1731
1732 /**
1733 *Reads the next char from the parser input stream.
1734 *@param a_this the current instance of #CRTknzr.
1735 *@param a_char out parameter. The read char.
1736 *@return CR_OK upon successfull completion, an error code
1737 *otherwise.
1738 */
1739 enum CRStatus
cr_tknzr_read_char(CRTknzr * a_this,guint32 * a_char)1740 cr_tknzr_read_char (CRTknzr * a_this, guint32 * a_char)
1741 {
1742 g_return_val_if_fail (a_this && PRIVATE (a_this)
1743 && PRIVATE (a_this)->input
1744 && a_char, CR_BAD_PARAM_ERROR);
1745
1746 if (PRIVATE (a_this)->token_cache) {
1747 cr_input_set_cur_pos (PRIVATE (a_this)->input,
1748 &PRIVATE (a_this)->prev_pos);
1749 cr_token_destroy (PRIVATE (a_this)->token_cache);
1750 PRIVATE (a_this)->token_cache = NULL;
1751 }
1752
1753 return cr_input_read_char (PRIVATE (a_this)->input, a_char);
1754 }
1755
1756 /**
1757 *Peeks a char from the parser input stream.
1758 *To "peek a char" means reads the next char without consuming it.
1759 *Subsequent calls to this function return the same char.
1760 *@param a_this the current instance of #CRTknzr.
1761 *@param a_char out parameter. The peeked char uppon successfull completion.
1762 *@return CR_OK upon successfull completion, an error code otherwise.
1763 */
1764 enum CRStatus
cr_tknzr_peek_char(CRTknzr * a_this,guint32 * a_char)1765 cr_tknzr_peek_char (CRTknzr * a_this, guint32 * a_char)
1766 {
1767 g_return_val_if_fail (a_this && PRIVATE (a_this)
1768 && PRIVATE (a_this)->input
1769 && a_char, CR_BAD_PARAM_ERROR);
1770
1771 if (PRIVATE (a_this)->token_cache) {
1772 cr_input_set_cur_pos (PRIVATE (a_this)->input,
1773 &PRIVATE (a_this)->prev_pos);
1774 cr_token_destroy (PRIVATE (a_this)->token_cache);
1775 PRIVATE (a_this)->token_cache = NULL;
1776 }
1777
1778 return cr_input_peek_char (PRIVATE (a_this)->input, a_char);
1779 }
1780
1781 /**
1782 *Peeks a byte ahead at a given postion in the parser input stream.
1783 *@param a_this the current instance of #CRTknzr.
1784 *@param a_offset the offset of the peeked byte starting from the current
1785 *byte in the parser input stream.
1786 *@param a_byte out parameter. The peeked byte upon
1787 *successfull completion.
1788 *@return CR_OK upon successfull completion, an error code otherwise.
1789 */
1790 enum CRStatus
cr_tknzr_peek_byte(CRTknzr * a_this,gulong a_offset,guchar * a_byte)1791 cr_tknzr_peek_byte (CRTknzr * a_this, gulong a_offset, guchar * a_byte)
1792 {
1793 g_return_val_if_fail (a_this && PRIVATE (a_this)
1794 && PRIVATE (a_this)->input && a_byte,
1795 CR_BAD_PARAM_ERROR);
1796
1797 if (PRIVATE (a_this)->token_cache) {
1798 cr_input_set_cur_pos (PRIVATE (a_this)->input,
1799 &PRIVATE (a_this)->prev_pos);
1800 cr_token_destroy (PRIVATE (a_this)->token_cache);
1801 PRIVATE (a_this)->token_cache = NULL;
1802 }
1803
1804 return cr_input_peek_byte (PRIVATE (a_this)->input,
1805 CR_SEEK_CUR, a_offset, a_byte);
1806 }
1807
1808 /**
1809 *Same as cr_tknzr_peek_byte() but this api returns the byte peeked.
1810 *@param a_this the current instance of #CRTknzr.
1811 *@param a_offset the offset of the peeked byte starting from the current
1812 *byte in the parser input stream.
1813 *@param a_eof out parameter. If not NULL, is set to TRUE if we reached end of
1814 *file, FALE otherwise. If the caller sets it to NULL, this parameter
1815 *is just ignored.
1816 *@return the peeked byte.
1817 */
1818 guchar
cr_tknzr_peek_byte2(CRTknzr * a_this,gulong a_offset,gboolean * a_eof)1819 cr_tknzr_peek_byte2 (CRTknzr * a_this, gulong a_offset, gboolean * a_eof)
1820 {
1821 g_return_val_if_fail (a_this && PRIVATE (a_this)
1822 && PRIVATE (a_this)->input, 0);
1823
1824 return cr_input_peek_byte2 (PRIVATE (a_this)->input, a_offset, a_eof);
1825 }
1826
1827 /**
1828 *Gets the number of bytes left in the topmost input stream
1829 *associated to this parser.
1830 *@param a_this the current instance of #CRTknzr
1831 *@return the number of bytes left or -1 in case of error.
1832 */
1833 glong
cr_tknzr_get_nb_bytes_left(CRTknzr * a_this)1834 cr_tknzr_get_nb_bytes_left (CRTknzr * a_this)
1835 {
1836 g_return_val_if_fail (a_this && PRIVATE (a_this)
1837 && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
1838
1839 if (PRIVATE (a_this)->token_cache) {
1840 cr_input_set_cur_pos (PRIVATE (a_this)->input,
1841 &PRIVATE (a_this)->prev_pos);
1842 cr_token_destroy (PRIVATE (a_this)->token_cache);
1843 PRIVATE (a_this)->token_cache = NULL;
1844 }
1845
1846 return cr_input_get_nb_bytes_left (PRIVATE (a_this)->input);
1847 }
1848
1849 enum CRStatus
cr_tknzr_get_cur_pos(CRTknzr * a_this,CRInputPos * a_pos)1850 cr_tknzr_get_cur_pos (CRTknzr * a_this, CRInputPos * a_pos)
1851 {
1852 g_return_val_if_fail (a_this && PRIVATE (a_this)
1853 && PRIVATE (a_this)->input
1854 && a_pos, CR_BAD_PARAM_ERROR);
1855
1856 if (PRIVATE (a_this)->token_cache) {
1857 cr_input_set_cur_pos (PRIVATE (a_this)->input,
1858 &PRIVATE (a_this)->prev_pos);
1859 cr_token_destroy (PRIVATE (a_this)->token_cache);
1860 PRIVATE (a_this)->token_cache = NULL;
1861 }
1862
1863 return cr_input_get_cur_pos (PRIVATE (a_this)->input, a_pos);
1864 }
1865
1866 enum CRStatus
cr_tknzr_get_parsing_location(CRTknzr * a_this,CRParsingLocation * a_loc)1867 cr_tknzr_get_parsing_location (CRTknzr *a_this,
1868 CRParsingLocation *a_loc)
1869 {
1870 g_return_val_if_fail (a_this
1871 && PRIVATE (a_this)
1872 && a_loc,
1873 CR_BAD_PARAM_ERROR) ;
1874
1875 return cr_input_get_parsing_location
1876 (PRIVATE (a_this)->input, a_loc) ;
1877 }
1878
1879 enum CRStatus
cr_tknzr_get_cur_byte_addr(CRTknzr * a_this,guchar ** a_addr)1880 cr_tknzr_get_cur_byte_addr (CRTknzr * a_this, guchar ** a_addr)
1881 {
1882 g_return_val_if_fail (a_this && PRIVATE (a_this)
1883 && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
1884 if (PRIVATE (a_this)->token_cache) {
1885 cr_input_set_cur_pos (PRIVATE (a_this)->input,
1886 &PRIVATE (a_this)->prev_pos);
1887 cr_token_destroy (PRIVATE (a_this)->token_cache);
1888 PRIVATE (a_this)->token_cache = NULL;
1889 }
1890
1891 return cr_input_get_cur_byte_addr (PRIVATE (a_this)->input, a_addr);
1892 }
1893
1894 enum CRStatus
cr_tknzr_seek_index(CRTknzr * a_this,enum CRSeekPos a_origin,gint a_pos)1895 cr_tknzr_seek_index (CRTknzr * a_this, enum CRSeekPos a_origin, gint a_pos)
1896 {
1897 g_return_val_if_fail (a_this && PRIVATE (a_this)
1898 && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
1899
1900 if (PRIVATE (a_this)->token_cache) {
1901 cr_input_set_cur_pos (PRIVATE (a_this)->input,
1902 &PRIVATE (a_this)->prev_pos);
1903 cr_token_destroy (PRIVATE (a_this)->token_cache);
1904 PRIVATE (a_this)->token_cache = NULL;
1905 }
1906
1907 return cr_input_seek_index (PRIVATE (a_this)->input, a_origin, a_pos);
1908 }
1909
1910 enum CRStatus
cr_tknzr_consume_chars(CRTknzr * a_this,guint32 a_char,glong * a_nb_char)1911 cr_tknzr_consume_chars (CRTknzr * a_this, guint32 a_char, glong * a_nb_char)
1912 {
1913 gulong consumed = *(gulong *) a_nb_char;
1914 enum CRStatus status;
1915 g_return_val_if_fail (a_this && PRIVATE (a_this)
1916 && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
1917
1918 if (PRIVATE (a_this)->token_cache) {
1919 cr_input_set_cur_pos (PRIVATE (a_this)->input,
1920 &PRIVATE (a_this)->prev_pos);
1921 cr_token_destroy (PRIVATE (a_this)->token_cache);
1922 PRIVATE (a_this)->token_cache = NULL;
1923 }
1924
1925 status = cr_input_consume_chars (PRIVATE (a_this)->input,
1926 a_char, &consumed);
1927 *a_nb_char = (glong) consumed;
1928 return status;
1929 }
1930
1931 enum CRStatus
cr_tknzr_set_cur_pos(CRTknzr * a_this,CRInputPos * a_pos)1932 cr_tknzr_set_cur_pos (CRTknzr * a_this, CRInputPos * a_pos)
1933 {
1934 g_return_val_if_fail (a_this && PRIVATE (a_this)
1935 && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
1936
1937 if (PRIVATE (a_this)->token_cache) {
1938 cr_token_destroy (PRIVATE (a_this)->token_cache);
1939 PRIVATE (a_this)->token_cache = NULL;
1940 }
1941
1942 return cr_input_set_cur_pos (PRIVATE (a_this)->input, a_pos);
1943 }
1944
1945 enum CRStatus
cr_tknzr_unget_token(CRTknzr * a_this,CRToken * a_token)1946 cr_tknzr_unget_token (CRTknzr * a_this, CRToken * a_token)
1947 {
1948 g_return_val_if_fail (a_this && PRIVATE (a_this)
1949 && PRIVATE (a_this)->token_cache == NULL,
1950 CR_BAD_PARAM_ERROR);
1951
1952 PRIVATE (a_this)->token_cache = a_token;
1953
1954 return CR_OK;
1955 }
1956
1957 /**
1958 *Returns the next token of the input stream.
1959 *This method is really central. Each parsing
1960 *method calls it.
1961 *@param a_this the current tokenizer.
1962 *@param a_tk out parameter. The returned token.
1963 *for the sake of mem leak avoidance, *a_tk must
1964 *be NULL.
1965 *@param CR_OK upon successfull completion, an error code
1966 *otherwise.
1967 */
1968 enum CRStatus
cr_tknzr_get_next_token(CRTknzr * a_this,CRToken ** a_tk)1969 cr_tknzr_get_next_token (CRTknzr * a_this, CRToken ** a_tk)
1970 {
1971 enum CRStatus status = CR_OK;
1972 CRToken *token = NULL;
1973 CRInputPos init_pos;
1974 guint32 next_char = 0;
1975 guchar next_bytes[4] = { 0 };
1976 gboolean reached_eof = FALSE;
1977 CRInput *input = NULL;
1978 CRString *str = NULL;
1979 CRRgb *rgb = NULL;
1980 CRParsingLocation location = {0} ;
1981
1982 g_return_val_if_fail (a_this && PRIVATE (a_this)
1983 && a_tk && *a_tk == NULL
1984 && PRIVATE (a_this)->input,
1985 CR_BAD_PARAM_ERROR);
1986
1987 if (PRIVATE (a_this)->token_cache) {
1988 *a_tk = PRIVATE (a_this)->token_cache;
1989 PRIVATE (a_this)->token_cache = NULL;
1990 return CR_OK;
1991 }
1992
1993 RECORD_INITIAL_POS (a_this, &init_pos);
1994
1995 status = cr_input_get_end_of_file
1996 (PRIVATE (a_this)->input, &reached_eof);
1997 ENSURE_PARSING_COND (status == CR_OK);
1998
1999 if (reached_eof == TRUE) {
2000 status = CR_END_OF_INPUT_ERROR;
2001 goto error;
2002 }
2003
2004 input = PRIVATE (a_this)->input;
2005
2006 PEEK_NEXT_CHAR (a_this, &next_char);
2007 token = cr_token_new ();
2008 ENSURE_PARSING_COND (token);
2009
2010 switch (next_char) {
2011 case '@':
2012 {
2013 if (BYTE (input, 2, NULL) == 'f'
2014 && BYTE (input, 3, NULL) == 'o'
2015 && BYTE (input, 4, NULL) == 'n'
2016 && BYTE (input, 5, NULL) == 't'
2017 && BYTE (input, 6, NULL) == '-'
2018 && BYTE (input, 7, NULL) == 'f'
2019 && BYTE (input, 8, NULL) == 'a'
2020 && BYTE (input, 9, NULL) == 'c'
2021 && BYTE (input, 10, NULL) == 'e') {
2022 SKIP_CHARS (a_this, 1);
2023 cr_tknzr_get_parsing_location
2024 (a_this, &location) ;
2025 SKIP_CHARS (a_this, 9);
2026 status = cr_token_set_font_face_sym (token);
2027 CHECK_PARSING_STATUS (status, TRUE);
2028 cr_parsing_location_copy (&token->location,
2029 &location) ;
2030 goto done;
2031 }
2032
2033 if (BYTE (input, 2, NULL) == 'c'
2034 && BYTE (input, 3, NULL) == 'h'
2035 && BYTE (input, 4, NULL) == 'a'
2036 && BYTE (input, 5, NULL) == 'r'
2037 && BYTE (input, 6, NULL) == 's'
2038 && BYTE (input, 7, NULL) == 'e'
2039 && BYTE (input, 8, NULL) == 't') {
2040 SKIP_CHARS (a_this, 1);
2041 cr_tknzr_get_parsing_location
2042 (a_this, &location) ;
2043 SKIP_CHARS (a_this, 7);
2044 status = cr_token_set_charset_sym (token);
2045 CHECK_PARSING_STATUS (status, TRUE);
2046 cr_parsing_location_copy (&token->location,
2047 &location) ;
2048 goto done;
2049 }
2050
2051 if (BYTE (input, 2, NULL) == 'i'
2052 && BYTE (input, 3, NULL) == 'm'
2053 && BYTE (input, 4, NULL) == 'p'
2054 && BYTE (input, 5, NULL) == 'o'
2055 && BYTE (input, 6, NULL) == 'r'
2056 && BYTE (input, 7, NULL) == 't') {
2057 SKIP_CHARS (a_this, 1);
2058 cr_tknzr_get_parsing_location
2059 (a_this, &location) ;
2060 SKIP_CHARS (a_this, 6);
2061 status = cr_token_set_import_sym (token);
2062 CHECK_PARSING_STATUS (status, TRUE);
2063 cr_parsing_location_copy (&token->location,
2064 &location) ;
2065 goto done;
2066 }
2067
2068 if (BYTE (input, 2, NULL) == 'm'
2069 && BYTE (input, 3, NULL) == 'e'
2070 && BYTE (input, 4, NULL) == 'd'
2071 && BYTE (input, 5, NULL) == 'i'
2072 && BYTE (input, 6, NULL) == 'a') {
2073 SKIP_CHARS (a_this, 1);
2074 cr_tknzr_get_parsing_location (a_this,
2075 &location) ;
2076 SKIP_CHARS (a_this, 5);
2077 status = cr_token_set_media_sym (token);
2078 CHECK_PARSING_STATUS (status, TRUE);
2079 cr_parsing_location_copy (&token->location,
2080 &location) ;
2081 goto done;
2082 }
2083
2084 if (BYTE (input, 2, NULL) == 'p'
2085 && BYTE (input, 3, NULL) == 'a'
2086 && BYTE (input, 4, NULL) == 'g'
2087 && BYTE (input, 5, NULL) == 'e') {
2088 SKIP_CHARS (a_this, 1);
2089 cr_tknzr_get_parsing_location (a_this,
2090 &location) ;
2091 SKIP_CHARS (a_this, 4);
2092 status = cr_token_set_page_sym (token);
2093 CHECK_PARSING_STATUS (status, TRUE);
2094 cr_parsing_location_copy (&token->location,
2095 &location) ;
2096 goto done;
2097 }
2098 status = cr_tknzr_parse_atkeyword (a_this, &str);
2099 if (status == CR_OK) {
2100 status = cr_token_set_atkeyword (token, str);
2101 CHECK_PARSING_STATUS (status, TRUE);
2102 if (str) {
2103 cr_parsing_location_copy (&token->location,
2104 &str->location) ;
2105 }
2106 goto done;
2107 }
2108 }
2109 break;
2110
2111 case 'u':
2112
2113 if (BYTE (input, 2, NULL) == 'r'
2114 && BYTE (input, 3, NULL) == 'l'
2115 && BYTE (input, 4, NULL) == '(') {
2116 CRString *str2 = NULL;
2117
2118 status = cr_tknzr_parse_uri (a_this, &str2);
2119 if (status == CR_OK) {
2120 status = cr_token_set_uri (token, str2);
2121 CHECK_PARSING_STATUS (status, TRUE);
2122 if (str2) {
2123 cr_parsing_location_copy (&token->location,
2124 &str2->location) ;
2125 }
2126 goto done;
2127 }
2128 }
2129 goto fallback;
2130 break;
2131
2132 case 'r':
2133 if (BYTE (input, 2, NULL) == 'g'
2134 && BYTE (input, 3, NULL) == 'b'
2135 && BYTE (input, 4, NULL) == '(') {
2136 status = cr_tknzr_parse_rgb (a_this, &rgb);
2137 if (status == CR_OK && rgb) {
2138 status = cr_token_set_rgb (token, rgb);
2139 CHECK_PARSING_STATUS (status, TRUE);
2140 if (rgb) {
2141 cr_parsing_location_copy (&token->location,
2142 &rgb->location) ;
2143 }
2144 rgb = NULL;
2145 goto done;
2146 }
2147
2148 }
2149 goto fallback;
2150 break;
2151
2152 case '<':
2153 if (BYTE (input, 2, NULL) == '!'
2154 && BYTE (input, 3, NULL) == '-'
2155 && BYTE (input, 4, NULL) == '-') {
2156 SKIP_CHARS (a_this, 1);
2157 cr_tknzr_get_parsing_location (a_this,
2158 &location) ;
2159 SKIP_CHARS (a_this, 3);
2160 status = cr_token_set_cdo (token);
2161 CHECK_PARSING_STATUS (status, TRUE);
2162 cr_parsing_location_copy (&token->location,
2163 &location) ;
2164 goto done;
2165 }
2166 break;
2167
2168 case '-':
2169 if (BYTE (input, 2, NULL) == '-'
2170 && BYTE (input, 3, NULL) == '>') {
2171 SKIP_CHARS (a_this, 1);
2172 cr_tknzr_get_parsing_location (a_this,
2173 &location) ;
2174 SKIP_CHARS (a_this, 2);
2175 status = cr_token_set_cdc (token);
2176 CHECK_PARSING_STATUS (status, TRUE);
2177 cr_parsing_location_copy (&token->location,
2178 &location) ;
2179 goto done;
2180 } else {
2181 status = cr_tknzr_parse_ident
2182 (a_this, &str);
2183 if (status == CR_OK) {
2184 cr_token_set_ident
2185 (token, str);
2186 if (str) {
2187 cr_parsing_location_copy (&token->location,
2188 &str->location) ;
2189 }
2190 goto done;
2191 } else {
2192 goto parse_number;
2193 }
2194 }
2195 break;
2196
2197 case '~':
2198 if (BYTE (input, 2, NULL) == '=') {
2199 SKIP_CHARS (a_this, 1);
2200 cr_tknzr_get_parsing_location (a_this,
2201 &location) ;
2202 SKIP_CHARS (a_this, 1);
2203 status = cr_token_set_includes (token);
2204 CHECK_PARSING_STATUS (status, TRUE);
2205 cr_parsing_location_copy (&token->location,
2206 &location) ;
2207 goto done;
2208 }
2209 break;
2210
2211 case '|':
2212 if (BYTE (input, 2, NULL) == '=') {
2213 SKIP_CHARS (a_this, 1);
2214 cr_tknzr_get_parsing_location (a_this,
2215 &location) ;
2216 SKIP_CHARS (a_this, 1);
2217 status = cr_token_set_dashmatch (token);
2218 CHECK_PARSING_STATUS (status, TRUE);
2219 cr_parsing_location_copy (&token->location,
2220 &location) ;
2221 goto done;
2222 }
2223 break;
2224
2225 case '/':
2226 if (BYTE (input, 2, NULL) == '*') {
2227 status = cr_tknzr_parse_comment (a_this, &str);
2228
2229 if (status == CR_OK) {
2230 status = cr_token_set_comment (token, str);
2231 str = NULL;
2232 CHECK_PARSING_STATUS (status, TRUE);
2233 if (str) {
2234 cr_parsing_location_copy (&token->location,
2235 &str->location) ;
2236 }
2237 goto done;
2238 }
2239 }
2240 break ;
2241
2242 case ';':
2243 SKIP_CHARS (a_this, 1);
2244 cr_tknzr_get_parsing_location (a_this,
2245 &location) ;
2246 status = cr_token_set_semicolon (token);
2247 CHECK_PARSING_STATUS (status, TRUE);
2248 cr_parsing_location_copy (&token->location,
2249 &location) ;
2250 goto done;
2251
2252 case '{':
2253 SKIP_CHARS (a_this, 1);
2254 cr_tknzr_get_parsing_location (a_this,
2255 &location) ;
2256 status = cr_token_set_cbo (token);
2257 CHECK_PARSING_STATUS (status, TRUE);
2258 cr_tknzr_get_parsing_location (a_this,
2259 &location) ;
2260 goto done;
2261
2262 case '}':
2263 SKIP_CHARS (a_this, 1);
2264 cr_tknzr_get_parsing_location (a_this,
2265 &location) ;
2266 status = cr_token_set_cbc (token);
2267 CHECK_PARSING_STATUS (status, TRUE);
2268 cr_parsing_location_copy (&token->location,
2269 &location) ;
2270 goto done;
2271
2272 case '(':
2273 SKIP_CHARS (a_this, 1);
2274 cr_tknzr_get_parsing_location (a_this,
2275 &location) ;
2276 status = cr_token_set_po (token);
2277 CHECK_PARSING_STATUS (status, TRUE);
2278 cr_parsing_location_copy (&token->location,
2279 &location) ;
2280 goto done;
2281
2282 case ')':
2283 SKIP_CHARS (a_this, 1);
2284 cr_tknzr_get_parsing_location (a_this,
2285 &location) ;
2286 status = cr_token_set_pc (token);
2287 CHECK_PARSING_STATUS (status, TRUE);
2288 cr_parsing_location_copy (&token->location,
2289 &location) ;
2290 goto done;
2291
2292 case '[':
2293 SKIP_CHARS (a_this, 1);
2294 cr_tknzr_get_parsing_location (a_this,
2295 &location) ;
2296 status = cr_token_set_bo (token);
2297 CHECK_PARSING_STATUS (status, TRUE);
2298 cr_parsing_location_copy (&token->location,
2299 &location) ;
2300 goto done;
2301
2302 case ']':
2303 SKIP_CHARS (a_this, 1);
2304 cr_tknzr_get_parsing_location (a_this,
2305 &location) ;
2306 status = cr_token_set_bc (token);
2307 CHECK_PARSING_STATUS (status, TRUE);
2308 cr_parsing_location_copy (&token->location,
2309 &location) ;
2310 goto done;
2311
2312 case ' ':
2313 case '\t':
2314 case '\n':
2315 case '\f':
2316 case '\r':
2317 {
2318 guchar *start = NULL,
2319 *end = NULL;
2320
2321 status = cr_tknzr_parse_w (a_this, &start,
2322 &end, &location);
2323 if (status == CR_OK) {
2324 status = cr_token_set_s (token);
2325 CHECK_PARSING_STATUS (status, TRUE);
2326 cr_tknzr_get_parsing_location (a_this,
2327 &location) ;
2328 goto done;
2329 }
2330 }
2331 break;
2332
2333 case '#':
2334 {
2335 status = cr_tknzr_parse_hash (a_this, &str);
2336 if (status == CR_OK && str) {
2337 status = cr_token_set_hash (token, str);
2338 CHECK_PARSING_STATUS (status, TRUE);
2339 if (str) {
2340 cr_parsing_location_copy (&token->location,
2341 &str->location) ;
2342 }
2343 str = NULL;
2344 goto done;
2345 }
2346 }
2347 break;
2348
2349 case '\'':
2350 case '"':
2351 status = cr_tknzr_parse_string (a_this, &str);
2352 if (status == CR_OK && str) {
2353 status = cr_token_set_string (token, str);
2354 CHECK_PARSING_STATUS (status, TRUE);
2355 if (str) {
2356 cr_parsing_location_copy (&token->location,
2357 &str->location) ;
2358 }
2359 str = NULL;
2360 goto done;
2361 }
2362 break;
2363
2364 case '!':
2365 status = cr_tknzr_parse_important (a_this, &location);
2366 if (status == CR_OK) {
2367 status = cr_token_set_important_sym (token);
2368 CHECK_PARSING_STATUS (status, TRUE);
2369 cr_parsing_location_copy (&token->location,
2370 &location) ;
2371 goto done;
2372 }
2373 break;
2374
2375 case '0':
2376 case '1':
2377 case '2':
2378 case '3':
2379 case '4':
2380 case '5':
2381 case '6':
2382 case '7':
2383 case '8':
2384 case '9':
2385 case '.':
2386 case '+':
2387 /* '-' case is handled separately above for --> comments */
2388 parse_number:
2389 {
2390 CRNum *num = NULL;
2391
2392 status = cr_tknzr_parse_num (a_this, &num);
2393 if (status == CR_OK && num) {
2394 next_bytes[0] = BYTE (input, 1, NULL);
2395 next_bytes[1] = BYTE (input, 2, NULL);
2396 next_bytes[2] = BYTE (input, 3, NULL);
2397 next_bytes[3] = BYTE (input, 4, NULL);
2398
2399 if (next_bytes[0] == 'e'
2400 && next_bytes[1] == 'm') {
2401 num->type = NUM_LENGTH_EM;
2402 status = cr_token_set_ems (token,
2403 num);
2404 num = NULL;
2405 SKIP_CHARS (a_this, 2);
2406 } else if (next_bytes[0] == 'e'
2407 && next_bytes[1] == 'x') {
2408 num->type = NUM_LENGTH_EX;
2409 status = cr_token_set_exs (token,
2410 num);
2411 num = NULL;
2412 SKIP_CHARS (a_this, 2);
2413 } else if (next_bytes[0] == 'p'
2414 && next_bytes[1] == 'x') {
2415 num->type = NUM_LENGTH_PX;
2416 status = cr_token_set_length
2417 (token, num, LENGTH_PX_ET);
2418 num = NULL;
2419 SKIP_CHARS (a_this, 2);
2420 } else if (next_bytes[0] == 'c'
2421 && next_bytes[1] == 'm') {
2422 num->type = NUM_LENGTH_CM;
2423 status = cr_token_set_length
2424 (token, num, LENGTH_CM_ET);
2425 num = NULL;
2426 SKIP_CHARS (a_this, 2);
2427 } else if (next_bytes[0] == 'm'
2428 && next_bytes[1] == 'm') {
2429 num->type = NUM_LENGTH_MM;
2430 status = cr_token_set_length
2431 (token, num, LENGTH_MM_ET);
2432 num = NULL;
2433 SKIP_CHARS (a_this, 2);
2434 } else if (next_bytes[0] == 'i'
2435 && next_bytes[1] == 'n') {
2436 num->type = NUM_LENGTH_IN;
2437 status = cr_token_set_length
2438 (token, num, LENGTH_IN_ET);
2439 num = NULL;
2440 SKIP_CHARS (a_this, 2);
2441 } else if (next_bytes[0] == 'p'
2442 && next_bytes[1] == 't') {
2443 num->type = NUM_LENGTH_PT;
2444 status = cr_token_set_length
2445 (token, num, LENGTH_PT_ET);
2446 num = NULL;
2447 SKIP_CHARS (a_this, 2);
2448 } else if (next_bytes[0] == 'p'
2449 && next_bytes[1] == 'c') {
2450 num->type = NUM_LENGTH_PC;
2451 status = cr_token_set_length
2452 (token, num, LENGTH_PC_ET);
2453 num = NULL;
2454 SKIP_CHARS (a_this, 2);
2455 } else if (next_bytes[0] == 'd'
2456 && next_bytes[1] == 'e'
2457 && next_bytes[2] == 'g') {
2458 num->type = NUM_ANGLE_DEG;
2459 status = cr_token_set_angle
2460 (token, num, ANGLE_DEG_ET);
2461 num = NULL;
2462 SKIP_CHARS (a_this, 3);
2463 } else if (next_bytes[0] == 'r'
2464 && next_bytes[1] == 'a'
2465 && next_bytes[2] == 'd') {
2466 num->type = NUM_ANGLE_RAD;
2467 status = cr_token_set_angle
2468 (token, num, ANGLE_RAD_ET);
2469 num = NULL;
2470 SKIP_CHARS (a_this, 3);
2471 } else if (next_bytes[0] == 'g'
2472 && next_bytes[1] == 'r'
2473 && next_bytes[2] == 'a'
2474 && next_bytes[3] == 'd') {
2475 num->type = NUM_ANGLE_GRAD;
2476 status = cr_token_set_angle
2477 (token, num, ANGLE_GRAD_ET);
2478 num = NULL;
2479 SKIP_CHARS (a_this, 4);
2480 } else if (next_bytes[0] == 'm'
2481 && next_bytes[1] == 's') {
2482 num->type = NUM_TIME_MS;
2483 status = cr_token_set_time
2484 (token, num, TIME_MS_ET);
2485 num = NULL;
2486 SKIP_CHARS (a_this, 2);
2487 } else if (next_bytes[0] == 's') {
2488 num->type = NUM_TIME_S;
2489 status = cr_token_set_time
2490 (token, num, TIME_S_ET);
2491 num = NULL;
2492 SKIP_CHARS (a_this, 1);
2493 } else if (next_bytes[0] == 'H'
2494 && next_bytes[1] == 'z') {
2495 num->type = NUM_FREQ_HZ;
2496 status = cr_token_set_freq
2497 (token, num, FREQ_HZ_ET);
2498 num = NULL;
2499 SKIP_CHARS (a_this, 2);
2500 } else if (next_bytes[0] == 'k'
2501 && next_bytes[1] == 'H'
2502 && next_bytes[2] == 'z') {
2503 num->type = NUM_FREQ_KHZ;
2504 status = cr_token_set_freq
2505 (token, num, FREQ_KHZ_ET);
2506 num = NULL;
2507 SKIP_CHARS (a_this, 3);
2508 } else if (next_bytes[0] == '%') {
2509 num->type = NUM_PERCENTAGE;
2510 status = cr_token_set_percentage
2511 (token, num);
2512 num = NULL;
2513 SKIP_CHARS (a_this, 1);
2514 } else {
2515 status = cr_tknzr_parse_ident (a_this,
2516 &str);
2517 if (status == CR_OK && str) {
2518 num->type = NUM_UNKNOWN_TYPE;
2519 status = cr_token_set_dimen
2520 (token, num, str);
2521 num = NULL;
2522 CHECK_PARSING_STATUS (status,
2523 TRUE);
2524 str = NULL;
2525 } else {
2526 status = cr_token_set_number
2527 (token, num);
2528 num = NULL;
2529 CHECK_PARSING_STATUS (status, CR_OK);
2530 str = NULL;
2531 }
2532 }
2533 if (token && token->u.num) {
2534 cr_parsing_location_copy (&token->location,
2535 &token->u.num->location) ;
2536 } else {
2537 status = CR_ERROR ;
2538 }
2539 goto done ;
2540 }
2541 }
2542 break;
2543
2544 default:
2545 fallback:
2546 /*process the fallback cases here */
2547
2548 if (next_char == '\\'
2549 || (cr_utils_is_nonascii (next_bytes[0]) == TRUE)
2550 || ((next_char >= 'a') && (next_char <= 'z'))
2551 || ((next_char >= 'A') && (next_char <= 'Z'))) {
2552 status = cr_tknzr_parse_ident (a_this, &str);
2553 if (status == CR_OK && str) {
2554 guint32 next_c = 0;
2555
2556 status = cr_input_peek_char
2557 (PRIVATE (a_this)->input, &next_c);
2558
2559 if (status == CR_OK && next_c == '(') {
2560
2561 SKIP_CHARS (a_this, 1);
2562 status = cr_token_set_function
2563 (token, str);
2564 CHECK_PARSING_STATUS (status, TRUE);
2565 /*ownership is transfered
2566 *to token by cr_token_set_function.
2567 */
2568 if (str) {
2569 cr_parsing_location_copy (&token->location,
2570 &str->location) ;
2571 }
2572 str = NULL;
2573 } else {
2574 status = cr_token_set_ident (token,
2575 str);
2576 CHECK_PARSING_STATUS (status, TRUE);
2577 if (str) {
2578 cr_parsing_location_copy (&token->location,
2579 &str->location) ;
2580 }
2581 str = NULL;
2582 }
2583 goto done;
2584 } else {
2585 if (str) {
2586 cr_string_destroy (str);
2587 str = NULL;
2588 }
2589 }
2590 }
2591 break;
2592 }
2593
2594 READ_NEXT_CHAR (a_this, &next_char);
2595 cr_tknzr_get_parsing_location (a_this,
2596 &location) ;
2597 status = cr_token_set_delim (token, next_char);
2598 CHECK_PARSING_STATUS (status, TRUE);
2599 cr_parsing_location_copy (&token->location,
2600 &location) ;
2601 done:
2602
2603 if (status == CR_OK && token) {
2604 *a_tk = token;
2605 /*
2606 *store the previous position input stream pos.
2607 */
2608 memmove (&PRIVATE (a_this)->prev_pos,
2609 &init_pos, sizeof (CRInputPos));
2610 return CR_OK;
2611 }
2612
2613 error:
2614 if (token) {
2615 cr_token_destroy (token);
2616 token = NULL;
2617 }
2618
2619 if (str) {
2620 cr_string_destroy (str);
2621 str = NULL;
2622 }
2623 cr_tknzr_set_cur_pos (a_this, &init_pos);
2624 return status;
2625
2626 }
2627
2628 enum CRStatus
cr_tknzr_parse_token(CRTknzr * a_this,enum CRTokenType a_type,enum CRTokenExtraType a_et,gpointer a_res,gpointer a_extra_res)2629 cr_tknzr_parse_token (CRTknzr * a_this, enum CRTokenType a_type,
2630 enum CRTokenExtraType a_et, gpointer a_res,
2631 gpointer a_extra_res)
2632 {
2633 enum CRStatus status = CR_OK;
2634 CRToken *token = NULL;
2635
2636 g_return_val_if_fail (a_this && PRIVATE (a_this)
2637 && PRIVATE (a_this)->input
2638 && a_res, CR_BAD_PARAM_ERROR);
2639
2640 status = cr_tknzr_get_next_token (a_this, &token);
2641 if (status != CR_OK)
2642 return status;
2643 if (token == NULL)
2644 return CR_PARSING_ERROR;
2645
2646 if (token->type == a_type) {
2647 switch (a_type) {
2648 case NO_TK:
2649 case S_TK:
2650 case CDO_TK:
2651 case CDC_TK:
2652 case INCLUDES_TK:
2653 case DASHMATCH_TK:
2654 case IMPORT_SYM_TK:
2655 case PAGE_SYM_TK:
2656 case MEDIA_SYM_TK:
2657 case FONT_FACE_SYM_TK:
2658 case CHARSET_SYM_TK:
2659 case IMPORTANT_SYM_TK:
2660 status = CR_OK;
2661 break;
2662
2663 case STRING_TK:
2664 case IDENT_TK:
2665 case HASH_TK:
2666 case ATKEYWORD_TK:
2667 case FUNCTION_TK:
2668 case COMMENT_TK:
2669 case URI_TK:
2670 *((CRString **) a_res) = token->u.str;
2671 token->u.str = NULL;
2672 status = CR_OK;
2673 break;
2674
2675 case EMS_TK:
2676 case EXS_TK:
2677 case PERCENTAGE_TK:
2678 case NUMBER_TK:
2679 *((CRNum **) a_res) = token->u.num;
2680 token->u.num = NULL;
2681 status = CR_OK;
2682 break;
2683
2684 case LENGTH_TK:
2685 case ANGLE_TK:
2686 case TIME_TK:
2687 case FREQ_TK:
2688 if (token->extra_type == a_et) {
2689 *((CRNum **) a_res) = token->u.num;
2690 token->u.num = NULL;
2691 status = CR_OK;
2692 }
2693 break;
2694
2695 case DIMEN_TK:
2696 *((CRNum **) a_res) = token->u.num;
2697 if (a_extra_res == NULL) {
2698 status = CR_BAD_PARAM_ERROR;
2699 goto error;
2700 }
2701
2702 *((CRString **) a_extra_res) = token->dimen;
2703 token->u.num = NULL;
2704 token->dimen = NULL;
2705 status = CR_OK;
2706 break;
2707
2708 case DELIM_TK:
2709 *((guint32 *) a_res) = token->u.unichar;
2710 status = CR_OK;
2711 break;
2712
2713 case UNICODERANGE_TK:
2714 default:
2715 status = CR_PARSING_ERROR;
2716 break;
2717 }
2718
2719 cr_token_destroy (token);
2720 token = NULL;
2721 } else {
2722 cr_tknzr_unget_token (a_this, token);
2723 token = NULL;
2724 status = CR_PARSING_ERROR;
2725 }
2726
2727 return status;
2728
2729 error:
2730
2731 if (token) {
2732 cr_tknzr_unget_token (a_this, token);
2733 token = NULL;
2734 }
2735
2736 return status;
2737 }
2738
2739 void
cr_tknzr_destroy(CRTknzr * a_this)2740 cr_tknzr_destroy (CRTknzr * a_this)
2741 {
2742 g_return_if_fail (a_this);
2743
2744 if (PRIVATE (a_this) && PRIVATE (a_this)->input) {
2745 if (cr_input_unref (PRIVATE (a_this)->input)
2746 == TRUE) {
2747 PRIVATE (a_this)->input = NULL;
2748 }
2749 }
2750
2751 if (PRIVATE (a_this)->token_cache) {
2752 cr_token_destroy (PRIVATE (a_this)->token_cache);
2753 PRIVATE (a_this)->token_cache = NULL;
2754 }
2755
2756 if (PRIVATE (a_this)) {
2757 g_free (PRIVATE (a_this));
2758 PRIVATE (a_this) = NULL;
2759 }
2760
2761 g_free (a_this);
2762 }
2763