Libcroco
cr-tknzr.c
Go to the documentation of this file.
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*/
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  */
46 
47  /**
48  *The position of the end of the previous token
49  *or char fetched.
50  */
52 
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
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,
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) {
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
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) {
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) {
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
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 
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
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,
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
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) {
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
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) {
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
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) {
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
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) {
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
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,
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) {
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
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,
946 
947  if (tmp_char == '-') {
948  READ_NEXT_CHAR (a_this, &tmp_char) ;
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) {
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
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,
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) {
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
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,
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  }
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
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,
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 
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
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) {
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
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
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,
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) {
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) {
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
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,
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 *
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 *
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 *
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
1661 {
1662  g_return_if_fail (a_this && PRIVATE (a_this));
1663 
1664  PRIVATE (a_this)->ref_count++;
1665 }
1666 
1667 gboolean
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
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
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
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
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
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
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,
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
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
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
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
1868  CRParsingLocation *a_loc)
1869 {
1870  g_return_val_if_fail (a_this
1871  && PRIVATE (a_this)
1872  && a_loc,
1874 
1876  (PRIVATE (a_this)->input, a_loc) ;
1877 }
1878 
1879 enum CRStatus
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
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
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
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
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,
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
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,
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);
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);
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);
2042  (a_this, &location) ;
2043  SKIP_CHARS (a_this, 7);
2044  status = cr_token_set_charset_sym (token);
2045  CHECK_PARSING_STATUS (status, TRUE);
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);
2059  (a_this, &location) ;
2060  SKIP_CHARS (a_this, 6);
2061  status = cr_token_set_import_sym (token);
2062  CHECK_PARSING_STATUS (status, TRUE);
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);
2075  &location) ;
2076  SKIP_CHARS (a_this, 5);
2077  status = cr_token_set_media_sym (token);
2078  CHECK_PARSING_STATUS (status, TRUE);
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);
2090  &location) ;
2091  SKIP_CHARS (a_this, 4);
2092  status = cr_token_set_page_sym (token);
2093  CHECK_PARSING_STATUS (status, TRUE);
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) {
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) {
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) {
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);
2158  &location) ;
2159  SKIP_CHARS (a_this, 3);
2160  status = cr_token_set_cdo (token);
2161  CHECK_PARSING_STATUS (status, TRUE);
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);
2173  &location) ;
2174  SKIP_CHARS (a_this, 2);
2175  status = cr_token_set_cdc (token);
2176  CHECK_PARSING_STATUS (status, TRUE);
2178  &location) ;
2179  goto done;
2180  } else {
2181  status = cr_tknzr_parse_ident
2182  (a_this, &str);
2183  if (status == CR_OK) {
2185  (token, str);
2186  if (str) {
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);
2201  &location) ;
2202  SKIP_CHARS (a_this, 1);
2203  status = cr_token_set_includes (token);
2204  CHECK_PARSING_STATUS (status, TRUE);
2206  &location) ;
2207  goto done;
2208  }
2209  break;
2210 
2211  case '|':
2212  if (BYTE (input, 2, NULL) == '=') {
2213  SKIP_CHARS (a_this, 1);
2215  &location) ;
2216  SKIP_CHARS (a_this, 1);
2217  status = cr_token_set_dashmatch (token);
2218  CHECK_PARSING_STATUS (status, TRUE);
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) {
2235  &str->location) ;
2236  }
2237  goto done;
2238  }
2239  }
2240  break ;
2241 
2242  case ';':
2243  SKIP_CHARS (a_this, 1);
2245  &location) ;
2246  status = cr_token_set_semicolon (token);
2247  CHECK_PARSING_STATUS (status, TRUE);
2249  &location) ;
2250  goto done;
2251 
2252  case '{':
2253  SKIP_CHARS (a_this, 1);
2255  &location) ;
2256  status = cr_token_set_cbo (token);
2257  CHECK_PARSING_STATUS (status, TRUE);
2259  &location) ;
2260  goto done;
2261 
2262  case '}':
2263  SKIP_CHARS (a_this, 1);
2265  &location) ;
2266  status = cr_token_set_cbc (token);
2267  CHECK_PARSING_STATUS (status, TRUE);
2269  &location) ;
2270  goto done;
2271 
2272  case '(':
2273  SKIP_CHARS (a_this, 1);
2275  &location) ;
2276  status = cr_token_set_po (token);
2277  CHECK_PARSING_STATUS (status, TRUE);
2279  &location) ;
2280  goto done;
2281 
2282  case ')':
2283  SKIP_CHARS (a_this, 1);
2285  &location) ;
2286  status = cr_token_set_pc (token);
2287  CHECK_PARSING_STATUS (status, TRUE);
2289  &location) ;
2290  goto done;
2291 
2292  case '[':
2293  SKIP_CHARS (a_this, 1);
2295  &location) ;
2296  status = cr_token_set_bo (token);
2297  CHECK_PARSING_STATUS (status, TRUE);
2299  &location) ;
2300  goto done;
2301 
2302  case ']':
2303  SKIP_CHARS (a_this, 1);
2305  &location) ;
2306  status = cr_token_set_bc (token);
2307  CHECK_PARSING_STATUS (status, TRUE);
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);
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) {
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) {
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);
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) {
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) {
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) {
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);
2596  &location) ;
2597  status = cr_token_set_delim (token, next_char);
2598  CHECK_PARSING_STATUS (status, TRUE);
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
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
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 }
enum CRStatus cr_tknzr_set_cur_pos(CRTknzr *a_this, CRInputPos *a_pos)
Definition: cr-tknzr.c:1932
void cr_tknzr_destroy(CRTknzr *a_this)
Definition: cr-tknzr.c:2740
enum CRStatus cr_input_get_parsing_location(CRInput const *a_this, CRParsingLocation *a_loc)
cr_input_get_parsing_location: @a_this: the current instance of CRInput @a_loc: the set parsing locat...
Definition: cr-input.c:1023
#define READ_NEXT_BYTE(a_tknzr, a_byte_ptr)
Reads a byte from the topmost parser input steam.
Definition: cr-tknzr.c:171
void cr_tknzr_ref(CRTknzr *a_this)
Definition: cr-tknzr.c:1660
guchar cr_tknzr_peek_byte2(CRTknzr *a_this, gulong a_offset, gboolean *a_eof)
Same as cr_tknzr_peek_byte() but this api returns the byte peeked.
Definition: cr-tknzr.c:1819
#define PRIVATE(obj)
Definition: cr-tknzr.c:63
enum CRStatus cr_input_read_char(CRInput *a_this, guint32 *a_char)
cr_input_read_char: @a_this: the current instance of CRInput.
Definition: cr-input.c:448
enum CRStatus cr_tknzr_get_next_token(CRTknzr *a_this, CRToken **a_tk)
Returns the next token of the input stream.
Definition: cr-tknzr.c:1969
CRTokenExtraType
Definition: cr-token.h:78
CRInputPos prev_pos
The position of the end of the previous token or char fetched.
Definition: cr-tknzr.c:51
enum CRStatus cr_token_set_ident(CRToken *a_this, CRString *a_ident)
Definition: cr-token.c:271
typedefG_BEGIN_DECLS struct _CRRgb CRRgb
Definition: cr-rgb.h:34
enum CRTokenType type
Definition: cr-token.h:103
enum CRStatus cr_token_set_important_sym(CRToken *a_this)
Definition: cr-token.c:388
glong cr_tknzr_get_nb_bytes_left(CRTknzr *a_this)
Gets the number of bytes left in the topmost input stream associated to this parser.
Definition: cr-tknzr.c:1834
#define READ_NEXT_CHAR(a_tknzr, to_char)
Reads the next char from the input stream of the current parser.
Definition: cr-tknzr.c:113
CRNum * num
Definition: cr-token.h:111
CRString * str
Definition: cr-token.h:109
enum CRStatus cr_tknzr_get_input(CRTknzr *a_this, CRInput **a_input)
Definition: cr-tknzr.c:1701
enum CRStatus cr_token_set_import_sym(CRToken *a_this)
Definition: cr-token.c:319
enum CRStatus cr_tknzr_peek_char(CRTknzr *a_this, guint32 *a_char)
Peeks a char from the parser input stream.
Definition: cr-tknzr.c:1765
enum CRStatus cr_tknzr_consume_chars(CRTknzr *a_this, guint32 a_char, glong *a_nb_char)
Definition: cr-tknzr.c:1911
enum CRStatus cr_token_set_bc(CRToken *a_this)
Definition: cr-token.c:613
enum CRStatus cr_token_set_exs(CRToken *a_this, CRNum *a_num)
Definition: cr-token.c:407
enum CRStatus cr_token_set_semicolon(CRToken *a_this)
Definition: cr-token.c:541
enum CRStatus cr_token_set_length(CRToken *a_this, CRNum *a_num, enum CRTokenExtraType a_et)
Definition: cr-token.c:417
CRTknzr * cr_tknzr_new_from_uri(const guchar *a_file_uri, enum CREncoding a_enc)
Definition: cr-tknzr.c:1645
enum CRStatus cr_tknzr_get_parsing_location(CRTknzr *a_this, CRParsingLocation *a_loc)
Definition: cr-tknzr.c:1867
enum CRStatus cr_tknzr_read_byte(CRTknzr *a_this, guchar *a_byte)
Reads the next byte from the parser input stream.
Definition: cr-tknzr.c:1724
void cr_string_destroy(CRString *a_this)
Definition: cr-string.c:159
CRToken * token_cache
A cache where tknzr_unget_token() puts back the token.
Definition: cr-tknzr.c:45
enum CRStatus cr_tknzr_get_cur_pos(CRTknzr *a_this, CRInputPos *a_pos)
Definition: cr-tknzr.c:1850
#define ENSURE_PARSING_COND(condition)
Tests the condition and if it is false, sets status to "CR_PARSING_ERROR" and goto the 'error' label.
Definition: cr-tknzr.c:210
CREncoding
Encoding values.
Definition: cr-utils.h:84
enum CRStatus cr_input_peek_byte(CRInput const *a_this, enum CRSeekPos a_origin, gulong a_offset, guchar *a_byte)
cr_input_peek_byte: @a_this: the current instance of CRInput.
Definition: cr-input.c:804
This class abstracts a css2 token.
Definition: cr-token.h:101
void cr_num_destroy(CRNum *a_this)
cr_num_destroy: @a_this: the this pointer of the current instance of CRNum.
Definition: cr-num.c:308
enum CRStatus cr_input_get_cur_byte_addr(CRInput *a_this, guchar **a_offset)
cr_input_get_cur_byte_addr: @a_this: the current input stream @a_offset: out parameter.
Definition: cr-input.c:908
enum CRStatus cr_token_set_function(CRToken *a_this, CRString *a_fun_name)
Definition: cr-token.c:283
CRStatus
The status type returned by the methods of the croco library.
Definition: cr-utils.h:43
glong ref_count
The reference count of the current instance of CRTknzr.
Definition: cr-tknzr.c:60
enum CRStatus cr_token_set_rgb(CRToken *a_this, CRRgb *a_rgb)
Definition: cr-token.c:307
typedefG_BEGIN_DECLS struct _CRDocHandler CRDocHandler
enum CRStatus cr_tknzr_peek_byte(CRTknzr *a_this, gulong a_offset, guchar *a_byte)
Peeks a byte ahead at a given postion in the parser input stream.
Definition: cr-tknzr.c:1791
CRString * cr_string_new(void)
Instanciates a CRString.
Definition: cr-string.c:33
The CRInput class provides the abstraction of an utf8-encoded character stream.
Definition: cr-input.h:47
enum CRStatus cr_input_consume_chars(CRInput *a_this, guint32 a_char, gulong *a_nb_char)
cr_input_consume_chars: @a_this: the this pointer of the current instance of CRInput.
Definition: cr-input.c:663
CRRgb * cr_rgb_new_with_vals(gulong a_red, gulong a_green, gulong a_blue, gboolean a_is_percentage)
cr_rgb_new_with_vals: @a_red: the red component of the color.
Definition: cr-rgb.c:221
enum CRStatus cr_tknzr_get_cur_byte_addr(CRTknzr *a_this, guchar **a_addr)
Definition: cr-tknzr.c:1880
enum CRStatus cr_tknzr_parse_token(CRTknzr *a_this, enum CRTokenType a_type, enum CRTokenExtraType a_et, gpointer a_res, gpointer a_extra_res)
Definition: cr-tknzr.c:2629
union _CRToken::@4 u
Definition: cr-utils.h:44
CRToken * cr_token_new(void)
Default constructor of the CRToken class.
Definition: cr-token.c:134
CRSeekPos
Values used by cr_input_seek_position() ;.
Definition: cr-utils.h:75
#define RECORD_CUR_BYTE_ADDR(a_tknzr, a_addr)
Gets the address of the current byte inside the parser input.
Definition: cr-tknzr.c:139
enum CRStatus cr_token_set_includes(CRToken *a_this)
Sets the type of the current instance of CRToken to INCLUDES_TK (INCLUDES as said by the css2 spec).
Definition: cr-token.c:215
CRString * dimen
Definition: cr-token.h:115
#define BYTE(a_input, a_n, a_eof)
Definition: cr-tknzr.c:161
enum CRStatus cr_token_set_atkeyword(CRToken *a_this, CRString *a_atname)
Definition: cr-token.c:377
typedefG_BEGIN_DECLS struct _CRTknzr CRTknzr
Definition: cr-tknzr.h:40
enum CRStatus cr_input_read_byte(CRInput *a_this, guchar *a_byte)
cr_input_read_byte: @a_this: the current instance of CRInput.
Definition: cr-input.c:405
enum CRStatus cr_token_set_hash(CRToken *a_this, CRString *a_hash)
Definition: cr-token.c:295
enum CRStatus cr_token_set_page_sym(CRToken *a_this)
Definition: cr-token.c:331
enum CRStatus cr_tknzr_seek_index(CRTknzr *a_this, enum CRSeekPos a_origin, gint a_pos)
Definition: cr-tknzr.c:1895
enum CRStatus cr_token_set_freq(CRToken *a_this, CRNum *a_num, enum CRTokenExtraType a_et)
Definition: cr-token.c:462
CRTknzr * cr_tknzr_new_from_buf(guchar *a_buf, gulong a_len, enum CREncoding a_enc, gboolean a_free_at_destroy)
Definition: cr-tknzr.c:1627
typedefG_BEGIN_DECLS struct _CRString CRString
Definition: cr-string.h:37
enum CRStatus cr_input_get_end_of_file(CRInput const *a_this, gboolean *a_eof)
cr_input_get_end_of_file: @a_this: the current instance of CRInput.
Definition: cr-input.c:1116
enum CRStatus cr_token_set_time(CRToken *a_this, CRNum *a_num, enum CRTokenExtraType a_et)
Definition: cr-token.c:447
guint32 unichar
Definition: cr-token.h:112
#define PEEK_NEXT_CHAR(a_tknzr, a_to_char)
Peeks the next char from the input stream of the current tokenizer.
Definition: cr-tknzr.c:99
gboolean cr_utils_is_nonascii(guint32 a_char)
Returns true if the character is a nonascii character (as defined in the css spec chap 4....
Definition: cr-utils.c:1244
#define SKIP_CHARS(a_tknzr, a_nb_chars)
Skip utf8 encoded characters.
Definition: cr-tknzr.c:196
The declaration of the #CRDocumentHandler class.
enum CRStatus cr_token_set_s(CRToken *a_this)
Sets the type of curren instance of CRToken to 'S_TK' (S in the css2 spec)
Definition: cr-token.c:158
CRParsingLocation location
Definition: cr-token.h:116
#define RECORD_INITIAL_POS(a_tknzr, a_pos)
Gets information about the current position in the input of the parser.
Definition: cr-tknzr.c:127
enum CRStatus cr_tknzr_unget_token(CRTknzr *a_this, CRToken *a_token)
Definition: cr-tknzr.c:1946
CRInput * cr_input_new_from_uri(const gchar *a_file_uri, enum CREncoding a_enc)
cr_input_new_from_uri: @a_file_uri: the file to create *the input stream from.
Definition: cr-input.c:196
CRNumType
The different types of numbers.
Definition: cr-num.h:54
enum CRStatus cr_token_set_cdc(CRToken *a_this)
Sets the type of the current token to CDC_TK (CDC as said by the css2 spec).
Definition: cr-token.c:196
enum CRStatus cr_input_seek_index(CRInput *a_this, enum CRSeekPos a_origin, gint a_pos)
cr_input_seek_index: @a_this: the current instance of CRInput.
Definition: cr-input.c:940
Definition: cr-token.h:39
CRTokenType
Definition: cr-token.h:36
enum CRStatus cr_token_set_cdo(CRToken *a_this)
Sets the type of the current instance of CRToken to 'CDO_TK' (CDO as said by the css2 spec)
Definition: cr-token.c:177
enum CRStatus cr_token_set_dashmatch(CRToken *a_this)
Sets the type of the current instance of CRToken to DASHMATCH_TK (DASHMATCH as said by the css2 spec)...
Definition: cr-token.c:234
enum CRStatus cr_token_set_cbo(CRToken *a_this)
Definition: cr-token.c:553
CRParsingLocation location
Definition: cr-num.h:94
enum CRStatus cr_input_consume_white_spaces(CRInput *a_this, gulong *a_nb_chars)
cr_input_consume_white_spaces: @a_this: the "this pointer" of the current instance of CRInput.
Definition: cr-input.c:704
enum CRStatus cr_token_set_media_sym(CRToken *a_this)
Definition: cr-token.c:343
#define CHECK_PARSING_STATUS(status, is_exception)
Checks if 'status' equals CR_OK.
Definition: cr-tknzr.c:80
enum CRStatus cr_token_set_delim(CRToken *a_this, guint32 a_char)
Definition: cr-token.c:528
enum CRStatus cr_input_set_cur_pos(CRInput *a_this, CRInputPos const *a_pos)
cr_input_set_cur_pos: @a_this: the "this pointer" of the current instance of CRInput.
Definition: cr-input.c:1179
CRInput * cr_input_new_from_buf(guchar *a_buf, gulong a_len, enum CREncoding a_enc, gboolean a_free_buf)
cr_input_new_from_buf: @a_buf: the memory buffer to create the input stream from.
Definition: cr-input.c:129
An abstraction of a number (num) as defined in the css2 spec.
Definition: cr-num.h:90
CRNum * cr_num_new_with_val(gdouble a_val, enum CRNumType a_type)
cr_num_new_with_val: @a_val: the numerical value of the number.
Definition: cr-num.c:71
The declaration of the CRTknzr (tokenizer) class.
Definition: cr-token.h:38
enum CRTokenExtraType extra_type
Definition: cr-token.h:104
CRTknzr * cr_tknzr_new(CRInput *a_input)
Definition: cr-tknzr.c:1595
enum CRStatus cr_token_set_string(CRToken *a_this, CRString *a_str)
Definition: cr-token.c:257
gboolean cr_tknzr_unref(CRTknzr *a_this)
Definition: cr-tknzr.c:1668
gdouble val
Definition: cr-num.h:93
enum CRStatus cr_input_peek_char(CRInput const *a_this, guint32 *a_char)
cr_input_peek_char: @a_this: the current instance of CRInput.
Definition: cr-input.c:755
enum CRStatus cr_token_set_dimen(CRToken *a_this, CRNum *a_num, CRString *a_dim)
Definition: cr-token.c:477
enum CRStatus cr_token_set_ems(CRToken *a_this, CRNum *a_num)
Definition: cr-token.c:397
enum CRStatus cr_input_get_cur_pos(CRInput const *a_this, CRInputPos *a_pos)
cr_input_get_cur_pos: @a_this: the current instance of CRInput.
Definition: cr-input.c:995
#define IS_NUM(a_char)
return TRUE if the character is a number ([0-9]), FALSE otherwise
Definition: cr-tknzr.c:69
enum CRStatus cr_tknzr_read_char(CRTknzr *a_this, guint32 *a_char)
Reads the next char from the parser input stream.
Definition: cr-tknzr.c:1740
enum CRStatus cr_token_set_cbc(CRToken *a_this)
Definition: cr-token.c:565
enum CRStatus cr_token_set_charset_sym(CRToken *a_this)
Definition: cr-token.c:366
enum CRStatus cr_tknzr_set_input(CRTknzr *a_this, CRInput *a_input)
Definition: cr-tknzr.c:1685
enum CRStatus cr_token_set_pc(CRToken *a_this)
Definition: cr-token.c:589
enum CRStatus cr_token_set_bo(CRToken *a_this)
Definition: cr-token.c:601
enum CRStatus cr_token_set_comment(CRToken *a_this, CRString *a_str)
Definition: cr-token.c:246
enum CRStatus cr_parsing_location_copy(CRParsingLocation *a_to, CRParsingLocation const *a_from)
cr_parsing_location_copy: @a_to: the destination of the copy.
gboolean cr_utils_is_white_space(guint32 a_char)
Returns TRUE if a_char is a white space as defined in the css spec in chap 4.1.1.
Definition: cr-utils.c:1181
#define PEEK_BYTE(a_tknzr, a_offset, a_byte_ptr)
Peeks a byte from the topmost parser input at a given offset from the current position.
Definition: cr-tknzr.c:155
#define SKIP_BYTES(a_tknzr, a_nb_bytes)
Skips a given number of byte in the topmost parser input.
Definition: cr-tknzr.c:184
enum CRNumType type
Definition: cr-num.h:92
enum CRStatus cr_token_set_font_face_sym(CRToken *a_this)
Definition: cr-token.c:355
enum CRStatus cr_token_set_number(CRToken *a_this, CRNum *a_num)
Definition: cr-token.c:503
gboolean cr_input_unref(CRInput *a_this)
cr_input_unref: @a_this: the current instance of CRInput.
Definition: cr-input.c:327
CRDocHandler * sac_handler
Definition: cr-tknzr.c:53
guchar cr_input_peek_byte2(CRInput const *a_this, gulong a_offset, gboolean *a_eof)
cr_input_peek_byte2: @a_this: the current byte input stream.
Definition: cr-input.c:856
void cr_token_destroy(CRToken *a_this)
The destructor of the CRToken class.
Definition: cr-token.c:629
CRInput * input
The parser input stream of bytes.
Definition: cr-tknzr.c:36
glong cr_input_get_nb_bytes_left(CRInput const *a_this)
cr_input_get_nb_bytes_left: @a_this: the current instance of CRInput.
Definition: cr-input.c:376
enum CRStatus cr_token_set_angle(CRToken *a_this, CRNum *a_num, enum CRTokenExtraType a_et)
Definition: cr-token.c:432
enum CRStatus cr_token_set_percentage(CRToken *a_this, CRNum *a_num)
Definition: cr-token.c:490
#define cr_utils_trace_info(a_msg)
Traces an info message.
Definition: cr-utils.h:127
enum CRStatus cr_token_set_uri(CRToken *a_this, CRString *a_uri)
Definition: cr-token.c:515
enum CRStatus cr_token_set_po(CRToken *a_this)
Definition: cr-token.c:577
void cr_input_ref(CRInput *a_this)
cr_input_ref: @a_this: the current instance of CRInput.
Definition: cr-input.c:309