Libcroco
|
00001 /* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ 00002 00003 /* 00004 * This file is part of The Croco Library 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of version 2.1 of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public License 00016 * along with this program; if not, write to the Free Software 00017 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00018 * USA 00019 * 00020 * Author: Dodji Seketeli 00021 * See the COPYRIGHTS file for copyrights information. 00022 */ 00023 00024 /** 00025 *@file 00026 *The definition of the #CRTknzr (tokenizer) 00027 *class. 00028 */ 00029 00030 #include "string.h" 00031 #include "cr-tknzr.h" 00032 #include "cr-doc-handler.h" 00033 00034 struct _CRTknzrPriv { 00035 /**The parser input stream of bytes*/ 00036 CRInput *input; 00037 00038 /** 00039 *A cache where tknzr_unget_token() 00040 *puts back the token. tknzr_get_next_token() 00041 *first look in this cache, and if and 00042 *only if it's empty, fetches the next token 00043 *from the input stream. 00044 */ 00045 CRToken *token_cache; 00046 00047 /** 00048 *The position of the end of the previous token 00049 *or char fetched. 00050 */ 00051 CRInputPos prev_pos; 00052 00053 CRDocHandler *sac_handler; 00054 00055 /** 00056 *The reference count of the current instance 00057 *of #CRTknzr. Is manipulated by cr_tknzr_ref() 00058 *and cr_tknzr_unref(). 00059 */ 00060 glong ref_count; 00061 }; 00062 00063 #define PRIVATE(obj) ((obj)->priv) 00064 00065 /** 00066 *return TRUE if the character is a number ([0-9]), FALSE otherwise 00067 *@param a_char the char to test. 00068 */ 00069 #define IS_NUM(a_char) (((a_char) >= '0' && (a_char) <= '9')?TRUE:FALSE) 00070 00071 /** 00072 *Checks if 'status' equals CR_OK. If not, goto the 'error' label. 00073 * 00074 *@param status the status (of type enum CRStatus) to test. 00075 *@param is_exception if set to FALSE, the final status returned the 00076 *current function will be CR_PARSING_ERROR. If set to TRUE, the 00077 *current status will be the current value of the 'status' variable. 00078 * 00079 */ 00080 #define CHECK_PARSING_STATUS(status, is_exception) \ 00081 if ((status) != CR_OK) \ 00082 { \ 00083 if (is_exception == FALSE) \ 00084 { \ 00085 status = CR_PARSING_ERROR ; \ 00086 } \ 00087 goto error ; \ 00088 } 00089 00090 /** 00091 *Peeks the next char from the input stream of the current tokenizer. 00092 *invokes CHECK_PARSING_STATUS on the status returned by 00093 *cr_tknzr_input_peek_char(). 00094 * 00095 *@param the current instance of #CRTkzr. 00096 *@param to_char a pointer to the char where to store the 00097 *char peeked. 00098 */ 00099 #define PEEK_NEXT_CHAR(a_tknzr, a_to_char) \ 00100 {\ 00101 status = cr_tknzr_peek_char (a_tknzr, a_to_char) ; \ 00102 CHECK_PARSING_STATUS (status, TRUE) \ 00103 } 00104 00105 /** 00106 *Reads the next char from the input stream of the current parser. 00107 *In case of error, jumps to the "error:" label located in the 00108 *function where this macro is called. 00109 *@param parser the curent instance of #CRTknzr 00110 *@param to_char a pointer to the guint32 char where to store 00111 *the character read. 00112 */ 00113 #define READ_NEXT_CHAR(a_tknzr, to_char) \ 00114 status = cr_tknzr_read_char (a_tknzr, to_char) ;\ 00115 CHECK_PARSING_STATUS (status, TRUE) 00116 00117 /** 00118 *Gets information about the current position in 00119 *the input of the parser. 00120 *In case of failure, this macro returns from the 00121 *calling function and 00122 *returns a status code of type enum #CRStatus. 00123 *@param parser the current instance of #CRTknzr. 00124 *@param pos out parameter. A pointer to the position 00125 *inside the current parser input. Must 00126 */ 00127 #define RECORD_INITIAL_POS(a_tknzr, a_pos) \ 00128 status = cr_input_get_cur_pos (PRIVATE \ 00129 (a_tknzr)->input, a_pos) ; \ 00130 g_return_val_if_fail (status == CR_OK, status) 00131 00132 /** 00133 *Gets the address of the current byte inside the 00134 *parser input. 00135 *@param parser the current instance of #CRTknzr. 00136 *@param addr out parameter a pointer (guchar*) 00137 *to where the address must be put. 00138 */ 00139 #define RECORD_CUR_BYTE_ADDR(a_tknzr, a_addr) \ 00140 status = cr_input_get_cur_byte_addr \ 00141 (PRIVATE (a_tknzr)->input, a_addr) ; \ 00142 CHECK_PARSING_STATUS (status, TRUE) 00143 00144 /** 00145 *Peeks a byte from the topmost parser input at 00146 *a given offset from the current position. 00147 *If it fails, goto the "error:" label. 00148 * 00149 *@param a_parser the current instance of #CRTknzr. 00150 *@param a_offset the offset of the byte to peek, the 00151 *current byte having the offset '0'. 00152 *@param a_byte_ptr out parameter a pointer (guchar*) to 00153 *where the peeked char is to be stored. 00154 */ 00155 #define PEEK_BYTE(a_tknzr, a_offset, a_byte_ptr) \ 00156 status = cr_tknzr_peek_byte (a_tknzr, \ 00157 a_offset, \ 00158 a_byte_ptr) ; \ 00159 CHECK_PARSING_STATUS (status, TRUE) ; 00160 00161 #define BYTE(a_input, a_n, a_eof) \ 00162 cr_input_peek_byte2 (a_input, a_n, a_eof) 00163 00164 /** 00165 *Reads a byte from the topmost parser input 00166 *steam. 00167 *If it fails, goto the "error" label. 00168 *@param a_parser the current instance of #CRTknzr. 00169 *@param a_byte_ptr the guchar * where to put the read char. 00170 */ 00171 #define READ_NEXT_BYTE(a_tknzr, a_byte_ptr) \ 00172 status = \ 00173 cr_input_read_byte (PRIVATE (a_tknzr)->input, a_byte_ptr) ;\ 00174 CHECK_PARSING_STATUS (status, TRUE) ; 00175 00176 /** 00177 *Skips a given number of byte in the topmost 00178 *parser input. Don't update line and column number. 00179 *In case of error, jumps to the "error:" label 00180 *of the surrounding function. 00181 *@param a_parser the current instance of #CRTknzr. 00182 *@param a_nb_bytes the number of bytes to skip. 00183 */ 00184 #define SKIP_BYTES(a_tknzr, a_nb_bytes) \ 00185 status = cr_input_seek_index (PRIVATE (a_tknzr)->input, \ 00186 CR_SEEK_CUR, a_nb_bytes) ; \ 00187 CHECK_PARSING_STATUS (status, TRUE) ; 00188 00189 /** 00190 *Skip utf8 encoded characters. 00191 *Updates line and column numbers. 00192 *@param a_parser the current instance of #CRTknzr. 00193 *@param a_nb_chars the number of chars to skip. Must be of 00194 *type glong. 00195 */ 00196 #define SKIP_CHARS(a_tknzr, a_nb_chars) \ 00197 { \ 00198 glong nb_chars = a_nb_chars ; \ 00199 status = cr_input_consume_chars \ 00200 (PRIVATE (a_tknzr)->input,0, &nb_chars) ; \ 00201 CHECK_PARSING_STATUS (status, TRUE) ; \ 00202 } 00203 00204 /** 00205 *Tests the condition and if it is false, sets 00206 *status to "CR_PARSING_ERROR" and goto the 'error' 00207 *label. 00208 *@param condition the condition to test. 00209 */ 00210 #define ENSURE_PARSING_COND(condition) \ 00211 if (! (condition)) {status = CR_PARSING_ERROR; goto error ;} 00212 00213 static enum CRStatus cr_tknzr_parse_nl (CRTknzr * a_this, 00214 guchar ** a_start, 00215 guchar ** a_end, 00216 CRParsingLocation *a_location); 00217 00218 static enum CRStatus cr_tknzr_parse_w (CRTknzr * a_this, 00219 guchar ** a_start, 00220 guchar ** a_end, 00221 CRParsingLocation *a_location) ; 00222 00223 static enum CRStatus cr_tknzr_parse_unicode_escape (CRTknzr * a_this, 00224 guint32 * a_unicode, 00225 CRParsingLocation *a_location) ; 00226 00227 static enum CRStatus cr_tknzr_parse_escape (CRTknzr * a_this, 00228 guint32 * a_esc_code, 00229 CRParsingLocation *a_location); 00230 00231 static enum CRStatus cr_tknzr_parse_string (CRTknzr * a_this, 00232 CRString ** a_str); 00233 00234 static enum CRStatus cr_tknzr_parse_comment (CRTknzr * a_this, 00235 CRString ** a_comment); 00236 00237 static enum CRStatus cr_tknzr_parse_nmstart (CRTknzr * a_this, 00238 guint32 * a_char, 00239 CRParsingLocation *a_location); 00240 00241 static enum CRStatus cr_tknzr_parse_num (CRTknzr * a_this, 00242 CRNum ** a_num); 00243 00244 /********************************** 00245 *PRIVATE methods 00246 **********************************/ 00247 00248 /** 00249 *Parses a "w" as defined by the css spec at [4.1.1]: 00250 * w ::= [ \t\r\n\f]* 00251 * 00252 *@param a_this the current instance of #CRTknzr. 00253 *@param a_start out param. Upon successfull completion, points 00254 *to the beginning of the parsed white space, points to NULL otherwise. 00255 *Can also point to NULL is there is no white space actually. 00256 *@param a_end out param. Upon successfull completion, points 00257 *to the end of the parsed white space, points to NULL otherwise. 00258 *Can also point to NULL is there is no white space actually. 00259 */ 00260 static enum CRStatus 00261 cr_tknzr_parse_w (CRTknzr * a_this, 00262 guchar ** a_start, 00263 guchar ** a_end, 00264 CRParsingLocation *a_location) 00265 { 00266 guint32 cur_char = 0; 00267 CRInputPos init_pos; 00268 enum CRStatus status = CR_OK; 00269 00270 g_return_val_if_fail (a_this && PRIVATE (a_this) 00271 && PRIVATE (a_this)->input 00272 && a_start && a_end, 00273 CR_BAD_PARAM_ERROR); 00274 00275 RECORD_INITIAL_POS (a_this, &init_pos); 00276 00277 *a_start = NULL; 00278 *a_end = NULL; 00279 00280 READ_NEXT_CHAR (a_this, &cur_char); 00281 00282 if (cr_utils_is_white_space (cur_char) == FALSE) { 00283 status = CR_PARSING_ERROR; 00284 goto error; 00285 } 00286 if (a_location) { 00287 cr_tknzr_get_parsing_location (a_this, 00288 a_location) ; 00289 } 00290 RECORD_CUR_BYTE_ADDR (a_this, a_start); 00291 *a_end = *a_start; 00292 00293 for (;;) { 00294 gboolean is_eof = FALSE; 00295 00296 cr_input_get_end_of_file (PRIVATE (a_this)->input, &is_eof); 00297 if (is_eof) 00298 break; 00299 00300 status = cr_tknzr_peek_char (a_this, &cur_char); 00301 if (status == CR_END_OF_INPUT_ERROR) { 00302 status = CR_OK; 00303 break; 00304 } else if (status != CR_OK) { 00305 goto error; 00306 } 00307 00308 if (cr_utils_is_white_space (cur_char) == TRUE) { 00309 READ_NEXT_CHAR (a_this, &cur_char); 00310 RECORD_CUR_BYTE_ADDR (a_this, a_end); 00311 } else { 00312 break; 00313 } 00314 } 00315 00316 return CR_OK; 00317 00318 error: 00319 cr_tknzr_set_cur_pos (a_this, &init_pos); 00320 00321 return status; 00322 } 00323 00324 /** 00325 *Parses a newline as defined in the css2 spec: 00326 * nl ::= \n|\r\n|\r|\f 00327 * 00328 *@param a_this the "this pointer" of the current instance of #CRTknzr. 00329 *@param a_start a pointer to the first character of the successfully 00330 *parsed string. 00331 *@param a_end a pointer to the last character of the successfully parsed 00332 *string. 00333 *@result CR_OK uppon successfull completion, an error code otherwise. 00334 */ 00335 static enum CRStatus 00336 cr_tknzr_parse_nl (CRTknzr * a_this, 00337 guchar ** a_start, 00338 guchar ** a_end, 00339 CRParsingLocation *a_location) 00340 { 00341 CRInputPos init_pos; 00342 guchar next_chars[2] = { 0 }; 00343 enum CRStatus status = CR_PARSING_ERROR; 00344 00345 g_return_val_if_fail (a_this && PRIVATE (a_this) 00346 && a_start && a_end, CR_BAD_PARAM_ERROR); 00347 00348 RECORD_INITIAL_POS (a_this, &init_pos); 00349 00350 PEEK_BYTE (a_this, 1, &next_chars[0]); 00351 PEEK_BYTE (a_this, 2, &next_chars[1]); 00352 00353 if ((next_chars[0] == '\r' && next_chars[1] == '\n')) { 00354 SKIP_BYTES (a_this, 1); 00355 if (a_location) { 00356 cr_tknzr_get_parsing_location 00357 (a_this, a_location) ; 00358 } 00359 SKIP_CHARS (a_this, 1); 00360 00361 RECORD_CUR_BYTE_ADDR (a_this, a_end); 00362 00363 status = CR_OK; 00364 } else if (next_chars[0] == '\n' 00365 || next_chars[0] == '\r' || next_chars[0] == '\f') { 00366 SKIP_CHARS (a_this, 1); 00367 if (a_location) { 00368 cr_tknzr_get_parsing_location 00369 (a_this, a_location) ; 00370 } 00371 RECORD_CUR_BYTE_ADDR (a_this, a_start); 00372 *a_end = *a_start; 00373 status = CR_OK; 00374 } else { 00375 status = CR_PARSING_ERROR; 00376 goto error; 00377 } 00378 return CR_OK ; 00379 00380 error: 00381 cr_tknzr_set_cur_pos (a_this, &init_pos) ; 00382 return status; 00383 } 00384 00385 /** 00386 *Go ahead in the parser input, skipping all the spaces. 00387 *If the next char if not a white space, this function does nothing. 00388 *In any cases, it stops when it encounters a non white space character. 00389 * 00390 *@param a_this the current instance of #CRTknzr. 00391 *@return CR_OK upon successfull completion, an error code otherwise. 00392 */ 00393 static enum CRStatus 00394 cr_tknzr_try_to_skip_spaces (CRTknzr * a_this) 00395 { 00396 enum CRStatus status = CR_ERROR; 00397 guint32 cur_char = 0; 00398 00399 g_return_val_if_fail (a_this && PRIVATE (a_this) 00400 && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); 00401 00402 status = cr_input_peek_char (PRIVATE (a_this)->input, &cur_char); 00403 00404 if (status != CR_OK) { 00405 if (status == CR_END_OF_INPUT_ERROR) 00406 return CR_OK; 00407 return status; 00408 } 00409 00410 if (cr_utils_is_white_space (cur_char) == TRUE) { 00411 glong nb_chars = -1; /*consume all spaces */ 00412 00413 status = cr_input_consume_white_spaces 00414 (PRIVATE (a_this)->input, &nb_chars); 00415 } 00416 00417 return status; 00418 } 00419 00420 /** 00421 *Parses a "comment" as defined in the css spec at [4.1.1]: 00422 *COMMENT ::= \/\*[^*]*\*+([^/][^*]*\*+)*\/ . 00423 *This complex regexp is just to say that comments start 00424 *with the two chars '/''*' and ends with the two chars '*''/'. 00425 *It also means that comments cannot be nested. 00426 *So based on that, I've just tried to implement the parsing function 00427 *simply and in a straight forward manner. 00428 */ 00429 static enum CRStatus 00430 cr_tknzr_parse_comment (CRTknzr * a_this, 00431 CRString ** a_comment) 00432 { 00433 enum CRStatus status = CR_OK; 00434 CRInputPos init_pos; 00435 guint32 cur_char = 0, next_char= 0; 00436 CRString *comment = NULL; 00437 CRParsingLocation loc = {0} ; 00438 00439 g_return_val_if_fail (a_this && PRIVATE (a_this) 00440 && PRIVATE (a_this)->input, 00441 CR_BAD_PARAM_ERROR); 00442 00443 RECORD_INITIAL_POS (a_this, &init_pos); 00444 READ_NEXT_CHAR (a_this, &cur_char) ; 00445 ENSURE_PARSING_COND (cur_char == '/'); 00446 cr_tknzr_get_parsing_location (a_this, &loc) ; 00447 00448 READ_NEXT_CHAR (a_this, &cur_char); 00449 ENSURE_PARSING_COND (cur_char == '*'); 00450 comment = cr_string_new (); 00451 for (;;) { /* [^*]* */ 00452 PEEK_NEXT_CHAR (a_this, &next_char); 00453 if (next_char == '*') 00454 break; 00455 READ_NEXT_CHAR (a_this, &cur_char); 00456 g_string_append_unichar (comment->stryng, cur_char); 00457 } 00458 /* Stop condition: next_char == '*' */ 00459 for (;;) { /* \*+ */ 00460 READ_NEXT_CHAR(a_this, &cur_char); 00461 ENSURE_PARSING_COND (cur_char == '*'); 00462 g_string_append_unichar (comment->stryng, cur_char); 00463 PEEK_NEXT_CHAR (a_this, &next_char); 00464 if (next_char != '*') 00465 break; 00466 } 00467 /* Stop condition: next_char != '*' */ 00468 for (;;) { /* ([^/][^*]*\*+)* */ 00469 if (next_char == '/') 00470 break; 00471 READ_NEXT_CHAR(a_this, &cur_char); 00472 g_string_append_unichar (comment->stryng, cur_char); 00473 for (;;) { /* [^*]* */ 00474 PEEK_NEXT_CHAR (a_this, &next_char); 00475 if (next_char == '*') 00476 break; 00477 READ_NEXT_CHAR (a_this, &cur_char); 00478 g_string_append_unichar (comment->stryng, cur_char); 00479 } 00480 /* Stop condition: next_char = '*', no need to verify, because peek and read exit to error anyway */ 00481 for (;;) { /* \*+ */ 00482 READ_NEXT_CHAR(a_this, &cur_char); 00483 ENSURE_PARSING_COND (cur_char == '*'); 00484 g_string_append_unichar (comment->stryng, cur_char); 00485 PEEK_NEXT_CHAR (a_this, &next_char); 00486 if (next_char != '*') 00487 break; 00488 } 00489 /* Continue condition: next_char != '*' */ 00490 } 00491 /* Stop condition: next_char == '\/' */ 00492 READ_NEXT_CHAR(a_this, &cur_char); 00493 g_string_append_unichar (comment->stryng, cur_char); 00494 00495 if (status == CR_OK) { 00496 cr_parsing_location_copy (&comment->location, 00497 &loc) ; 00498 *a_comment = comment; 00499 return CR_OK; 00500 } 00501 error: 00502 00503 if (comment) { 00504 cr_string_destroy (comment); 00505 comment = NULL; 00506 } 00507 00508 cr_tknzr_set_cur_pos (a_this, &init_pos); 00509 00510 return status; 00511 } 00512 00513 /** 00514 *Parses an 'unicode' escape sequence defined 00515 *in css spec at chap 4.1.1: 00516 *unicode ::= \\[0-9a-f]{1,6}[ \n\r\t\f]? 00517 *@param a_this the current instance of #CRTknzr. 00518 *@param a_start out parameter. A pointer to the start 00519 *of the unicode escape sequence. Must *NOT* be deleted by 00520 *the caller. 00521 *@param a_end out parameter. A pointer to the last character 00522 *of the unicode escape sequence. Must *NOT* be deleted by the caller. 00523 *@return CR_OK if parsing succeded, an error code otherwise. 00524 *Error code can be either CR_PARSING_ERROR if the string 00525 *parsed just doesn't 00526 *respect the production or another error if a 00527 *lower level error occured. 00528 */ 00529 static enum CRStatus 00530 cr_tknzr_parse_unicode_escape (CRTknzr * a_this, 00531 guint32 * a_unicode, 00532 CRParsingLocation *a_location) 00533 { 00534 guint32 cur_char; 00535 CRInputPos init_pos; 00536 glong occur = 0; 00537 guint32 unicode = 0; 00538 guchar *tmp_char_ptr1 = NULL, 00539 *tmp_char_ptr2 = NULL; 00540 enum CRStatus status = CR_OK; 00541 00542 g_return_val_if_fail (a_this && PRIVATE (a_this) 00543 && a_unicode, CR_BAD_PARAM_ERROR); 00544 00545 /*first, let's backup the current position pointer */ 00546 RECORD_INITIAL_POS (a_this, &init_pos); 00547 00548 READ_NEXT_CHAR (a_this, &cur_char); 00549 00550 if (cur_char != '\\') { 00551 status = CR_PARSING_ERROR; 00552 goto error; 00553 } 00554 if (a_location) { 00555 cr_tknzr_get_parsing_location 00556 (a_this, a_location) ; 00557 } 00558 PEEK_NEXT_CHAR (a_this, &cur_char); 00559 00560 for (occur = 0, unicode = 0; ((cur_char >= '0' && cur_char <= '9') 00561 || (cur_char >= 'a' && cur_char <= 'f') 00562 || (cur_char >= 'A' && cur_char <= 'F')) 00563 && occur < 6; occur++) { 00564 gint cur_char_val = 0; 00565 00566 READ_NEXT_CHAR (a_this, &cur_char); 00567 00568 if ((cur_char >= '0' && cur_char <= '9')) { 00569 cur_char_val = (cur_char - '0'); 00570 } else if ((cur_char >= 'a' && cur_char <= 'f')) { 00571 cur_char_val = 10 + (cur_char - 'a'); 00572 } else if ((cur_char >= 'A' && cur_char <= 'F')) { 00573 cur_char_val = 10 + (cur_char - 'A'); 00574 } 00575 00576 unicode = unicode * 16 + cur_char_val; 00577 00578 PEEK_NEXT_CHAR (a_this, &cur_char); 00579 } 00580 00581 /* Eat a whitespace if possible. */ 00582 cr_tknzr_parse_w (a_this, &tmp_char_ptr1, 00583 &tmp_char_ptr2, NULL); 00584 *a_unicode = unicode; 00585 return CR_OK; 00586 00587 error: 00588 /* 00589 *restore the initial position pointer backuped at 00590 *the beginning of this function. 00591 */ 00592 cr_tknzr_set_cur_pos (a_this, &init_pos); 00593 00594 return status; 00595 } 00596 00597 /** 00598 *parses an escape sequence as defined by the css spec: 00599 *escape ::= {unicode}|\\[ -~\200-\4177777] 00600 *@param a_this the current instance of #CRTknzr . 00601 */ 00602 static enum CRStatus 00603 cr_tknzr_parse_escape (CRTknzr * a_this, guint32 * a_esc_code, 00604 CRParsingLocation *a_location) 00605 { 00606 enum CRStatus status = CR_OK; 00607 guint32 cur_char = 0; 00608 CRInputPos init_pos; 00609 guchar next_chars[2]; 00610 00611 g_return_val_if_fail (a_this && PRIVATE (a_this) 00612 && a_esc_code, CR_BAD_PARAM_ERROR); 00613 00614 RECORD_INITIAL_POS (a_this, &init_pos); 00615 00616 PEEK_BYTE (a_this, 1, &next_chars[0]); 00617 PEEK_BYTE (a_this, 2, &next_chars[1]); 00618 00619 if (next_chars[0] != '\\') { 00620 status = CR_PARSING_ERROR; 00621 goto error; 00622 } 00623 00624 if ((next_chars[1] >= '0' && next_chars[1] <= '9') 00625 || (next_chars[1] >= 'a' && next_chars[1] <= 'f') 00626 || (next_chars[1] >= 'A' && next_chars[1] <= 'F')) { 00627 status = cr_tknzr_parse_unicode_escape (a_this, a_esc_code, 00628 a_location); 00629 } else { 00630 /*consume the '\' char */ 00631 READ_NEXT_CHAR (a_this, &cur_char); 00632 if (a_location) { 00633 cr_tknzr_get_parsing_location (a_this, 00634 a_location) ; 00635 } 00636 /*then read the char after the '\' */ 00637 READ_NEXT_CHAR (a_this, &cur_char); 00638 00639 if (cur_char != ' ' && (cur_char < 200 || cur_char > 4177777)) { 00640 status = CR_PARSING_ERROR; 00641 goto error; 00642 } 00643 *a_esc_code = cur_char; 00644 00645 } 00646 if (status == CR_OK) { 00647 return CR_OK; 00648 } 00649 error: 00650 cr_tknzr_set_cur_pos (a_this, &init_pos); 00651 return status; 00652 } 00653 00654 /** 00655 *Parses a string type as defined in css spec [4.1.1]: 00656 * 00657 *string ::= {string1}|{string2} 00658 *string1 ::= \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\" 00659 *string2 ::= \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\' 00660 * 00661 *@param a_this the current instance of #CRTknzr. 00662 *@param a_start out parameter. Upon successfull completion, 00663 *points to the beginning of the string, points to an undefined value 00664 *otherwise. 00665 *@param a_end out parameter. Upon successfull completion, points to 00666 *the beginning of the string, points to an undefined value otherwise. 00667 *@return CR_OK upon successfull completion, an error code otherwise. 00668 */ 00669 static enum CRStatus 00670 cr_tknzr_parse_string (CRTknzr * a_this, CRString ** a_str) 00671 { 00672 guint32 cur_char = 0, 00673 delim = 0; 00674 CRInputPos init_pos; 00675 enum CRStatus status = CR_OK; 00676 CRString *str = NULL; 00677 00678 g_return_val_if_fail (a_this && PRIVATE (a_this) 00679 && PRIVATE (a_this)->input 00680 && a_str, CR_BAD_PARAM_ERROR); 00681 00682 RECORD_INITIAL_POS (a_this, &init_pos); 00683 READ_NEXT_CHAR (a_this, &cur_char); 00684 00685 if (cur_char == '"') 00686 delim = '"'; 00687 else if (cur_char == '\'') 00688 delim = '\''; 00689 else { 00690 status = CR_PARSING_ERROR; 00691 goto error; 00692 } 00693 str = cr_string_new (); 00694 if (str) { 00695 cr_tknzr_get_parsing_location 00696 (a_this, &str->location) ; 00697 } 00698 for (;;) { 00699 guchar next_chars[2] = { 0 }; 00700 00701 PEEK_BYTE (a_this, 1, &next_chars[0]); 00702 PEEK_BYTE (a_this, 2, &next_chars[1]); 00703 00704 if (next_chars[0] == '\\') { 00705 guchar *tmp_char_ptr1 = NULL, 00706 *tmp_char_ptr2 = NULL; 00707 guint32 esc_code = 0; 00708 00709 if (next_chars[1] == '\'' || next_chars[1] == '"') { 00710 g_string_append_unichar (str->stryng, 00711 next_chars[1]); 00712 SKIP_BYTES (a_this, 2); 00713 status = CR_OK; 00714 } else { 00715 status = cr_tknzr_parse_escape 00716 (a_this, &esc_code, NULL); 00717 00718 if (status == CR_OK) { 00719 g_string_append_unichar 00720 (str->stryng, 00721 esc_code); 00722 } 00723 } 00724 00725 if (status != CR_OK) { 00726 /* 00727 *consume the '\' char, and try to parse 00728 *a newline. 00729 */ 00730 READ_NEXT_CHAR (a_this, &cur_char); 00731 00732 status = cr_tknzr_parse_nl 00733 (a_this, &tmp_char_ptr1, 00734 &tmp_char_ptr2, NULL); 00735 } 00736 00737 CHECK_PARSING_STATUS (status, FALSE); 00738 } else if (strchr ("\t !#$%&", next_chars[0]) 00739 || (next_chars[0] >= '(' && next_chars[0] <= '~')) { 00740 READ_NEXT_CHAR (a_this, &cur_char); 00741 g_string_append_unichar (str->stryng, 00742 cur_char); 00743 status = CR_OK; 00744 } 00745 00746 else if (cr_utils_is_nonascii (next_chars[0])) { 00747 READ_NEXT_CHAR (a_this, &cur_char); 00748 g_string_append_unichar (str->stryng, cur_char); 00749 } else if (next_chars[0] == delim) { 00750 READ_NEXT_CHAR (a_this, &cur_char); 00751 break; 00752 } else { 00753 status = CR_PARSING_ERROR; 00754 goto error; 00755 } 00756 } 00757 00758 if (status == CR_OK) { 00759 if (*a_str == NULL) { 00760 *a_str = str; 00761 str = NULL; 00762 } else { 00763 (*a_str)->stryng = g_string_append_len 00764 ((*a_str)->stryng, 00765 str->stryng->str, 00766 str->stryng->len); 00767 cr_string_destroy (str); 00768 } 00769 return CR_OK; 00770 } 00771 00772 error: 00773 00774 if (str) { 00775 cr_string_destroy (str) ; 00776 str = NULL; 00777 } 00778 cr_tknzr_set_cur_pos (a_this, &init_pos); 00779 return status; 00780 } 00781 00782 /** 00783 *Parses the an nmstart as defined by the css2 spec [4.1.1]: 00784 * nmstart [a-zA-Z]|{nonascii}|{escape} 00785 * 00786 *@param a_this the current instance of #CRTknzr. 00787 *@param a_start out param. A pointer to the starting point of 00788 *the token. 00789 *@param a_end out param. A pointer to the ending point of the 00790 *token. 00791 *@param a_char out param. The actual parsed nmchar. 00792 *@return CR_OK upon successfull completion, 00793 *an error code otherwise. 00794 */ 00795 static enum CRStatus 00796 cr_tknzr_parse_nmstart (CRTknzr * a_this, 00797 guint32 * a_char, 00798 CRParsingLocation *a_location) 00799 { 00800 CRInputPos init_pos; 00801 enum CRStatus status = CR_OK; 00802 guint32 cur_char = 0, 00803 next_char = 0; 00804 00805 g_return_val_if_fail (a_this && PRIVATE (a_this) 00806 && PRIVATE (a_this)->input 00807 && a_char, CR_BAD_PARAM_ERROR); 00808 00809 RECORD_INITIAL_POS (a_this, &init_pos); 00810 00811 PEEK_NEXT_CHAR (a_this, &next_char); 00812 00813 if (next_char == '\\') { 00814 status = cr_tknzr_parse_escape (a_this, a_char, 00815 a_location); 00816 00817 if (status != CR_OK) 00818 goto error; 00819 00820 } else if (cr_utils_is_nonascii (next_char) == TRUE 00821 || ((next_char >= 'a') && (next_char <= 'z')) 00822 || ((next_char >= 'A') && (next_char <= 'Z')) 00823 ) { 00824 READ_NEXT_CHAR (a_this, &cur_char); 00825 if (a_location) { 00826 cr_tknzr_get_parsing_location (a_this, 00827 a_location) ; 00828 } 00829 *a_char = cur_char; 00830 status = CR_OK; 00831 } else { 00832 status = CR_PARSING_ERROR; 00833 goto error; 00834 } 00835 00836 return CR_OK; 00837 00838 error: 00839 cr_tknzr_set_cur_pos (a_this, &init_pos); 00840 00841 return status; 00842 00843 } 00844 00845 /** 00846 *Parses an nmchar as described in the css spec at 00847 *chap 4.1.1: 00848 *nmchar ::= [a-z0-9-]|{nonascii}|{escape} 00849 * 00850 *Humm, I have added the possibility for nmchar to 00851 *contain upper case letters. 00852 * 00853 *@param a_this the current instance of #CRTknzr. 00854 *@param a_start out param. A pointer to the starting point of 00855 *the token. 00856 *@param a_end out param. A pointer to the ending point of the 00857 *token. 00858 *@param a_char out param. The actual parsed nmchar. 00859 *@return CR_OK upon successfull completion, 00860 *an error code otherwise. 00861 */ 00862 static enum CRStatus 00863 cr_tknzr_parse_nmchar (CRTknzr * a_this, guint32 * a_char, 00864 CRParsingLocation *a_location) 00865 { 00866 guint32 cur_char = 0, 00867 next_char = 0; 00868 enum CRStatus status = CR_OK; 00869 CRInputPos init_pos; 00870 00871 g_return_val_if_fail (a_this && PRIVATE (a_this) && a_char, 00872 CR_BAD_PARAM_ERROR); 00873 00874 RECORD_INITIAL_POS (a_this, &init_pos); 00875 00876 status = cr_input_peek_char (PRIVATE (a_this)->input, 00877 &next_char) ; 00878 if (status != CR_OK) 00879 goto error; 00880 00881 if (next_char == '\\') { 00882 status = cr_tknzr_parse_escape (a_this, a_char, 00883 a_location); 00884 00885 if (status != CR_OK) 00886 goto error; 00887 00888 } else if (cr_utils_is_nonascii (next_char) == TRUE 00889 || ((next_char >= 'a') && (next_char <= 'z')) 00890 || ((next_char >= 'A') && (next_char <= 'Z')) 00891 || ((next_char >= '0') && (next_char <= '9')) 00892 || (next_char == '-') 00893 || (next_char == '_') /*'_' not allowed by the spec. */ 00894 ) { 00895 READ_NEXT_CHAR (a_this, &cur_char); 00896 *a_char = cur_char; 00897 status = CR_OK; 00898 if (a_location) { 00899 cr_tknzr_get_parsing_location 00900 (a_this, a_location) ; 00901 } 00902 } else { 00903 status = CR_PARSING_ERROR; 00904 goto error; 00905 } 00906 return CR_OK; 00907 00908 error: 00909 cr_tknzr_set_cur_pos (a_this, &init_pos); 00910 return status; 00911 } 00912 00913 /** 00914 *Parses an "ident" as defined in css spec [4.1.1]: 00915 *ident ::= {nmstart}{nmchar}* 00916 * 00917 *Actually parses it using the css3 grammar: 00918 *ident ::= -?{nmstart}{nmchar}* 00919 *@param a_this the currens instance of #CRTknzr. 00920 * 00921 *@param a_str a pointer to parsed ident. If *a_str is NULL, 00922 *this function allocates a new instance of CRString. If not, 00923 *the function just appends the parsed string to the one passed. 00924 *In both cases it is up to the caller to free *a_str. 00925 * 00926 *@return CR_OK upon successfull completion, an error code 00927 *otherwise. 00928 */ 00929 static enum CRStatus 00930 cr_tknzr_parse_ident (CRTknzr * a_this, CRString ** a_str) 00931 { 00932 guint32 tmp_char = 0; 00933 CRString *stringue = NULL ; 00934 CRInputPos init_pos; 00935 enum CRStatus status = CR_OK; 00936 gboolean location_is_set = FALSE ; 00937 00938 g_return_val_if_fail (a_this && PRIVATE (a_this) 00939 && PRIVATE (a_this)->input 00940 && a_str, CR_BAD_PARAM_ERROR); 00941 00942 RECORD_INITIAL_POS (a_this, &init_pos); 00943 PEEK_NEXT_CHAR (a_this, &tmp_char) ; 00944 stringue = cr_string_new () ; 00945 g_return_val_if_fail (stringue, 00946 CR_OUT_OF_MEMORY_ERROR) ; 00947 00948 if (tmp_char == '-') { 00949 READ_NEXT_CHAR (a_this, &tmp_char) ; 00950 cr_tknzr_get_parsing_location 00951 (a_this, &stringue->location) ; 00952 location_is_set = TRUE ; 00953 g_string_append_unichar (stringue->stryng, 00954 tmp_char) ; 00955 } 00956 status = cr_tknzr_parse_nmstart (a_this, &tmp_char, NULL); 00957 if (status != CR_OK) { 00958 status = CR_PARSING_ERROR; 00959 goto end ; 00960 } 00961 if (location_is_set == FALSE) { 00962 cr_tknzr_get_parsing_location 00963 (a_this, &stringue->location) ; 00964 location_is_set = TRUE ; 00965 } 00966 g_string_append_unichar (stringue->stryng, tmp_char); 00967 for (;;) { 00968 status = cr_tknzr_parse_nmchar (a_this, 00969 &tmp_char, 00970 NULL); 00971 if (status != CR_OK) { 00972 status = CR_OK ; 00973 break; 00974 } 00975 g_string_append_unichar (stringue->stryng, tmp_char); 00976 } 00977 if (status == CR_OK) { 00978 if (!*a_str) { 00979 *a_str = stringue ; 00980 00981 } else { 00982 g_string_append_len ((*a_str)->stryng, 00983 stringue->stryng->str, 00984 stringue->stryng->len) ; 00985 cr_string_destroy (stringue) ; 00986 } 00987 stringue = NULL ; 00988 } 00989 00990 error: 00991 end: 00992 if (stringue) { 00993 cr_string_destroy (stringue) ; 00994 stringue = NULL ; 00995 } 00996 if (status != CR_OK ) { 00997 cr_tknzr_set_cur_pos (a_this, &init_pos) ; 00998 } 00999 return status ; 01000 } 01001 01002 01003 /** 01004 *Parses a "name" as defined by css spec [4.1.1]: 01005 *name ::= {nmchar}+ 01006 * 01007 *@param a_this the current instance of #CRTknzr. 01008 * 01009 *@param a_str out parameter. A pointer to the successfully parsed 01010 *name. If *a_str is set to NULL, this function allocates a new instance 01011 *of CRString. If not, it just appends the parsed name to the passed *a_str. 01012 *In both cases, it is up to the caller to free *a_str. 01013 * 01014 *@return CR_OK upon successfull completion, an error code otherwise. 01015 */ 01016 static enum CRStatus 01017 cr_tknzr_parse_name (CRTknzr * a_this, 01018 CRString ** a_str) 01019 { 01020 guint32 tmp_char = 0; 01021 CRInputPos init_pos; 01022 enum CRStatus status = CR_OK; 01023 gboolean str_needs_free = FALSE, 01024 is_first_nmchar=TRUE ; 01025 glong i = 0; 01026 CRParsingLocation loc = {0} ; 01027 01028 g_return_val_if_fail (a_this && PRIVATE (a_this) 01029 && PRIVATE (a_this)->input 01030 && a_str, 01031 CR_BAD_PARAM_ERROR) ; 01032 01033 RECORD_INITIAL_POS (a_this, &init_pos); 01034 01035 if (*a_str == NULL) { 01036 *a_str = cr_string_new (); 01037 str_needs_free = TRUE; 01038 } 01039 for (i = 0;; i++) { 01040 if (is_first_nmchar == TRUE) { 01041 status = cr_tknzr_parse_nmchar 01042 (a_this, &tmp_char, 01043 &loc) ; 01044 is_first_nmchar = FALSE ; 01045 } else { 01046 status = cr_tknzr_parse_nmchar 01047 (a_this, &tmp_char, NULL) ; 01048 } 01049 if (status != CR_OK) 01050 break; 01051 g_string_append_unichar ((*a_str)->stryng, 01052 tmp_char); 01053 } 01054 if (i > 0) { 01055 cr_parsing_location_copy 01056 (&(*a_str)->location, &loc) ; 01057 return CR_OK; 01058 } 01059 if (str_needs_free == TRUE && *a_str) { 01060 cr_string_destroy (*a_str); 01061 *a_str = NULL; 01062 } 01063 cr_tknzr_set_cur_pos (a_this, &init_pos); 01064 return CR_PARSING_ERROR; 01065 } 01066 01067 /** 01068 *Parses a "hash" as defined by the css spec in [4.1.1]: 01069 *HASH ::= #{name} 01070 */ 01071 static enum CRStatus 01072 cr_tknzr_parse_hash (CRTknzr * a_this, CRString ** a_str) 01073 { 01074 guint32 cur_char = 0; 01075 CRInputPos init_pos; 01076 enum CRStatus status = CR_OK; 01077 gboolean str_needs_free = FALSE; 01078 CRParsingLocation loc = {0} ; 01079 01080 g_return_val_if_fail (a_this && PRIVATE (a_this) 01081 && PRIVATE (a_this)->input, 01082 CR_BAD_PARAM_ERROR); 01083 01084 RECORD_INITIAL_POS (a_this, &init_pos); 01085 READ_NEXT_CHAR (a_this, &cur_char); 01086 if (cur_char != '#') { 01087 status = CR_PARSING_ERROR; 01088 goto error; 01089 } 01090 if (*a_str == NULL) { 01091 *a_str = cr_string_new (); 01092 str_needs_free = TRUE; 01093 } 01094 cr_tknzr_get_parsing_location (a_this, 01095 &loc) ; 01096 status = cr_tknzr_parse_name (a_this, a_str); 01097 cr_parsing_location_copy (&(*a_str)->location, &loc) ; 01098 if (status != CR_OK) { 01099 goto error; 01100 } 01101 return CR_OK; 01102 01103 error: 01104 if (str_needs_free == TRUE && *a_str) { 01105 cr_string_destroy (*a_str); 01106 *a_str = NULL; 01107 } 01108 01109 cr_tknzr_set_cur_pos (a_this, &init_pos); 01110 return status; 01111 } 01112 01113 /** 01114 *Parses an uri as defined by the css spec [4.1.1]: 01115 * URI ::= url\({w}{string}{w}\) 01116 * |url\({w}([!#$%&*-~]|{nonascii}|{escape})*{w}\) 01117 * 01118 *@param a_this the current instance of #CRTknzr. 01119 *@param a_str the successfully parsed url. 01120 *@return CR_OK upon successfull completion, an error code otherwise. 01121 */ 01122 static enum CRStatus 01123 cr_tknzr_parse_uri (CRTknzr * a_this, 01124 CRString ** a_str) 01125 { 01126 guint32 cur_char = 0; 01127 CRInputPos init_pos; 01128 enum CRStatus status = CR_PARSING_ERROR; 01129 guchar tab[4] = { 0 }, *tmp_ptr1 = NULL, *tmp_ptr2 = NULL; 01130 CRString *str = NULL; 01131 CRParsingLocation location = {0} ; 01132 01133 g_return_val_if_fail (a_this 01134 && PRIVATE (a_this) 01135 && PRIVATE (a_this)->input 01136 && a_str, 01137 CR_BAD_PARAM_ERROR); 01138 01139 RECORD_INITIAL_POS (a_this, &init_pos); 01140 01141 PEEK_BYTE (a_this, 1, &tab[0]); 01142 PEEK_BYTE (a_this, 2, &tab[1]); 01143 PEEK_BYTE (a_this, 3, &tab[2]); 01144 PEEK_BYTE (a_this, 4, &tab[3]); 01145 01146 if (tab[0] != 'u' || tab[1] != 'r' || tab[2] != 'l' || tab[3] != '(') { 01147 status = CR_PARSING_ERROR; 01148 goto error; 01149 } 01150 /* 01151 *Here, we want to skip 4 bytes ('u''r''l''('). 01152 *But we also need to keep track of the parsing location 01153 *of the 'u'. So, we skip 1 byte, we record the parsing 01154 *location, then we skip the 3 remaining bytes. 01155 */ 01156 SKIP_CHARS (a_this, 1); 01157 cr_tknzr_get_parsing_location (a_this, &location) ; 01158 SKIP_CHARS (a_this, 3); 01159 cr_tknzr_try_to_skip_spaces (a_this); 01160 status = cr_tknzr_parse_string (a_this, a_str); 01161 01162 if (status == CR_OK) { 01163 guint32 next_char = 0; 01164 status = cr_tknzr_parse_w (a_this, &tmp_ptr1, 01165 &tmp_ptr2, NULL); 01166 cr_tknzr_try_to_skip_spaces (a_this); 01167 PEEK_NEXT_CHAR (a_this, &next_char); 01168 if (next_char == ')') { 01169 READ_NEXT_CHAR (a_this, &cur_char); 01170 status = CR_OK; 01171 } else { 01172 status = CR_PARSING_ERROR; 01173 } 01174 } 01175 if (status != CR_OK) { 01176 str = cr_string_new (); 01177 for (;;) { 01178 guint32 next_char = 0; 01179 PEEK_NEXT_CHAR (a_this, &next_char); 01180 if (strchr ("!#$%&", next_char) 01181 || (next_char >= '*' && next_char <= '~') 01182 || (cr_utils_is_nonascii (next_char) == TRUE)) { 01183 READ_NEXT_CHAR (a_this, &cur_char); 01184 g_string_append_unichar 01185 (str->stryng, cur_char); 01186 status = CR_OK; 01187 } else { 01188 guint32 esc_code = 0; 01189 status = cr_tknzr_parse_escape 01190 (a_this, &esc_code, NULL); 01191 if (status == CR_OK) { 01192 g_string_append_unichar 01193 (str->stryng, 01194 esc_code); 01195 } else { 01196 status = CR_OK; 01197 break; 01198 } 01199 } 01200 } 01201 cr_tknzr_try_to_skip_spaces (a_this); 01202 READ_NEXT_CHAR (a_this, &cur_char); 01203 if (cur_char == ')') { 01204 status = CR_OK; 01205 } else { 01206 status = CR_PARSING_ERROR; 01207 goto error; 01208 } 01209 if (str) { 01210 if (*a_str == NULL) { 01211 *a_str = str; 01212 str = NULL; 01213 } else { 01214 g_string_append_len 01215 ((*a_str)->stryng, 01216 str->stryng->str, 01217 str->stryng->len); 01218 cr_string_destroy (str); 01219 } 01220 } 01221 } 01222 01223 cr_parsing_location_copy 01224 (&(*a_str)->location, 01225 &location) ; 01226 return CR_OK ; 01227 error: 01228 if (str) { 01229 cr_string_destroy (str); 01230 str = NULL; 01231 } 01232 cr_tknzr_set_cur_pos (a_this, &init_pos); 01233 return status; 01234 } 01235 01236 /** 01237 *parses an RGB as defined in the css2 spec. 01238 *rgb: rgb '('S*{num}%?S* ',' {num}#?S*,S*{num}#?S*')' 01239 * 01240 *@param a_this the "this pointer" of the current instance of 01241 *@param a_rgb out parameter the parsed rgb. 01242 *@return CR_OK upon successfull completion, an error code otherwise. 01243 */ 01244 static enum CRStatus 01245 cr_tknzr_parse_rgb (CRTknzr * a_this, CRRgb ** a_rgb) 01246 { 01247 enum CRStatus status = CR_OK; 01248 CRInputPos init_pos; 01249 CRNum *num = NULL; 01250 guchar next_bytes[3] = { 0 }, cur_byte = 0; 01251 glong red = 0, 01252 green = 0, 01253 blue = 0, 01254 i = 0; 01255 gboolean is_percentage = FALSE; 01256 CRParsingLocation location = {0} ; 01257 01258 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 01259 01260 RECORD_INITIAL_POS (a_this, &init_pos); 01261 01262 PEEK_BYTE (a_this, 1, &next_bytes[0]); 01263 PEEK_BYTE (a_this, 2, &next_bytes[1]); 01264 PEEK_BYTE (a_this, 3, &next_bytes[2]); 01265 01266 if (((next_bytes[0] == 'r') || (next_bytes[0] == 'R')) 01267 && ((next_bytes[1] == 'g') || (next_bytes[1] == 'G')) 01268 && ((next_bytes[2] == 'b') || (next_bytes[2] == 'B'))) { 01269 SKIP_CHARS (a_this, 1); 01270 cr_tknzr_get_parsing_location (a_this, &location) ; 01271 SKIP_CHARS (a_this, 2); 01272 } else { 01273 status = CR_PARSING_ERROR; 01274 goto error; 01275 } 01276 READ_NEXT_BYTE (a_this, &cur_byte); 01277 ENSURE_PARSING_COND (cur_byte == '('); 01278 01279 cr_tknzr_try_to_skip_spaces (a_this); 01280 status = cr_tknzr_parse_num (a_this, &num); 01281 ENSURE_PARSING_COND ((status == CR_OK) && (num != NULL)); 01282 01283 red = num->val; 01284 cr_num_destroy (num); 01285 num = NULL; 01286 01287 PEEK_BYTE (a_this, 1, &next_bytes[0]); 01288 if (next_bytes[0] == '%') { 01289 SKIP_CHARS (a_this, 1); 01290 is_percentage = TRUE; 01291 } 01292 cr_tknzr_try_to_skip_spaces (a_this); 01293 01294 for (i = 0; i < 2; i++) { 01295 READ_NEXT_BYTE (a_this, &cur_byte); 01296 ENSURE_PARSING_COND (cur_byte == ','); 01297 01298 cr_tknzr_try_to_skip_spaces (a_this); 01299 status = cr_tknzr_parse_num (a_this, &num); 01300 ENSURE_PARSING_COND ((status == CR_OK) && (num != NULL)); 01301 01302 PEEK_BYTE (a_this, 1, &next_bytes[0]); 01303 if (next_bytes[0] == '%') { 01304 SKIP_CHARS (a_this, 1); 01305 is_percentage = 1; 01306 } 01307 01308 if (i == 0) { 01309 green = num->val; 01310 } else if (i == 1) { 01311 blue = num->val; 01312 } 01313 01314 if (num) { 01315 cr_num_destroy (num); 01316 num = NULL; 01317 } 01318 cr_tknzr_try_to_skip_spaces (a_this); 01319 } 01320 01321 READ_NEXT_BYTE (a_this, &cur_byte); 01322 if (*a_rgb == NULL) { 01323 *a_rgb = cr_rgb_new_with_vals (red, green, blue, 01324 is_percentage); 01325 01326 if (*a_rgb == NULL) { 01327 status = CR_ERROR; 01328 goto error; 01329 } 01330 status = CR_OK; 01331 } else { 01332 (*a_rgb)->red = red; 01333 (*a_rgb)->green = green; 01334 (*a_rgb)->blue = blue; 01335 (*a_rgb)->is_percentage = is_percentage; 01336 01337 status = CR_OK; 01338 } 01339 01340 if (status == CR_OK) { 01341 if (a_rgb && *a_rgb) { 01342 cr_parsing_location_copy 01343 (&(*a_rgb)->location, 01344 &location) ; 01345 } 01346 return CR_OK; 01347 } 01348 01349 error: 01350 if (num) { 01351 cr_num_destroy (num); 01352 num = NULL; 01353 } 01354 01355 cr_tknzr_set_cur_pos (a_this, &init_pos); 01356 return CR_OK; 01357 } 01358 01359 /** 01360 *Parses a atkeyword as defined by the css spec in [4.1.1]: 01361 *ATKEYWORD ::= @{ident} 01362 * 01363 *@param a_this the "this pointer" of the current instance of 01364 *#CRTknzr. 01365 * 01366 *@param a_str out parameter. The parsed atkeyword. If *a_str is 01367 *set to NULL this function allocates a new instance of CRString and 01368 *sets it to the parsed atkeyword. If not, this function just appends 01369 *the parsed atkeyword to the end of *a_str. In both cases it is up to 01370 *the caller to free *a_str. 01371 * 01372 *@return CR_OK upon successfull completion, an error code otherwise. 01373 */ 01374 static enum CRStatus 01375 cr_tknzr_parse_atkeyword (CRTknzr * a_this, 01376 CRString ** a_str) 01377 { 01378 guint32 cur_char = 0; 01379 CRInputPos init_pos; 01380 gboolean str_needs_free = FALSE; 01381 enum CRStatus status = CR_OK; 01382 01383 g_return_val_if_fail (a_this && PRIVATE (a_this) 01384 && PRIVATE (a_this)->input 01385 && a_str, CR_BAD_PARAM_ERROR); 01386 01387 RECORD_INITIAL_POS (a_this, &init_pos); 01388 01389 READ_NEXT_CHAR (a_this, &cur_char); 01390 01391 if (cur_char != '@') { 01392 status = CR_PARSING_ERROR; 01393 goto error; 01394 } 01395 01396 if (*a_str == NULL) { 01397 *a_str = cr_string_new (); 01398 str_needs_free = TRUE; 01399 } 01400 status = cr_tknzr_parse_ident (a_this, a_str); 01401 if (status != CR_OK) { 01402 goto error; 01403 } 01404 return CR_OK; 01405 error: 01406 01407 if (str_needs_free == TRUE && *a_str) { 01408 cr_string_destroy (*a_str); 01409 *a_str = NULL; 01410 } 01411 cr_tknzr_set_cur_pos (a_this, &init_pos); 01412 return status; 01413 } 01414 01415 static enum CRStatus 01416 cr_tknzr_parse_important (CRTknzr * a_this, 01417 CRParsingLocation *a_location) 01418 { 01419 guint32 cur_char = 0; 01420 CRInputPos init_pos; 01421 enum CRStatus status = CR_OK; 01422 01423 g_return_val_if_fail (a_this && PRIVATE (a_this) 01424 && PRIVATE (a_this)->input, 01425 CR_BAD_PARAM_ERROR); 01426 01427 RECORD_INITIAL_POS (a_this, &init_pos); 01428 READ_NEXT_CHAR (a_this, &cur_char); 01429 ENSURE_PARSING_COND (cur_char == '!'); 01430 if (a_location) { 01431 cr_tknzr_get_parsing_location (a_this, 01432 a_location) ; 01433 } 01434 cr_tknzr_try_to_skip_spaces (a_this); 01435 01436 if (BYTE (PRIVATE (a_this)->input, 1, NULL) == 'i' 01437 && BYTE (PRIVATE (a_this)->input, 2, NULL) == 'm' 01438 && BYTE (PRIVATE (a_this)->input, 3, NULL) == 'p' 01439 && BYTE (PRIVATE (a_this)->input, 4, NULL) == 'o' 01440 && BYTE (PRIVATE (a_this)->input, 5, NULL) == 'r' 01441 && BYTE (PRIVATE (a_this)->input, 6, NULL) == 't' 01442 && BYTE (PRIVATE (a_this)->input, 7, NULL) == 'a' 01443 && BYTE (PRIVATE (a_this)->input, 8, NULL) == 'n' 01444 && BYTE (PRIVATE (a_this)->input, 9, NULL) == 't') { 01445 SKIP_BYTES (a_this, 9); 01446 if (a_location) { 01447 cr_tknzr_get_parsing_location (a_this, 01448 a_location) ; 01449 } 01450 return CR_OK; 01451 } else { 01452 status = CR_PARSING_ERROR; 01453 } 01454 01455 error: 01456 cr_tknzr_set_cur_pos (a_this, &init_pos); 01457 01458 return status; 01459 } 01460 01461 /** 01462 *Parses a num as defined in the css spec [4.1.1]: 01463 *[0-9]+|[0-9]*\.[0-9]+ 01464 *@param a_this the current instance of #CRTknzr. 01465 *@param a_num out parameter. The parsed number. 01466 *@return CR_OK upon successfull completion, 01467 *an error code otherwise. 01468 * 01469 *The CSS specification says that numbers may be 01470 *preceeded by '+' or '-' to indicate the sign. 01471 *Technically, the "num" construction as defined 01472 *by the tokenizer doesn't allow this, but we parse 01473 *it here for simplicity. 01474 */ 01475 static enum CRStatus 01476 cr_tknzr_parse_num (CRTknzr * a_this, 01477 CRNum ** a_num) 01478 { 01479 enum CRStatus status = CR_PARSING_ERROR; 01480 enum CRNumType val_type = NUM_GENERIC; 01481 gboolean parsing_dec, /* true iff seen decimal point. */ 01482 parsed; /* true iff the substring seen so far is a valid CSS 01483 number, i.e. `[0-9]+|[0-9]*\.[0-9]+'. */ 01484 guint32 cur_char = 0, 01485 next_char = 0; 01486 gdouble numerator, denominator = 1; 01487 CRInputPos init_pos; 01488 CRParsingLocation location = {0} ; 01489 int sign = 1; 01490 01491 g_return_val_if_fail (a_this && PRIVATE (a_this) 01492 && PRIVATE (a_this)->input, 01493 CR_BAD_PARAM_ERROR); 01494 01495 RECORD_INITIAL_POS (a_this, &init_pos); 01496 READ_NEXT_CHAR (a_this, &cur_char); 01497 01498 if (cur_char == '+' || cur_char == '-') { 01499 if (cur_char == '-') { 01500 sign = -1; 01501 } 01502 READ_NEXT_CHAR (a_this, &cur_char); 01503 } 01504 01505 if (IS_NUM (cur_char)) { 01506 numerator = (cur_char - '0'); 01507 parsing_dec = FALSE; 01508 parsed = TRUE; 01509 } else if (cur_char == '.') { 01510 numerator = 0; 01511 parsing_dec = TRUE; 01512 parsed = FALSE; 01513 } else { 01514 status = CR_PARSING_ERROR; 01515 goto error; 01516 } 01517 cr_tknzr_get_parsing_location (a_this, &location) ; 01518 01519 for (;;) { 01520 status = cr_tknzr_peek_char (a_this, &next_char); 01521 if (status != CR_OK) { 01522 if (status == CR_END_OF_INPUT_ERROR) 01523 status = CR_OK; 01524 break; 01525 } 01526 if (next_char == '.') { 01527 if (parsing_dec) { 01528 status = CR_PARSING_ERROR; 01529 goto error; 01530 } 01531 01532 READ_NEXT_CHAR (a_this, &cur_char); 01533 parsing_dec = TRUE; 01534 parsed = FALSE; /* In CSS, there must be at least 01535 one digit after `.'. */ 01536 } else if (IS_NUM (next_char)) { 01537 READ_NEXT_CHAR (a_this, &cur_char); 01538 parsed = TRUE; 01539 01540 numerator = numerator * 10 + (cur_char - '0'); 01541 if (parsing_dec) { 01542 denominator *= 10; 01543 } 01544 } else { 01545 break; 01546 } 01547 } 01548 01549 if (!parsed) { 01550 status = CR_PARSING_ERROR; 01551 } 01552 01553 /* 01554 *Now, set the output param values. 01555 */ 01556 if (status == CR_OK) { 01557 gdouble val = (numerator / denominator) * sign; 01558 if (*a_num == NULL) { 01559 *a_num = cr_num_new_with_val (val, val_type); 01560 01561 if (*a_num == NULL) { 01562 status = CR_ERROR; 01563 goto error; 01564 } 01565 } else { 01566 (*a_num)->val = val; 01567 (*a_num)->type = val_type; 01568 } 01569 cr_parsing_location_copy (&(*a_num)->location, 01570 &location) ; 01571 return CR_OK; 01572 } 01573 01574 error: 01575 01576 cr_tknzr_set_cur_pos (a_this, &init_pos); 01577 01578 return status; 01579 } 01580 01581 /********************************************* 01582 *PUBLIC methods 01583 ********************************************/ 01584 01585 CRTknzr * 01586 cr_tknzr_new (CRInput * a_input) 01587 { 01588 CRTknzr *result = NULL; 01589 01590 result = g_try_malloc (sizeof (CRTknzr)); 01591 01592 if (result == NULL) { 01593 cr_utils_trace_info ("Out of memory"); 01594 return NULL; 01595 } 01596 01597 memset (result, 0, sizeof (CRTknzr)); 01598 01599 result->priv = g_try_malloc (sizeof (CRTknzrPriv)); 01600 01601 if (result->priv == NULL) { 01602 cr_utils_trace_info ("Out of memory"); 01603 01604 if (result) { 01605 g_free (result); 01606 result = NULL; 01607 } 01608 01609 return NULL; 01610 } 01611 memset (result->priv, 0, sizeof (CRTknzrPriv)); 01612 if (a_input) 01613 cr_tknzr_set_input (result, a_input); 01614 return result; 01615 } 01616 01617 CRTknzr * 01618 cr_tknzr_new_from_buf (guchar * a_buf, gulong a_len, 01619 enum CREncoding a_enc, 01620 gboolean a_free_at_destroy) 01621 { 01622 CRTknzr *result = NULL; 01623 CRInput *input = NULL; 01624 01625 input = cr_input_new_from_buf (a_buf, a_len, a_enc, 01626 a_free_at_destroy); 01627 01628 g_return_val_if_fail (input != NULL, NULL); 01629 01630 result = cr_tknzr_new (input); 01631 01632 return result; 01633 } 01634 01635 CRTknzr * 01636 cr_tknzr_new_from_uri (const guchar * a_file_uri, 01637 enum CREncoding a_enc) 01638 { 01639 CRTknzr *result = NULL; 01640 CRInput *input = NULL; 01641 01642 input = cr_input_new_from_uri (a_file_uri, a_enc); 01643 g_return_val_if_fail (input != NULL, NULL); 01644 01645 result = cr_tknzr_new (input); 01646 01647 return result; 01648 } 01649 01650 void 01651 cr_tknzr_ref (CRTknzr * a_this) 01652 { 01653 g_return_if_fail (a_this && PRIVATE (a_this)); 01654 01655 PRIVATE (a_this)->ref_count++; 01656 } 01657 01658 gboolean 01659 cr_tknzr_unref (CRTknzr * a_this) 01660 { 01661 g_return_val_if_fail (a_this && PRIVATE (a_this), FALSE); 01662 01663 if (PRIVATE (a_this)->ref_count > 0) { 01664 PRIVATE (a_this)->ref_count--; 01665 } 01666 01667 if (PRIVATE (a_this)->ref_count == 0) { 01668 cr_tknzr_destroy (a_this); 01669 return TRUE; 01670 } 01671 01672 return FALSE; 01673 } 01674 01675 enum CRStatus 01676 cr_tknzr_set_input (CRTknzr * a_this, CRInput * a_input) 01677 { 01678 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 01679 01680 if (PRIVATE (a_this)->input) { 01681 cr_input_unref (PRIVATE (a_this)->input); 01682 } 01683 01684 PRIVATE (a_this)->input = a_input; 01685 01686 cr_input_ref (PRIVATE (a_this)->input); 01687 01688 return CR_OK; 01689 } 01690 01691 enum CRStatus 01692 cr_tknzr_get_input (CRTknzr * a_this, CRInput ** a_input) 01693 { 01694 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 01695 01696 *a_input = PRIVATE (a_this)->input; 01697 01698 return CR_OK; 01699 } 01700 01701 /********************************* 01702 *Tokenizer input handling routines 01703 *********************************/ 01704 01705 /** 01706 *Reads the next byte from the parser input stream. 01707 *@param a_this the "this pointer" of the current instance of 01708 *#CRParser. 01709 *@param a_byte out parameter the place where to store the byte 01710 *read. 01711 *@return CR_OK upon successfull completion, an error 01712 *code otherwise. 01713 */ 01714 enum CRStatus 01715 cr_tknzr_read_byte (CRTknzr * a_this, guchar * a_byte) 01716 { 01717 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 01718 01719 return cr_input_read_byte (PRIVATE (a_this)->input, a_byte); 01720 01721 } 01722 01723 /** 01724 *Reads the next char from the parser input stream. 01725 *@param a_this the current instance of #CRTknzr. 01726 *@param a_char out parameter. The read char. 01727 *@return CR_OK upon successfull completion, an error code 01728 *otherwise. 01729 */ 01730 enum CRStatus 01731 cr_tknzr_read_char (CRTknzr * a_this, guint32 * a_char) 01732 { 01733 g_return_val_if_fail (a_this && PRIVATE (a_this) 01734 && PRIVATE (a_this)->input 01735 && a_char, CR_BAD_PARAM_ERROR); 01736 01737 if (PRIVATE (a_this)->token_cache) { 01738 cr_input_set_cur_pos (PRIVATE (a_this)->input, 01739 &PRIVATE (a_this)->prev_pos); 01740 cr_token_destroy (PRIVATE (a_this)->token_cache); 01741 PRIVATE (a_this)->token_cache = NULL; 01742 } 01743 01744 return cr_input_read_char (PRIVATE (a_this)->input, a_char); 01745 } 01746 01747 /** 01748 *Peeks a char from the parser input stream. 01749 *To "peek a char" means reads the next char without consuming it. 01750 *Subsequent calls to this function return the same char. 01751 *@param a_this the current instance of #CRTknzr. 01752 *@param a_char out parameter. The peeked char uppon successfull completion. 01753 *@return CR_OK upon successfull completion, an error code otherwise. 01754 */ 01755 enum CRStatus 01756 cr_tknzr_peek_char (CRTknzr * a_this, guint32 * a_char) 01757 { 01758 g_return_val_if_fail (a_this && PRIVATE (a_this) 01759 && PRIVATE (a_this)->input 01760 && a_char, CR_BAD_PARAM_ERROR); 01761 01762 if (PRIVATE (a_this)->token_cache) { 01763 cr_input_set_cur_pos (PRIVATE (a_this)->input, 01764 &PRIVATE (a_this)->prev_pos); 01765 cr_token_destroy (PRIVATE (a_this)->token_cache); 01766 PRIVATE (a_this)->token_cache = NULL; 01767 } 01768 01769 return cr_input_peek_char (PRIVATE (a_this)->input, a_char); 01770 } 01771 01772 /** 01773 *Peeks a byte ahead at a given postion in the parser input stream. 01774 *@param a_this the current instance of #CRTknzr. 01775 *@param a_offset the offset of the peeked byte starting from the current 01776 *byte in the parser input stream. 01777 *@param a_byte out parameter. The peeked byte upon 01778 *successfull completion. 01779 *@return CR_OK upon successfull completion, an error code otherwise. 01780 */ 01781 enum CRStatus 01782 cr_tknzr_peek_byte (CRTknzr * a_this, gulong a_offset, guchar * a_byte) 01783 { 01784 g_return_val_if_fail (a_this && PRIVATE (a_this) 01785 && PRIVATE (a_this)->input && a_byte, 01786 CR_BAD_PARAM_ERROR); 01787 01788 if (PRIVATE (a_this)->token_cache) { 01789 cr_input_set_cur_pos (PRIVATE (a_this)->input, 01790 &PRIVATE (a_this)->prev_pos); 01791 cr_token_destroy (PRIVATE (a_this)->token_cache); 01792 PRIVATE (a_this)->token_cache = NULL; 01793 } 01794 01795 return cr_input_peek_byte (PRIVATE (a_this)->input, 01796 CR_SEEK_CUR, a_offset, a_byte); 01797 } 01798 01799 /** 01800 *Same as cr_tknzr_peek_byte() but this api returns the byte peeked. 01801 *@param a_this the current instance of #CRTknzr. 01802 *@param a_offset the offset of the peeked byte starting from the current 01803 *byte in the parser input stream. 01804 *@param a_eof out parameter. If not NULL, is set to TRUE if we reached end of 01805 *file, FALE otherwise. If the caller sets it to NULL, this parameter 01806 *is just ignored. 01807 *@return the peeked byte. 01808 */ 01809 guchar 01810 cr_tknzr_peek_byte2 (CRTknzr * a_this, gulong a_offset, gboolean * a_eof) 01811 { 01812 g_return_val_if_fail (a_this && PRIVATE (a_this) 01813 && PRIVATE (a_this)->input, 0); 01814 01815 return cr_input_peek_byte2 (PRIVATE (a_this)->input, a_offset, a_eof); 01816 } 01817 01818 /** 01819 *Gets the number of bytes left in the topmost input stream 01820 *associated to this parser. 01821 *@param a_this the current instance of #CRTknzr 01822 *@return the number of bytes left or -1 in case of error. 01823 */ 01824 glong 01825 cr_tknzr_get_nb_bytes_left (CRTknzr * a_this) 01826 { 01827 g_return_val_if_fail (a_this && PRIVATE (a_this) 01828 && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); 01829 01830 if (PRIVATE (a_this)->token_cache) { 01831 cr_input_set_cur_pos (PRIVATE (a_this)->input, 01832 &PRIVATE (a_this)->prev_pos); 01833 cr_token_destroy (PRIVATE (a_this)->token_cache); 01834 PRIVATE (a_this)->token_cache = NULL; 01835 } 01836 01837 return cr_input_get_nb_bytes_left (PRIVATE (a_this)->input); 01838 } 01839 01840 enum CRStatus 01841 cr_tknzr_get_cur_pos (CRTknzr * a_this, CRInputPos * a_pos) 01842 { 01843 g_return_val_if_fail (a_this && PRIVATE (a_this) 01844 && PRIVATE (a_this)->input 01845 && a_pos, CR_BAD_PARAM_ERROR); 01846 01847 if (PRIVATE (a_this)->token_cache) { 01848 cr_input_set_cur_pos (PRIVATE (a_this)->input, 01849 &PRIVATE (a_this)->prev_pos); 01850 cr_token_destroy (PRIVATE (a_this)->token_cache); 01851 PRIVATE (a_this)->token_cache = NULL; 01852 } 01853 01854 return cr_input_get_cur_pos (PRIVATE (a_this)->input, a_pos); 01855 } 01856 01857 enum CRStatus 01858 cr_tknzr_get_parsing_location (CRTknzr *a_this, 01859 CRParsingLocation *a_loc) 01860 { 01861 g_return_val_if_fail (a_this 01862 && PRIVATE (a_this) 01863 && a_loc, 01864 CR_BAD_PARAM_ERROR) ; 01865 01866 return cr_input_get_parsing_location 01867 (PRIVATE (a_this)->input, a_loc) ; 01868 } 01869 01870 enum CRStatus 01871 cr_tknzr_get_cur_byte_addr (CRTknzr * a_this, guchar ** a_addr) 01872 { 01873 g_return_val_if_fail (a_this && PRIVATE (a_this) 01874 && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); 01875 if (PRIVATE (a_this)->token_cache) { 01876 cr_input_set_cur_pos (PRIVATE (a_this)->input, 01877 &PRIVATE (a_this)->prev_pos); 01878 cr_token_destroy (PRIVATE (a_this)->token_cache); 01879 PRIVATE (a_this)->token_cache = NULL; 01880 } 01881 01882 return cr_input_get_cur_byte_addr (PRIVATE (a_this)->input, a_addr); 01883 } 01884 01885 enum CRStatus 01886 cr_tknzr_seek_index (CRTknzr * a_this, enum CRSeekPos a_origin, gint a_pos) 01887 { 01888 g_return_val_if_fail (a_this && PRIVATE (a_this) 01889 && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); 01890 01891 if (PRIVATE (a_this)->token_cache) { 01892 cr_input_set_cur_pos (PRIVATE (a_this)->input, 01893 &PRIVATE (a_this)->prev_pos); 01894 cr_token_destroy (PRIVATE (a_this)->token_cache); 01895 PRIVATE (a_this)->token_cache = NULL; 01896 } 01897 01898 return cr_input_seek_index (PRIVATE (a_this)->input, a_origin, a_pos); 01899 } 01900 01901 enum CRStatus 01902 cr_tknzr_consume_chars (CRTknzr * a_this, guint32 a_char, glong * a_nb_char) 01903 { 01904 g_return_val_if_fail (a_this && PRIVATE (a_this) 01905 && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); 01906 01907 if (PRIVATE (a_this)->token_cache) { 01908 cr_input_set_cur_pos (PRIVATE (a_this)->input, 01909 &PRIVATE (a_this)->prev_pos); 01910 cr_token_destroy (PRIVATE (a_this)->token_cache); 01911 PRIVATE (a_this)->token_cache = NULL; 01912 } 01913 01914 return cr_input_consume_chars (PRIVATE (a_this)->input, 01915 a_char, a_nb_char); 01916 } 01917 01918 enum CRStatus 01919 cr_tknzr_set_cur_pos (CRTknzr * a_this, CRInputPos * a_pos) 01920 { 01921 g_return_val_if_fail (a_this && PRIVATE (a_this) 01922 && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); 01923 01924 if (PRIVATE (a_this)->token_cache) { 01925 cr_token_destroy (PRIVATE (a_this)->token_cache); 01926 PRIVATE (a_this)->token_cache = NULL; 01927 } 01928 01929 return cr_input_set_cur_pos (PRIVATE (a_this)->input, a_pos); 01930 } 01931 01932 enum CRStatus 01933 cr_tknzr_unget_token (CRTknzr * a_this, CRToken * a_token) 01934 { 01935 g_return_val_if_fail (a_this && PRIVATE (a_this) 01936 && PRIVATE (a_this)->token_cache == NULL, 01937 CR_BAD_PARAM_ERROR); 01938 01939 PRIVATE (a_this)->token_cache = a_token; 01940 01941 return CR_OK; 01942 } 01943 01944 /** 01945 *Returns the next token of the input stream. 01946 *This method is really central. Each parsing 01947 *method calls it. 01948 *@param a_this the current tokenizer. 01949 *@param a_tk out parameter. The returned token. 01950 *for the sake of mem leak avoidance, *a_tk must 01951 *be NULL. 01952 *@param CR_OK upon successfull completion, an error code 01953 *otherwise. 01954 */ 01955 enum CRStatus 01956 cr_tknzr_get_next_token (CRTknzr * a_this, CRToken ** a_tk) 01957 { 01958 enum CRStatus status = CR_OK; 01959 CRToken *token = NULL; 01960 CRInputPos init_pos; 01961 guint32 next_char = 0; 01962 guchar next_bytes[4] = { 0 }; 01963 gboolean reached_eof = FALSE; 01964 CRInput *input = NULL; 01965 CRString *str = NULL; 01966 CRRgb *rgb = NULL; 01967 CRParsingLocation location = {0} ; 01968 01969 g_return_val_if_fail (a_this && PRIVATE (a_this) 01970 && a_tk && *a_tk == NULL 01971 && PRIVATE (a_this)->input, 01972 CR_BAD_PARAM_ERROR); 01973 01974 if (PRIVATE (a_this)->token_cache) { 01975 *a_tk = PRIVATE (a_this)->token_cache; 01976 PRIVATE (a_this)->token_cache = NULL; 01977 return CR_OK; 01978 } 01979 01980 RECORD_INITIAL_POS (a_this, &init_pos); 01981 01982 status = cr_input_get_end_of_file 01983 (PRIVATE (a_this)->input, &reached_eof); 01984 ENSURE_PARSING_COND (status == CR_OK); 01985 01986 if (reached_eof == TRUE) { 01987 status = CR_END_OF_INPUT_ERROR; 01988 goto error; 01989 } 01990 01991 input = PRIVATE (a_this)->input; 01992 01993 PEEK_NEXT_CHAR (a_this, &next_char); 01994 token = cr_token_new (); 01995 ENSURE_PARSING_COND (token); 01996 01997 switch (next_char) { 01998 case '@': 01999 { 02000 if (BYTE (input, 2, NULL) == 'f' 02001 && BYTE (input, 3, NULL) == 'o' 02002 && BYTE (input, 4, NULL) == 'n' 02003 && BYTE (input, 5, NULL) == 't' 02004 && BYTE (input, 6, NULL) == '-' 02005 && BYTE (input, 7, NULL) == 'f' 02006 && BYTE (input, 8, NULL) == 'a' 02007 && BYTE (input, 9, NULL) == 'c' 02008 && BYTE (input, 10, NULL) == 'e') { 02009 SKIP_CHARS (a_this, 1); 02010 cr_tknzr_get_parsing_location 02011 (a_this, &location) ; 02012 SKIP_CHARS (a_this, 9); 02013 status = cr_token_set_font_face_sym (token); 02014 CHECK_PARSING_STATUS (status, TRUE); 02015 cr_parsing_location_copy (&token->location, 02016 &location) ; 02017 goto done; 02018 } 02019 02020 if (BYTE (input, 2, NULL) == 'c' 02021 && BYTE (input, 3, NULL) == 'h' 02022 && BYTE (input, 4, NULL) == 'a' 02023 && BYTE (input, 5, NULL) == 'r' 02024 && BYTE (input, 6, NULL) == 's' 02025 && BYTE (input, 7, NULL) == 'e' 02026 && BYTE (input, 8, NULL) == 't') { 02027 SKIP_CHARS (a_this, 1); 02028 cr_tknzr_get_parsing_location 02029 (a_this, &location) ; 02030 SKIP_CHARS (a_this, 7); 02031 status = cr_token_set_charset_sym (token); 02032 CHECK_PARSING_STATUS (status, TRUE); 02033 cr_parsing_location_copy (&token->location, 02034 &location) ; 02035 goto done; 02036 } 02037 02038 if (BYTE (input, 2, NULL) == 'i' 02039 && BYTE (input, 3, NULL) == 'm' 02040 && BYTE (input, 4, NULL) == 'p' 02041 && BYTE (input, 5, NULL) == 'o' 02042 && BYTE (input, 6, NULL) == 'r' 02043 && BYTE (input, 7, NULL) == 't') { 02044 SKIP_CHARS (a_this, 1); 02045 cr_tknzr_get_parsing_location 02046 (a_this, &location) ; 02047 SKIP_CHARS (a_this, 6); 02048 status = cr_token_set_import_sym (token); 02049 CHECK_PARSING_STATUS (status, TRUE); 02050 cr_parsing_location_copy (&token->location, 02051 &location) ; 02052 goto done; 02053 } 02054 02055 if (BYTE (input, 2, NULL) == 'm' 02056 && BYTE (input, 3, NULL) == 'e' 02057 && BYTE (input, 4, NULL) == 'd' 02058 && BYTE (input, 5, NULL) == 'i' 02059 && BYTE (input, 6, NULL) == 'a') { 02060 SKIP_CHARS (a_this, 1); 02061 cr_tknzr_get_parsing_location (a_this, 02062 &location) ; 02063 SKIP_CHARS (a_this, 5); 02064 status = cr_token_set_media_sym (token); 02065 CHECK_PARSING_STATUS (status, TRUE); 02066 cr_parsing_location_copy (&token->location, 02067 &location) ; 02068 goto done; 02069 } 02070 02071 if (BYTE (input, 2, NULL) == 'p' 02072 && BYTE (input, 3, NULL) == 'a' 02073 && BYTE (input, 4, NULL) == 'g' 02074 && BYTE (input, 5, NULL) == 'e') { 02075 SKIP_CHARS (a_this, 1); 02076 cr_tknzr_get_parsing_location (a_this, 02077 &location) ; 02078 SKIP_CHARS (a_this, 4); 02079 status = cr_token_set_page_sym (token); 02080 CHECK_PARSING_STATUS (status, TRUE); 02081 cr_parsing_location_copy (&token->location, 02082 &location) ; 02083 goto done; 02084 } 02085 status = cr_tknzr_parse_atkeyword (a_this, &str); 02086 if (status == CR_OK) { 02087 status = cr_token_set_atkeyword (token, str); 02088 CHECK_PARSING_STATUS (status, TRUE); 02089 if (str) { 02090 cr_parsing_location_copy (&token->location, 02091 &str->location) ; 02092 } 02093 goto done; 02094 } 02095 } 02096 break; 02097 02098 case 'u': 02099 02100 if (BYTE (input, 2, NULL) == 'r' 02101 && BYTE (input, 3, NULL) == 'l' 02102 && BYTE (input, 4, NULL) == '(') { 02103 CRString *str = NULL; 02104 02105 status = cr_tknzr_parse_uri (a_this, &str); 02106 if (status == CR_OK) { 02107 status = cr_token_set_uri (token, str); 02108 CHECK_PARSING_STATUS (status, TRUE); 02109 if (str) { 02110 cr_parsing_location_copy (&token->location, 02111 &str->location) ; 02112 } 02113 goto done; 02114 } 02115 } 02116 goto fallback; 02117 break; 02118 02119 case 'r': 02120 if (BYTE (input, 2, NULL) == 'g' 02121 && BYTE (input, 3, NULL) == 'b' 02122 && BYTE (input, 4, NULL) == '(') { 02123 status = cr_tknzr_parse_rgb (a_this, &rgb); 02124 if (status == CR_OK && rgb) { 02125 status = cr_token_set_rgb (token, rgb); 02126 CHECK_PARSING_STATUS (status, TRUE); 02127 if (rgb) { 02128 cr_parsing_location_copy (&token->location, 02129 &rgb->location) ; 02130 } 02131 rgb = NULL; 02132 goto done; 02133 } 02134 02135 } 02136 goto fallback; 02137 break; 02138 02139 case '<': 02140 if (BYTE (input, 2, NULL) == '!' 02141 && BYTE (input, 3, NULL) == '-' 02142 && BYTE (input, 4, NULL) == '-') { 02143 SKIP_CHARS (a_this, 1); 02144 cr_tknzr_get_parsing_location (a_this, 02145 &location) ; 02146 SKIP_CHARS (a_this, 3); 02147 status = cr_token_set_cdo (token); 02148 CHECK_PARSING_STATUS (status, TRUE); 02149 cr_parsing_location_copy (&token->location, 02150 &location) ; 02151 goto done; 02152 } 02153 break; 02154 02155 case '-': 02156 if (BYTE (input, 2, NULL) == '-' 02157 && BYTE (input, 3, NULL) == '>') { 02158 SKIP_CHARS (a_this, 1); 02159 cr_tknzr_get_parsing_location (a_this, 02160 &location) ; 02161 SKIP_CHARS (a_this, 2); 02162 status = cr_token_set_cdc (token); 02163 CHECK_PARSING_STATUS (status, TRUE); 02164 cr_parsing_location_copy (&token->location, 02165 &location) ; 02166 goto done; 02167 } else { 02168 status = cr_tknzr_parse_ident 02169 (a_this, &str); 02170 if (status == CR_OK) { 02171 cr_token_set_ident 02172 (token, str); 02173 if (str) { 02174 cr_parsing_location_copy (&token->location, 02175 &str->location) ; 02176 } 02177 goto done; 02178 } else { 02179 goto parse_number; 02180 } 02181 } 02182 break; 02183 02184 case '~': 02185 if (BYTE (input, 2, NULL) == '=') { 02186 SKIP_CHARS (a_this, 1); 02187 cr_tknzr_get_parsing_location (a_this, 02188 &location) ; 02189 SKIP_CHARS (a_this, 1); 02190 status = cr_token_set_includes (token); 02191 CHECK_PARSING_STATUS (status, TRUE); 02192 cr_parsing_location_copy (&token->location, 02193 &location) ; 02194 goto done; 02195 } 02196 break; 02197 02198 case '|': 02199 if (BYTE (input, 2, NULL) == '=') { 02200 SKIP_CHARS (a_this, 1); 02201 cr_tknzr_get_parsing_location (a_this, 02202 &location) ; 02203 SKIP_CHARS (a_this, 1); 02204 status = cr_token_set_dashmatch (token); 02205 CHECK_PARSING_STATUS (status, TRUE); 02206 cr_parsing_location_copy (&token->location, 02207 &location) ; 02208 goto done; 02209 } 02210 break; 02211 02212 case '/': 02213 if (BYTE (input, 2, NULL) == '*') { 02214 status = cr_tknzr_parse_comment (a_this, &str); 02215 02216 if (status == CR_OK) { 02217 status = cr_token_set_comment (token, str); 02218 str = NULL; 02219 CHECK_PARSING_STATUS (status, TRUE); 02220 if (str) { 02221 cr_parsing_location_copy (&token->location, 02222 &str->location) ; 02223 } 02224 goto done; 02225 } 02226 } 02227 break ; 02228 02229 case ';': 02230 SKIP_CHARS (a_this, 1); 02231 cr_tknzr_get_parsing_location (a_this, 02232 &location) ; 02233 status = cr_token_set_semicolon (token); 02234 CHECK_PARSING_STATUS (status, TRUE); 02235 cr_parsing_location_copy (&token->location, 02236 &location) ; 02237 goto done; 02238 02239 case '{': 02240 SKIP_CHARS (a_this, 1); 02241 cr_tknzr_get_parsing_location (a_this, 02242 &location) ; 02243 status = cr_token_set_cbo (token); 02244 CHECK_PARSING_STATUS (status, TRUE); 02245 cr_tknzr_get_parsing_location (a_this, 02246 &location) ; 02247 goto done; 02248 02249 case '}': 02250 SKIP_CHARS (a_this, 1); 02251 cr_tknzr_get_parsing_location (a_this, 02252 &location) ; 02253 status = cr_token_set_cbc (token); 02254 CHECK_PARSING_STATUS (status, TRUE); 02255 cr_parsing_location_copy (&token->location, 02256 &location) ; 02257 goto done; 02258 02259 case '(': 02260 SKIP_CHARS (a_this, 1); 02261 cr_tknzr_get_parsing_location (a_this, 02262 &location) ; 02263 status = cr_token_set_po (token); 02264 CHECK_PARSING_STATUS (status, TRUE); 02265 cr_parsing_location_copy (&token->location, 02266 &location) ; 02267 goto done; 02268 02269 case ')': 02270 SKIP_CHARS (a_this, 1); 02271 cr_tknzr_get_parsing_location (a_this, 02272 &location) ; 02273 status = cr_token_set_pc (token); 02274 CHECK_PARSING_STATUS (status, TRUE); 02275 cr_parsing_location_copy (&token->location, 02276 &location) ; 02277 goto done; 02278 02279 case '[': 02280 SKIP_CHARS (a_this, 1); 02281 cr_tknzr_get_parsing_location (a_this, 02282 &location) ; 02283 status = cr_token_set_bo (token); 02284 CHECK_PARSING_STATUS (status, TRUE); 02285 cr_parsing_location_copy (&token->location, 02286 &location) ; 02287 goto done; 02288 02289 case ']': 02290 SKIP_CHARS (a_this, 1); 02291 cr_tknzr_get_parsing_location (a_this, 02292 &location) ; 02293 status = cr_token_set_bc (token); 02294 CHECK_PARSING_STATUS (status, TRUE); 02295 cr_parsing_location_copy (&token->location, 02296 &location) ; 02297 goto done; 02298 02299 case ' ': 02300 case '\t': 02301 case '\n': 02302 case '\f': 02303 case '\r': 02304 { 02305 guchar *start = NULL, 02306 *end = NULL; 02307 02308 status = cr_tknzr_parse_w (a_this, &start, 02309 &end, &location); 02310 if (status == CR_OK) { 02311 status = cr_token_set_s (token); 02312 CHECK_PARSING_STATUS (status, TRUE); 02313 cr_tknzr_get_parsing_location (a_this, 02314 &location) ; 02315 goto done; 02316 } 02317 } 02318 break; 02319 02320 case '#': 02321 { 02322 status = cr_tknzr_parse_hash (a_this, &str); 02323 if (status == CR_OK && str) { 02324 status = cr_token_set_hash (token, str); 02325 CHECK_PARSING_STATUS (status, TRUE); 02326 if (str) { 02327 cr_parsing_location_copy (&token->location, 02328 &str->location) ; 02329 } 02330 str = NULL; 02331 goto done; 02332 } 02333 } 02334 break; 02335 02336 case '\'': 02337 case '"': 02338 status = cr_tknzr_parse_string (a_this, &str); 02339 if (status == CR_OK && str) { 02340 status = cr_token_set_string (token, str); 02341 CHECK_PARSING_STATUS (status, TRUE); 02342 if (str) { 02343 cr_parsing_location_copy (&token->location, 02344 &str->location) ; 02345 } 02346 str = NULL; 02347 goto done; 02348 } 02349 break; 02350 02351 case '!': 02352 status = cr_tknzr_parse_important (a_this, &location); 02353 if (status == CR_OK) { 02354 status = cr_token_set_important_sym (token); 02355 CHECK_PARSING_STATUS (status, TRUE); 02356 cr_parsing_location_copy (&token->location, 02357 &location) ; 02358 goto done; 02359 } 02360 break; 02361 02362 case '0': 02363 case '1': 02364 case '2': 02365 case '3': 02366 case '4': 02367 case '5': 02368 case '6': 02369 case '7': 02370 case '8': 02371 case '9': 02372 case '.': 02373 case '+': 02374 /* '-' case is handled separately above for --> comments */ 02375 parse_number: 02376 { 02377 CRNum *num = NULL; 02378 02379 status = cr_tknzr_parse_num (a_this, &num); 02380 if (status == CR_OK && num) { 02381 next_bytes[0] = BYTE (input, 1, NULL); 02382 next_bytes[1] = BYTE (input, 2, NULL); 02383 next_bytes[2] = BYTE (input, 3, NULL); 02384 next_bytes[3] = BYTE (input, 3, NULL); 02385 02386 if (next_bytes[0] == 'e' 02387 && next_bytes[1] == 'm') { 02388 num->type = NUM_LENGTH_EM; 02389 status = cr_token_set_ems (token, 02390 num); 02391 num = NULL; 02392 SKIP_CHARS (a_this, 2); 02393 } else if (next_bytes[0] == 'e' 02394 && next_bytes[1] == 'x') { 02395 num->type = NUM_LENGTH_EX; 02396 status = cr_token_set_exs (token, 02397 num); 02398 num = NULL; 02399 SKIP_CHARS (a_this, 2); 02400 } else if (next_bytes[0] == 'p' 02401 && next_bytes[1] == 'x') { 02402 num->type = NUM_LENGTH_PX; 02403 status = cr_token_set_length 02404 (token, num, LENGTH_PX_ET); 02405 num = NULL; 02406 SKIP_CHARS (a_this, 2); 02407 } else if (next_bytes[0] == 'c' 02408 && next_bytes[1] == 'm') { 02409 num->type = NUM_LENGTH_CM; 02410 status = cr_token_set_length 02411 (token, num, LENGTH_CM_ET); 02412 num = NULL; 02413 SKIP_CHARS (a_this, 2); 02414 } else if (next_bytes[0] == 'm' 02415 && next_bytes[1] == 'm') { 02416 num->type = NUM_LENGTH_MM; 02417 status = cr_token_set_length 02418 (token, num, LENGTH_MM_ET); 02419 num = NULL; 02420 SKIP_CHARS (a_this, 2); 02421 } else if (next_bytes[0] == 'i' 02422 && next_bytes[1] == 'n') { 02423 num->type = NUM_LENGTH_IN; 02424 status = cr_token_set_length 02425 (token, num, LENGTH_IN_ET); 02426 num = NULL; 02427 SKIP_CHARS (a_this, 2); 02428 } else if (next_bytes[0] == 'p' 02429 && next_bytes[1] == 't') { 02430 num->type = NUM_LENGTH_PT; 02431 status = cr_token_set_length 02432 (token, num, LENGTH_PT_ET); 02433 num = NULL; 02434 SKIP_CHARS (a_this, 2); 02435 } else if (next_bytes[0] == 'p' 02436 && next_bytes[1] == 'c') { 02437 num->type = NUM_LENGTH_PC; 02438 status = cr_token_set_length 02439 (token, num, LENGTH_PC_ET); 02440 num = NULL; 02441 SKIP_CHARS (a_this, 2); 02442 } else if (next_bytes[0] == 'd' 02443 && next_bytes[1] == 'e' 02444 && next_bytes[2] == 'g') { 02445 num->type = NUM_ANGLE_DEG; 02446 status = cr_token_set_angle 02447 (token, num, ANGLE_DEG_ET); 02448 num = NULL; 02449 SKIP_CHARS (a_this, 3); 02450 } else if (next_bytes[0] == 'r' 02451 && next_bytes[1] == 'a' 02452 && next_bytes[2] == 'd') { 02453 num->type = NUM_ANGLE_RAD; 02454 status = cr_token_set_angle 02455 (token, num, ANGLE_RAD_ET); 02456 num = NULL; 02457 SKIP_CHARS (a_this, 3); 02458 } else if (next_bytes[0] == 'g' 02459 && next_bytes[1] == 'r' 02460 && next_bytes[2] == 'a' 02461 && next_bytes[3] == 'd') { 02462 num->type = NUM_ANGLE_GRAD; 02463 status = cr_token_set_angle 02464 (token, num, ANGLE_GRAD_ET); 02465 num = NULL; 02466 SKIP_CHARS (a_this, 4); 02467 } else if (next_bytes[0] == 'm' 02468 && next_bytes[1] == 's') { 02469 num->type = NUM_TIME_MS; 02470 status = cr_token_set_time 02471 (token, num, TIME_MS_ET); 02472 num = NULL; 02473 SKIP_CHARS (a_this, 2); 02474 } else if (next_bytes[0] == 's') { 02475 num->type = NUM_TIME_S; 02476 status = cr_token_set_time 02477 (token, num, TIME_S_ET); 02478 num = NULL; 02479 SKIP_CHARS (a_this, 1); 02480 } else if (next_bytes[0] == 'H' 02481 && next_bytes[1] == 'z') { 02482 num->type = NUM_FREQ_HZ; 02483 status = cr_token_set_freq 02484 (token, num, FREQ_HZ_ET); 02485 num = NULL; 02486 SKIP_CHARS (a_this, 2); 02487 } else if (next_bytes[0] == 'k' 02488 && next_bytes[1] == 'H' 02489 && next_bytes[2] == 'z') { 02490 num->type = NUM_FREQ_KHZ; 02491 status = cr_token_set_freq 02492 (token, num, FREQ_KHZ_ET); 02493 num = NULL; 02494 SKIP_CHARS (a_this, 3); 02495 } else if (next_bytes[0] == '%') { 02496 num->type = NUM_PERCENTAGE; 02497 status = cr_token_set_percentage 02498 (token, num); 02499 num = NULL; 02500 SKIP_CHARS (a_this, 1); 02501 } else { 02502 status = cr_tknzr_parse_ident (a_this, 02503 &str); 02504 if (status == CR_OK && str) { 02505 num->type = NUM_UNKNOWN_TYPE; 02506 status = cr_token_set_dimen 02507 (token, num, str); 02508 num = NULL; 02509 CHECK_PARSING_STATUS (status, 02510 TRUE); 02511 str = NULL; 02512 } else { 02513 status = cr_token_set_number 02514 (token, num); 02515 num = NULL; 02516 CHECK_PARSING_STATUS (status, CR_OK); 02517 str = NULL; 02518 } 02519 } 02520 if (token && token->u.num) { 02521 cr_parsing_location_copy (&token->location, 02522 &token->u.num->location) ; 02523 } else { 02524 status = CR_ERROR ; 02525 } 02526 goto done ; 02527 } 02528 } 02529 break; 02530 02531 default: 02532 fallback: 02533 /*process the fallback cases here */ 02534 02535 if (next_char == '\\' 02536 || (cr_utils_is_nonascii (next_bytes[0]) == TRUE) 02537 || ((next_char >= 'a') && (next_char <= 'z')) 02538 || ((next_char >= 'A') && (next_char <= 'Z'))) { 02539 status = cr_tknzr_parse_ident (a_this, &str); 02540 if (status == CR_OK && str) { 02541 guint32 next_c = 0; 02542 02543 status = cr_input_peek_char 02544 (PRIVATE (a_this)->input, &next_c); 02545 02546 if (status == CR_OK && next_c == '(') { 02547 02548 SKIP_CHARS (a_this, 1); 02549 status = cr_token_set_function 02550 (token, str); 02551 CHECK_PARSING_STATUS (status, TRUE); 02552 /*ownership is transfered 02553 *to token by cr_token_set_function. 02554 */ 02555 if (str) { 02556 cr_parsing_location_copy (&token->location, 02557 &str->location) ; 02558 } 02559 str = NULL; 02560 } else { 02561 status = cr_token_set_ident (token, 02562 str); 02563 CHECK_PARSING_STATUS (status, TRUE); 02564 if (str) { 02565 cr_parsing_location_copy (&token->location, 02566 &str->location) ; 02567 } 02568 str = NULL; 02569 } 02570 goto done; 02571 } else { 02572 if (str) { 02573 cr_string_destroy (str); 02574 str = NULL; 02575 } 02576 } 02577 } 02578 break; 02579 } 02580 02581 READ_NEXT_CHAR (a_this, &next_char); 02582 cr_tknzr_get_parsing_location (a_this, 02583 &location) ; 02584 status = cr_token_set_delim (token, next_char); 02585 CHECK_PARSING_STATUS (status, TRUE); 02586 cr_parsing_location_copy (&token->location, 02587 &location) ; 02588 done: 02589 02590 if (status == CR_OK && token) { 02591 *a_tk = token; 02592 /* 02593 *store the previous position input stream pos. 02594 */ 02595 memmove (&PRIVATE (a_this)->prev_pos, 02596 &init_pos, sizeof (CRInputPos)); 02597 return CR_OK; 02598 } 02599 02600 error: 02601 if (token) { 02602 cr_token_destroy (token); 02603 token = NULL; 02604 } 02605 02606 if (str) { 02607 cr_string_destroy (str); 02608 str = NULL; 02609 } 02610 cr_tknzr_set_cur_pos (a_this, &init_pos); 02611 return status; 02612 02613 } 02614 02615 enum CRStatus 02616 cr_tknzr_parse_token (CRTknzr * a_this, enum CRTokenType a_type, 02617 enum CRTokenExtraType a_et, gpointer a_res, 02618 gpointer a_extra_res) 02619 { 02620 enum CRStatus status = CR_OK; 02621 CRToken *token = NULL; 02622 02623 g_return_val_if_fail (a_this && PRIVATE (a_this) 02624 && PRIVATE (a_this)->input 02625 && a_res, CR_BAD_PARAM_ERROR); 02626 02627 status = cr_tknzr_get_next_token (a_this, &token); 02628 if (status != CR_OK) 02629 return status; 02630 if (token == NULL) 02631 return CR_PARSING_ERROR; 02632 02633 if (token->type == a_type) { 02634 switch (a_type) { 02635 case NO_TK: 02636 case S_TK: 02637 case CDO_TK: 02638 case CDC_TK: 02639 case INCLUDES_TK: 02640 case DASHMATCH_TK: 02641 case IMPORT_SYM_TK: 02642 case PAGE_SYM_TK: 02643 case MEDIA_SYM_TK: 02644 case FONT_FACE_SYM_TK: 02645 case CHARSET_SYM_TK: 02646 case IMPORTANT_SYM_TK: 02647 status = CR_OK; 02648 break; 02649 02650 case STRING_TK: 02651 case IDENT_TK: 02652 case HASH_TK: 02653 case ATKEYWORD_TK: 02654 case FUNCTION_TK: 02655 case COMMENT_TK: 02656 case URI_TK: 02657 *((CRString **) a_res) = token->u.str; 02658 token->u.str = NULL; 02659 status = CR_OK; 02660 break; 02661 02662 case EMS_TK: 02663 case EXS_TK: 02664 case PERCENTAGE_TK: 02665 case NUMBER_TK: 02666 *((CRNum **) a_res) = token->u.num; 02667 token->u.num = NULL; 02668 status = CR_OK; 02669 break; 02670 02671 case LENGTH_TK: 02672 case ANGLE_TK: 02673 case TIME_TK: 02674 case FREQ_TK: 02675 if (token->extra_type == a_et) { 02676 *((CRNum **) a_res) = token->u.num; 02677 token->u.num = NULL; 02678 status = CR_OK; 02679 } 02680 break; 02681 02682 case DIMEN_TK: 02683 *((CRNum **) a_res) = token->u.num; 02684 if (a_extra_res == NULL) { 02685 status = CR_BAD_PARAM_ERROR; 02686 goto error; 02687 } 02688 02689 *((CRString **) a_extra_res) = token->dimen; 02690 token->u.num = NULL; 02691 token->dimen = NULL; 02692 status = CR_OK; 02693 break; 02694 02695 case DELIM_TK: 02696 *((guint32 *) a_res) = token->u.unichar; 02697 status = CR_OK; 02698 break; 02699 02700 case UNICODERANGE_TK: 02701 default: 02702 status = CR_PARSING_ERROR; 02703 break; 02704 } 02705 02706 cr_token_destroy (token); 02707 token = NULL; 02708 } else { 02709 cr_tknzr_unget_token (a_this, token); 02710 token = NULL; 02711 status = CR_PARSING_ERROR; 02712 } 02713 02714 return status; 02715 02716 error: 02717 02718 if (token) { 02719 cr_tknzr_unget_token (a_this, token); 02720 token = NULL; 02721 } 02722 02723 return status; 02724 } 02725 02726 void 02727 cr_tknzr_destroy (CRTknzr * a_this) 02728 { 02729 g_return_if_fail (a_this); 02730 02731 if (PRIVATE (a_this) && PRIVATE (a_this)->input) { 02732 if (cr_input_unref (PRIVATE (a_this)->input) 02733 == TRUE) { 02734 PRIVATE (a_this)->input = NULL; 02735 } 02736 } 02737 02738 if (PRIVATE (a_this)->token_cache) { 02739 cr_token_destroy (PRIVATE (a_this)->token_cache); 02740 PRIVATE (a_this)->token_cache = NULL; 02741 } 02742 02743 if (PRIVATE (a_this)) { 02744 g_free (PRIVATE (a_this)); 02745 PRIVATE (a_this) = NULL; 02746 } 02747 02748 g_free (a_this); 02749 }