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 gulong 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 gulong 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 occurred. 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 ((const gchar *) 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 gulong consumed = *(gulong *) a_nb_char; 01905 enum CRStatus status; 01906 g_return_val_if_fail (a_this && PRIVATE (a_this) 01907 && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); 01908 01909 if (PRIVATE (a_this)->token_cache) { 01910 cr_input_set_cur_pos (PRIVATE (a_this)->input, 01911 &PRIVATE (a_this)->prev_pos); 01912 cr_token_destroy (PRIVATE (a_this)->token_cache); 01913 PRIVATE (a_this)->token_cache = NULL; 01914 } 01915 01916 status = cr_input_consume_chars (PRIVATE (a_this)->input, 01917 a_char, &consumed); 01918 *a_nb_char = (glong) consumed; 01919 return status; 01920 } 01921 01922 enum CRStatus 01923 cr_tknzr_set_cur_pos (CRTknzr * a_this, CRInputPos * a_pos) 01924 { 01925 g_return_val_if_fail (a_this && PRIVATE (a_this) 01926 && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR); 01927 01928 if (PRIVATE (a_this)->token_cache) { 01929 cr_token_destroy (PRIVATE (a_this)->token_cache); 01930 PRIVATE (a_this)->token_cache = NULL; 01931 } 01932 01933 return cr_input_set_cur_pos (PRIVATE (a_this)->input, a_pos); 01934 } 01935 01936 enum CRStatus 01937 cr_tknzr_unget_token (CRTknzr * a_this, CRToken * a_token) 01938 { 01939 g_return_val_if_fail (a_this && PRIVATE (a_this) 01940 && PRIVATE (a_this)->token_cache == NULL, 01941 CR_BAD_PARAM_ERROR); 01942 01943 PRIVATE (a_this)->token_cache = a_token; 01944 01945 return CR_OK; 01946 } 01947 01948 /** 01949 *Returns the next token of the input stream. 01950 *This method is really central. Each parsing 01951 *method calls it. 01952 *@param a_this the current tokenizer. 01953 *@param a_tk out parameter. The returned token. 01954 *for the sake of mem leak avoidance, *a_tk must 01955 *be NULL. 01956 *@param CR_OK upon successfull completion, an error code 01957 *otherwise. 01958 */ 01959 enum CRStatus 01960 cr_tknzr_get_next_token (CRTknzr * a_this, CRToken ** a_tk) 01961 { 01962 enum CRStatus status = CR_OK; 01963 CRToken *token = NULL; 01964 CRInputPos init_pos; 01965 guint32 next_char = 0; 01966 guchar next_bytes[4] = { 0 }; 01967 gboolean reached_eof = FALSE; 01968 CRInput *input = NULL; 01969 CRString *str = NULL; 01970 CRRgb *rgb = NULL; 01971 CRParsingLocation location = {0} ; 01972 01973 g_return_val_if_fail (a_this && PRIVATE (a_this) 01974 && a_tk && *a_tk == NULL 01975 && PRIVATE (a_this)->input, 01976 CR_BAD_PARAM_ERROR); 01977 01978 if (PRIVATE (a_this)->token_cache) { 01979 *a_tk = PRIVATE (a_this)->token_cache; 01980 PRIVATE (a_this)->token_cache = NULL; 01981 return CR_OK; 01982 } 01983 01984 RECORD_INITIAL_POS (a_this, &init_pos); 01985 01986 status = cr_input_get_end_of_file 01987 (PRIVATE (a_this)->input, &reached_eof); 01988 ENSURE_PARSING_COND (status == CR_OK); 01989 01990 if (reached_eof == TRUE) { 01991 status = CR_END_OF_INPUT_ERROR; 01992 goto error; 01993 } 01994 01995 input = PRIVATE (a_this)->input; 01996 01997 PEEK_NEXT_CHAR (a_this, &next_char); 01998 token = cr_token_new (); 01999 ENSURE_PARSING_COND (token); 02000 02001 switch (next_char) { 02002 case '@': 02003 { 02004 if (BYTE (input, 2, NULL) == 'f' 02005 && BYTE (input, 3, NULL) == 'o' 02006 && BYTE (input, 4, NULL) == 'n' 02007 && BYTE (input, 5, NULL) == 't' 02008 && BYTE (input, 6, NULL) == '-' 02009 && BYTE (input, 7, NULL) == 'f' 02010 && BYTE (input, 8, NULL) == 'a' 02011 && BYTE (input, 9, NULL) == 'c' 02012 && BYTE (input, 10, NULL) == 'e') { 02013 SKIP_CHARS (a_this, 1); 02014 cr_tknzr_get_parsing_location 02015 (a_this, &location) ; 02016 SKIP_CHARS (a_this, 9); 02017 status = cr_token_set_font_face_sym (token); 02018 CHECK_PARSING_STATUS (status, TRUE); 02019 cr_parsing_location_copy (&token->location, 02020 &location) ; 02021 goto done; 02022 } 02023 02024 if (BYTE (input, 2, NULL) == 'c' 02025 && BYTE (input, 3, NULL) == 'h' 02026 && BYTE (input, 4, NULL) == 'a' 02027 && BYTE (input, 5, NULL) == 'r' 02028 && BYTE (input, 6, NULL) == 's' 02029 && BYTE (input, 7, NULL) == 'e' 02030 && BYTE (input, 8, NULL) == 't') { 02031 SKIP_CHARS (a_this, 1); 02032 cr_tknzr_get_parsing_location 02033 (a_this, &location) ; 02034 SKIP_CHARS (a_this, 7); 02035 status = cr_token_set_charset_sym (token); 02036 CHECK_PARSING_STATUS (status, TRUE); 02037 cr_parsing_location_copy (&token->location, 02038 &location) ; 02039 goto done; 02040 } 02041 02042 if (BYTE (input, 2, NULL) == 'i' 02043 && BYTE (input, 3, NULL) == 'm' 02044 && BYTE (input, 4, NULL) == 'p' 02045 && BYTE (input, 5, NULL) == 'o' 02046 && BYTE (input, 6, NULL) == 'r' 02047 && BYTE (input, 7, NULL) == 't') { 02048 SKIP_CHARS (a_this, 1); 02049 cr_tknzr_get_parsing_location 02050 (a_this, &location) ; 02051 SKIP_CHARS (a_this, 6); 02052 status = cr_token_set_import_sym (token); 02053 CHECK_PARSING_STATUS (status, TRUE); 02054 cr_parsing_location_copy (&token->location, 02055 &location) ; 02056 goto done; 02057 } 02058 02059 if (BYTE (input, 2, NULL) == 'm' 02060 && BYTE (input, 3, NULL) == 'e' 02061 && BYTE (input, 4, NULL) == 'd' 02062 && BYTE (input, 5, NULL) == 'i' 02063 && BYTE (input, 6, NULL) == 'a') { 02064 SKIP_CHARS (a_this, 1); 02065 cr_tknzr_get_parsing_location (a_this, 02066 &location) ; 02067 SKIP_CHARS (a_this, 5); 02068 status = cr_token_set_media_sym (token); 02069 CHECK_PARSING_STATUS (status, TRUE); 02070 cr_parsing_location_copy (&token->location, 02071 &location) ; 02072 goto done; 02073 } 02074 02075 if (BYTE (input, 2, NULL) == 'p' 02076 && BYTE (input, 3, NULL) == 'a' 02077 && BYTE (input, 4, NULL) == 'g' 02078 && BYTE (input, 5, NULL) == 'e') { 02079 SKIP_CHARS (a_this, 1); 02080 cr_tknzr_get_parsing_location (a_this, 02081 &location) ; 02082 SKIP_CHARS (a_this, 4); 02083 status = cr_token_set_page_sym (token); 02084 CHECK_PARSING_STATUS (status, TRUE); 02085 cr_parsing_location_copy (&token->location, 02086 &location) ; 02087 goto done; 02088 } 02089 status = cr_tknzr_parse_atkeyword (a_this, &str); 02090 if (status == CR_OK) { 02091 status = cr_token_set_atkeyword (token, str); 02092 CHECK_PARSING_STATUS (status, TRUE); 02093 if (str) { 02094 cr_parsing_location_copy (&token->location, 02095 &str->location) ; 02096 } 02097 goto done; 02098 } 02099 } 02100 break; 02101 02102 case 'u': 02103 02104 if (BYTE (input, 2, NULL) == 'r' 02105 && BYTE (input, 3, NULL) == 'l' 02106 && BYTE (input, 4, NULL) == '(') { 02107 CRString *str2 = NULL; 02108 02109 status = cr_tknzr_parse_uri (a_this, &str2); 02110 if (status == CR_OK) { 02111 status = cr_token_set_uri (token, str2); 02112 CHECK_PARSING_STATUS (status, TRUE); 02113 if (str2) { 02114 cr_parsing_location_copy (&token->location, 02115 &str2->location) ; 02116 } 02117 goto done; 02118 } 02119 } 02120 goto fallback; 02121 break; 02122 02123 case 'r': 02124 if (BYTE (input, 2, NULL) == 'g' 02125 && BYTE (input, 3, NULL) == 'b' 02126 && BYTE (input, 4, NULL) == '(') { 02127 status = cr_tknzr_parse_rgb (a_this, &rgb); 02128 if (status == CR_OK && rgb) { 02129 status = cr_token_set_rgb (token, rgb); 02130 CHECK_PARSING_STATUS (status, TRUE); 02131 if (rgb) { 02132 cr_parsing_location_copy (&token->location, 02133 &rgb->location) ; 02134 } 02135 rgb = NULL; 02136 goto done; 02137 } 02138 02139 } 02140 goto fallback; 02141 break; 02142 02143 case '<': 02144 if (BYTE (input, 2, NULL) == '!' 02145 && BYTE (input, 3, NULL) == '-' 02146 && BYTE (input, 4, NULL) == '-') { 02147 SKIP_CHARS (a_this, 1); 02148 cr_tknzr_get_parsing_location (a_this, 02149 &location) ; 02150 SKIP_CHARS (a_this, 3); 02151 status = cr_token_set_cdo (token); 02152 CHECK_PARSING_STATUS (status, TRUE); 02153 cr_parsing_location_copy (&token->location, 02154 &location) ; 02155 goto done; 02156 } 02157 break; 02158 02159 case '-': 02160 if (BYTE (input, 2, NULL) == '-' 02161 && BYTE (input, 3, NULL) == '>') { 02162 SKIP_CHARS (a_this, 1); 02163 cr_tknzr_get_parsing_location (a_this, 02164 &location) ; 02165 SKIP_CHARS (a_this, 2); 02166 status = cr_token_set_cdc (token); 02167 CHECK_PARSING_STATUS (status, TRUE); 02168 cr_parsing_location_copy (&token->location, 02169 &location) ; 02170 goto done; 02171 } else { 02172 status = cr_tknzr_parse_ident 02173 (a_this, &str); 02174 if (status == CR_OK) { 02175 cr_token_set_ident 02176 (token, str); 02177 if (str) { 02178 cr_parsing_location_copy (&token->location, 02179 &str->location) ; 02180 } 02181 goto done; 02182 } else { 02183 goto parse_number; 02184 } 02185 } 02186 break; 02187 02188 case '~': 02189 if (BYTE (input, 2, NULL) == '=') { 02190 SKIP_CHARS (a_this, 1); 02191 cr_tknzr_get_parsing_location (a_this, 02192 &location) ; 02193 SKIP_CHARS (a_this, 1); 02194 status = cr_token_set_includes (token); 02195 CHECK_PARSING_STATUS (status, TRUE); 02196 cr_parsing_location_copy (&token->location, 02197 &location) ; 02198 goto done; 02199 } 02200 break; 02201 02202 case '|': 02203 if (BYTE (input, 2, NULL) == '=') { 02204 SKIP_CHARS (a_this, 1); 02205 cr_tknzr_get_parsing_location (a_this, 02206 &location) ; 02207 SKIP_CHARS (a_this, 1); 02208 status = cr_token_set_dashmatch (token); 02209 CHECK_PARSING_STATUS (status, TRUE); 02210 cr_parsing_location_copy (&token->location, 02211 &location) ; 02212 goto done; 02213 } 02214 break; 02215 02216 case '/': 02217 if (BYTE (input, 2, NULL) == '*') { 02218 status = cr_tknzr_parse_comment (a_this, &str); 02219 02220 if (status == CR_OK) { 02221 status = cr_token_set_comment (token, str); 02222 str = NULL; 02223 CHECK_PARSING_STATUS (status, TRUE); 02224 if (str) { 02225 cr_parsing_location_copy (&token->location, 02226 &str->location) ; 02227 } 02228 goto done; 02229 } 02230 } 02231 break ; 02232 02233 case ';': 02234 SKIP_CHARS (a_this, 1); 02235 cr_tknzr_get_parsing_location (a_this, 02236 &location) ; 02237 status = cr_token_set_semicolon (token); 02238 CHECK_PARSING_STATUS (status, TRUE); 02239 cr_parsing_location_copy (&token->location, 02240 &location) ; 02241 goto done; 02242 02243 case '{': 02244 SKIP_CHARS (a_this, 1); 02245 cr_tknzr_get_parsing_location (a_this, 02246 &location) ; 02247 status = cr_token_set_cbo (token); 02248 CHECK_PARSING_STATUS (status, TRUE); 02249 cr_tknzr_get_parsing_location (a_this, 02250 &location) ; 02251 goto done; 02252 02253 case '}': 02254 SKIP_CHARS (a_this, 1); 02255 cr_tknzr_get_parsing_location (a_this, 02256 &location) ; 02257 status = cr_token_set_cbc (token); 02258 CHECK_PARSING_STATUS (status, TRUE); 02259 cr_parsing_location_copy (&token->location, 02260 &location) ; 02261 goto done; 02262 02263 case '(': 02264 SKIP_CHARS (a_this, 1); 02265 cr_tknzr_get_parsing_location (a_this, 02266 &location) ; 02267 status = cr_token_set_po (token); 02268 CHECK_PARSING_STATUS (status, TRUE); 02269 cr_parsing_location_copy (&token->location, 02270 &location) ; 02271 goto done; 02272 02273 case ')': 02274 SKIP_CHARS (a_this, 1); 02275 cr_tknzr_get_parsing_location (a_this, 02276 &location) ; 02277 status = cr_token_set_pc (token); 02278 CHECK_PARSING_STATUS (status, TRUE); 02279 cr_parsing_location_copy (&token->location, 02280 &location) ; 02281 goto done; 02282 02283 case '[': 02284 SKIP_CHARS (a_this, 1); 02285 cr_tknzr_get_parsing_location (a_this, 02286 &location) ; 02287 status = cr_token_set_bo (token); 02288 CHECK_PARSING_STATUS (status, TRUE); 02289 cr_parsing_location_copy (&token->location, 02290 &location) ; 02291 goto done; 02292 02293 case ']': 02294 SKIP_CHARS (a_this, 1); 02295 cr_tknzr_get_parsing_location (a_this, 02296 &location) ; 02297 status = cr_token_set_bc (token); 02298 CHECK_PARSING_STATUS (status, TRUE); 02299 cr_parsing_location_copy (&token->location, 02300 &location) ; 02301 goto done; 02302 02303 case ' ': 02304 case '\t': 02305 case '\n': 02306 case '\f': 02307 case '\r': 02308 { 02309 guchar *start = NULL, 02310 *end = NULL; 02311 02312 status = cr_tknzr_parse_w (a_this, &start, 02313 &end, &location); 02314 if (status == CR_OK) { 02315 status = cr_token_set_s (token); 02316 CHECK_PARSING_STATUS (status, TRUE); 02317 cr_tknzr_get_parsing_location (a_this, 02318 &location) ; 02319 goto done; 02320 } 02321 } 02322 break; 02323 02324 case '#': 02325 { 02326 status = cr_tknzr_parse_hash (a_this, &str); 02327 if (status == CR_OK && str) { 02328 status = cr_token_set_hash (token, str); 02329 CHECK_PARSING_STATUS (status, TRUE); 02330 if (str) { 02331 cr_parsing_location_copy (&token->location, 02332 &str->location) ; 02333 } 02334 str = NULL; 02335 goto done; 02336 } 02337 } 02338 break; 02339 02340 case '\'': 02341 case '"': 02342 status = cr_tknzr_parse_string (a_this, &str); 02343 if (status == CR_OK && str) { 02344 status = cr_token_set_string (token, str); 02345 CHECK_PARSING_STATUS (status, TRUE); 02346 if (str) { 02347 cr_parsing_location_copy (&token->location, 02348 &str->location) ; 02349 } 02350 str = NULL; 02351 goto done; 02352 } 02353 break; 02354 02355 case '!': 02356 status = cr_tknzr_parse_important (a_this, &location); 02357 if (status == CR_OK) { 02358 status = cr_token_set_important_sym (token); 02359 CHECK_PARSING_STATUS (status, TRUE); 02360 cr_parsing_location_copy (&token->location, 02361 &location) ; 02362 goto done; 02363 } 02364 break; 02365 02366 case '0': 02367 case '1': 02368 case '2': 02369 case '3': 02370 case '4': 02371 case '5': 02372 case '6': 02373 case '7': 02374 case '8': 02375 case '9': 02376 case '.': 02377 case '+': 02378 /* '-' case is handled separately above for --> comments */ 02379 parse_number: 02380 { 02381 CRNum *num = NULL; 02382 02383 status = cr_tknzr_parse_num (a_this, &num); 02384 if (status == CR_OK && num) { 02385 next_bytes[0] = BYTE (input, 1, NULL); 02386 next_bytes[1] = BYTE (input, 2, NULL); 02387 next_bytes[2] = BYTE (input, 3, NULL); 02388 next_bytes[3] = BYTE (input, 4, NULL); 02389 02390 if (next_bytes[0] == 'e' 02391 && next_bytes[1] == 'm') { 02392 num->type = NUM_LENGTH_EM; 02393 status = cr_token_set_ems (token, 02394 num); 02395 num = NULL; 02396 SKIP_CHARS (a_this, 2); 02397 } else if (next_bytes[0] == 'e' 02398 && next_bytes[1] == 'x') { 02399 num->type = NUM_LENGTH_EX; 02400 status = cr_token_set_exs (token, 02401 num); 02402 num = NULL; 02403 SKIP_CHARS (a_this, 2); 02404 } else if (next_bytes[0] == 'p' 02405 && next_bytes[1] == 'x') { 02406 num->type = NUM_LENGTH_PX; 02407 status = cr_token_set_length 02408 (token, num, LENGTH_PX_ET); 02409 num = NULL; 02410 SKIP_CHARS (a_this, 2); 02411 } else if (next_bytes[0] == 'c' 02412 && next_bytes[1] == 'm') { 02413 num->type = NUM_LENGTH_CM; 02414 status = cr_token_set_length 02415 (token, num, LENGTH_CM_ET); 02416 num = NULL; 02417 SKIP_CHARS (a_this, 2); 02418 } else if (next_bytes[0] == 'm' 02419 && next_bytes[1] == 'm') { 02420 num->type = NUM_LENGTH_MM; 02421 status = cr_token_set_length 02422 (token, num, LENGTH_MM_ET); 02423 num = NULL; 02424 SKIP_CHARS (a_this, 2); 02425 } else if (next_bytes[0] == 'i' 02426 && next_bytes[1] == 'n') { 02427 num->type = NUM_LENGTH_IN; 02428 status = cr_token_set_length 02429 (token, num, LENGTH_IN_ET); 02430 num = NULL; 02431 SKIP_CHARS (a_this, 2); 02432 } else if (next_bytes[0] == 'p' 02433 && next_bytes[1] == 't') { 02434 num->type = NUM_LENGTH_PT; 02435 status = cr_token_set_length 02436 (token, num, LENGTH_PT_ET); 02437 num = NULL; 02438 SKIP_CHARS (a_this, 2); 02439 } else if (next_bytes[0] == 'p' 02440 && next_bytes[1] == 'c') { 02441 num->type = NUM_LENGTH_PC; 02442 status = cr_token_set_length 02443 (token, num, LENGTH_PC_ET); 02444 num = NULL; 02445 SKIP_CHARS (a_this, 2); 02446 } else if (next_bytes[0] == 'd' 02447 && next_bytes[1] == 'e' 02448 && next_bytes[2] == 'g') { 02449 num->type = NUM_ANGLE_DEG; 02450 status = cr_token_set_angle 02451 (token, num, ANGLE_DEG_ET); 02452 num = NULL; 02453 SKIP_CHARS (a_this, 3); 02454 } else if (next_bytes[0] == 'r' 02455 && next_bytes[1] == 'a' 02456 && next_bytes[2] == 'd') { 02457 num->type = NUM_ANGLE_RAD; 02458 status = cr_token_set_angle 02459 (token, num, ANGLE_RAD_ET); 02460 num = NULL; 02461 SKIP_CHARS (a_this, 3); 02462 } else if (next_bytes[0] == 'g' 02463 && next_bytes[1] == 'r' 02464 && next_bytes[2] == 'a' 02465 && next_bytes[3] == 'd') { 02466 num->type = NUM_ANGLE_GRAD; 02467 status = cr_token_set_angle 02468 (token, num, ANGLE_GRAD_ET); 02469 num = NULL; 02470 SKIP_CHARS (a_this, 4); 02471 } else if (next_bytes[0] == 'm' 02472 && next_bytes[1] == 's') { 02473 num->type = NUM_TIME_MS; 02474 status = cr_token_set_time 02475 (token, num, TIME_MS_ET); 02476 num = NULL; 02477 SKIP_CHARS (a_this, 2); 02478 } else if (next_bytes[0] == 's') { 02479 num->type = NUM_TIME_S; 02480 status = cr_token_set_time 02481 (token, num, TIME_S_ET); 02482 num = NULL; 02483 SKIP_CHARS (a_this, 1); 02484 } else if (next_bytes[0] == 'H' 02485 && next_bytes[1] == 'z') { 02486 num->type = NUM_FREQ_HZ; 02487 status = cr_token_set_freq 02488 (token, num, FREQ_HZ_ET); 02489 num = NULL; 02490 SKIP_CHARS (a_this, 2); 02491 } else if (next_bytes[0] == 'k' 02492 && next_bytes[1] == 'H' 02493 && next_bytes[2] == 'z') { 02494 num->type = NUM_FREQ_KHZ; 02495 status = cr_token_set_freq 02496 (token, num, FREQ_KHZ_ET); 02497 num = NULL; 02498 SKIP_CHARS (a_this, 3); 02499 } else if (next_bytes[0] == '%') { 02500 num->type = NUM_PERCENTAGE; 02501 status = cr_token_set_percentage 02502 (token, num); 02503 num = NULL; 02504 SKIP_CHARS (a_this, 1); 02505 } else { 02506 status = cr_tknzr_parse_ident (a_this, 02507 &str); 02508 if (status == CR_OK && str) { 02509 num->type = NUM_UNKNOWN_TYPE; 02510 status = cr_token_set_dimen 02511 (token, num, str); 02512 num = NULL; 02513 CHECK_PARSING_STATUS (status, 02514 TRUE); 02515 str = NULL; 02516 } else { 02517 status = cr_token_set_number 02518 (token, num); 02519 num = NULL; 02520 CHECK_PARSING_STATUS (status, CR_OK); 02521 str = NULL; 02522 } 02523 } 02524 if (token && token->u.num) { 02525 cr_parsing_location_copy (&token->location, 02526 &token->u.num->location) ; 02527 } else { 02528 status = CR_ERROR ; 02529 } 02530 goto done ; 02531 } 02532 } 02533 break; 02534 02535 default: 02536 fallback: 02537 /*process the fallback cases here */ 02538 02539 if (next_char == '\\' 02540 || (cr_utils_is_nonascii (next_bytes[0]) == TRUE) 02541 || ((next_char >= 'a') && (next_char <= 'z')) 02542 || ((next_char >= 'A') && (next_char <= 'Z'))) { 02543 status = cr_tknzr_parse_ident (a_this, &str); 02544 if (status == CR_OK && str) { 02545 guint32 next_c = 0; 02546 02547 status = cr_input_peek_char 02548 (PRIVATE (a_this)->input, &next_c); 02549 02550 if (status == CR_OK && next_c == '(') { 02551 02552 SKIP_CHARS (a_this, 1); 02553 status = cr_token_set_function 02554 (token, str); 02555 CHECK_PARSING_STATUS (status, TRUE); 02556 /*ownership is transfered 02557 *to token by cr_token_set_function. 02558 */ 02559 if (str) { 02560 cr_parsing_location_copy (&token->location, 02561 &str->location) ; 02562 } 02563 str = NULL; 02564 } else { 02565 status = cr_token_set_ident (token, 02566 str); 02567 CHECK_PARSING_STATUS (status, TRUE); 02568 if (str) { 02569 cr_parsing_location_copy (&token->location, 02570 &str->location) ; 02571 } 02572 str = NULL; 02573 } 02574 goto done; 02575 } else { 02576 if (str) { 02577 cr_string_destroy (str); 02578 str = NULL; 02579 } 02580 } 02581 } 02582 break; 02583 } 02584 02585 READ_NEXT_CHAR (a_this, &next_char); 02586 cr_tknzr_get_parsing_location (a_this, 02587 &location) ; 02588 status = cr_token_set_delim (token, next_char); 02589 CHECK_PARSING_STATUS (status, TRUE); 02590 cr_parsing_location_copy (&token->location, 02591 &location) ; 02592 done: 02593 02594 if (status == CR_OK && token) { 02595 *a_tk = token; 02596 /* 02597 *store the previous position input stream pos. 02598 */ 02599 memmove (&PRIVATE (a_this)->prev_pos, 02600 &init_pos, sizeof (CRInputPos)); 02601 return CR_OK; 02602 } 02603 02604 error: 02605 if (token) { 02606 cr_token_destroy (token); 02607 token = NULL; 02608 } 02609 02610 if (str) { 02611 cr_string_destroy (str); 02612 str = NULL; 02613 } 02614 cr_tknzr_set_cur_pos (a_this, &init_pos); 02615 return status; 02616 02617 } 02618 02619 enum CRStatus 02620 cr_tknzr_parse_token (CRTknzr * a_this, enum CRTokenType a_type, 02621 enum CRTokenExtraType a_et, gpointer a_res, 02622 gpointer a_extra_res) 02623 { 02624 enum CRStatus status = CR_OK; 02625 CRToken *token = NULL; 02626 02627 g_return_val_if_fail (a_this && PRIVATE (a_this) 02628 && PRIVATE (a_this)->input 02629 && a_res, CR_BAD_PARAM_ERROR); 02630 02631 status = cr_tknzr_get_next_token (a_this, &token); 02632 if (status != CR_OK) 02633 return status; 02634 if (token == NULL) 02635 return CR_PARSING_ERROR; 02636 02637 if (token->type == a_type) { 02638 switch (a_type) { 02639 case NO_TK: 02640 case S_TK: 02641 case CDO_TK: 02642 case CDC_TK: 02643 case INCLUDES_TK: 02644 case DASHMATCH_TK: 02645 case IMPORT_SYM_TK: 02646 case PAGE_SYM_TK: 02647 case MEDIA_SYM_TK: 02648 case FONT_FACE_SYM_TK: 02649 case CHARSET_SYM_TK: 02650 case IMPORTANT_SYM_TK: 02651 status = CR_OK; 02652 break; 02653 02654 case STRING_TK: 02655 case IDENT_TK: 02656 case HASH_TK: 02657 case ATKEYWORD_TK: 02658 case FUNCTION_TK: 02659 case COMMENT_TK: 02660 case URI_TK: 02661 *((CRString **) a_res) = token->u.str; 02662 token->u.str = NULL; 02663 status = CR_OK; 02664 break; 02665 02666 case EMS_TK: 02667 case EXS_TK: 02668 case PERCENTAGE_TK: 02669 case NUMBER_TK: 02670 *((CRNum **) a_res) = token->u.num; 02671 token->u.num = NULL; 02672 status = CR_OK; 02673 break; 02674 02675 case LENGTH_TK: 02676 case ANGLE_TK: 02677 case TIME_TK: 02678 case FREQ_TK: 02679 if (token->extra_type == a_et) { 02680 *((CRNum **) a_res) = token->u.num; 02681 token->u.num = NULL; 02682 status = CR_OK; 02683 } 02684 break; 02685 02686 case DIMEN_TK: 02687 *((CRNum **) a_res) = token->u.num; 02688 if (a_extra_res == NULL) { 02689 status = CR_BAD_PARAM_ERROR; 02690 goto error; 02691 } 02692 02693 *((CRString **) a_extra_res) = token->dimen; 02694 token->u.num = NULL; 02695 token->dimen = NULL; 02696 status = CR_OK; 02697 break; 02698 02699 case DELIM_TK: 02700 *((guint32 *) a_res) = token->u.unichar; 02701 status = CR_OK; 02702 break; 02703 02704 case UNICODERANGE_TK: 02705 default: 02706 status = CR_PARSING_ERROR; 02707 break; 02708 } 02709 02710 cr_token_destroy (token); 02711 token = NULL; 02712 } else { 02713 cr_tknzr_unget_token (a_this, token); 02714 token = NULL; 02715 status = CR_PARSING_ERROR; 02716 } 02717 02718 return status; 02719 02720 error: 02721 02722 if (token) { 02723 cr_tknzr_unget_token (a_this, token); 02724 token = NULL; 02725 } 02726 02727 return status; 02728 } 02729 02730 void 02731 cr_tknzr_destroy (CRTknzr * a_this) 02732 { 02733 g_return_if_fail (a_this); 02734 02735 if (PRIVATE (a_this) && PRIVATE (a_this)->input) { 02736 if (cr_input_unref (PRIVATE (a_this)->input) 02737 == TRUE) { 02738 PRIVATE (a_this)->input = NULL; 02739 } 02740 } 02741 02742 if (PRIVATE (a_this)->token_cache) { 02743 cr_token_destroy (PRIVATE (a_this)->token_cache); 02744 PRIVATE (a_this)->token_cache = NULL; 02745 } 02746 02747 if (PRIVATE (a_this)) { 02748 g_free (PRIVATE (a_this)); 02749 PRIVATE (a_this) = NULL; 02750 } 02751 02752 g_free (a_this); 02753 }