1 /* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
3 /*
4 * This file is part of The Croco Library
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2.1 of the GNU Lesser General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18 * USA
19 *
20 * Author: Dodji Seketeli
21 * See COPYRIGHTS file for copyright information.
22 */
24 #include <string.h>
25 #include "cr-utils.h"
26 #include "cr-om-parser.h"
28 #define UNUSED(_param) ((void)(_param))
30 /**
31 *@file
32 *The definition of the CSS Object Model Parser.
33 *This parser uses (and sits) the SAC api of libcroco defined
34 *in cr-parser.h and cr-doc-handler.h
35 */
37 struct _CROMParserPriv {
38 CRParser *parser;
39 };
41 #define PRIVATE(a_this) ((a_this)->priv)
43 /*
44 *Forward declaration of a type defined later
45 *in this file.
46 */
47 struct _ParsingContext;
48 typedef struct _ParsingContext ParsingContext;
50 static ParsingContext *new_parsing_context (void);
52 static void destroy_context (ParsingContext * a_ctxt);
54 static void unrecoverable_error (CRDocHandler * a_this);
56 static void error (CRDocHandler * a_this);
58 static void property (CRDocHandler * a_this,
59 CRString * a_name,
60 CRTerm * a_expression,
61 gboolean a_important);
63 static void end_selector (CRDocHandler * a_this,
64 CRSelector * a_selector_list);
66 static void start_selector (CRDocHandler * a_this,
67 CRSelector * a_selector_list);
69 static void start_font_face (CRDocHandler * a_this,
70 CRParsingLocation *a_location);
72 static void end_font_face (CRDocHandler * a_this);
74 static void end_document (CRDocHandler * a_this);
76 static void start_document (CRDocHandler * a_this);
78 static void charset (CRDocHandler * a_this,
79 CRString * a_charset,
80 CRParsingLocation *a_location);
82 static void start_page (CRDocHandler * a_this, CRString * a_page,
83 CRString * a_pseudo_page,
84 CRParsingLocation *a_location);
86 static void end_page (CRDocHandler * a_this, CRString * a_page,
87 CRString * a_pseudo_page);
89 static void start_media (CRDocHandler * a_this,
90 GList * a_media_list,
91 CRParsingLocation *a_location);
93 static void end_media (CRDocHandler * a_this,
94 GList * a_media_list);
96 static void import_style (CRDocHandler * a_this,
97 GList * a_media_list,
98 CRString * a_uri,
99 CRString * a_uri_default_ns,
100 CRParsingLocation *a_location);
102 struct _ParsingContext {
103 CRStyleSheet *stylesheet;
104 CRStatement *cur_stmt;
105 CRStatement *cur_media_stmt;
106 };
108 /********************************************
109 *Private methods
110 ********************************************/
112 static ParsingContext *
113 new_parsing_context (void)
114 {
115 ParsingContext *result =
116 (ParsingContext *)g_try_malloc (sizeof (ParsingContext));
117 if (!result) {
118 cr_utils_trace_info ("Out of Memory");
119 return NULL;
120 }
121 memset (result, 0, sizeof (ParsingContext));
122 return result;
123 }
125 static void
126 destroy_context (ParsingContext * a_ctxt)
127 {
128 g_return_if_fail (a_ctxt);
130 if (a_ctxt->stylesheet) {
131 cr_stylesheet_destroy (a_ctxt->stylesheet);
132 a_ctxt->stylesheet = NULL;
133 }
134 if (a_ctxt->cur_stmt) {
135 cr_statement_destroy (a_ctxt->cur_stmt);
136 a_ctxt->cur_stmt = NULL;
137 }
138 g_free (a_ctxt);
139 }
141 static enum CRStatus
142 cr_om_parser_init_default_sac_handler (CROMParser * a_this)
143 {
144 CRDocHandler *sac_handler = NULL;
145 gboolean free_hdlr_if_error = FALSE;
146 enum CRStatus status = CR_OK;
148 g_return_val_if_fail (a_this && PRIVATE (a_this)
149 && PRIVATE (a_this)->parser,
150 CR_BAD_PARAM_ERROR);
152 status = cr_parser_get_sac_handler (PRIVATE (a_this)->parser,
153 &sac_handler);
154 g_return_val_if_fail (status == CR_OK, status);
156 if (!sac_handler) {
157 sac_handler = cr_doc_handler_new ();
158 free_hdlr_if_error = TRUE;
159 }
161 /*
162 *initialyze here the sac handler.
163 */
164 sac_handler->start_document = start_document;
165 sac_handler->end_document = end_document;
166 sac_handler->start_selector = start_selector;
167 sac_handler->end_selector = end_selector;
168 sac_handler->property = property;
169 sac_handler->start_font_face = start_font_face;
170 sac_handler->end_font_face = end_font_face;
171 sac_handler->error = error;
172 sac_handler->unrecoverable_error = unrecoverable_error;
173 sac_handler->charset = charset;
174 sac_handler->start_page = start_page;
175 sac_handler->end_page = end_page;
176 sac_handler->start_media = start_media;
177 sac_handler->end_media = end_media;
178 sac_handler->import_style = import_style;
180 status = cr_parser_set_sac_handler (PRIVATE (a_this)->parser,
181 sac_handler);
182 if (status == CR_OK) {
183 return CR_OK;
184 }
186 if (sac_handler && free_hdlr_if_error == TRUE) {
187 cr_doc_handler_destroy (sac_handler);
188 sac_handler = NULL;
189 }
191 return status;
193 }
195 static void
196 start_document (CRDocHandler * a_this)
197 {
198 ParsingContext *ctxt = NULL;
199 CRStyleSheet *stylesheet = NULL;
201 g_return_if_fail (a_this);
203 ctxt = new_parsing_context ();
204 g_return_if_fail (ctxt);
206 stylesheet = cr_stylesheet_new (NULL);
207 ctxt->stylesheet = stylesheet;
208 cr_doc_handler_set_ctxt (a_this, ctxt);
209 }
211 static void
212 start_font_face (CRDocHandler * a_this,
213 CRParsingLocation *a_location)
214 {
215 enum CRStatus status = CR_OK;
216 ParsingContext *ctxt = NULL;
217 ParsingContext **ctxtptr = NULL;
219 UNUSED(a_location);
221 g_return_if_fail (a_this);
222 ctxtptr = &ctxt;
223 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
224 g_return_if_fail (status == CR_OK && ctxt);
225 g_return_if_fail (ctxt->cur_stmt == NULL);
227 ctxt->cur_stmt =
228 cr_statement_new_at_font_face_rule (ctxt->stylesheet, NULL);
230 g_return_if_fail (ctxt->cur_stmt);
231 }
233 static void
234 end_font_face (CRDocHandler * a_this)
235 {
236 enum CRStatus status = CR_OK;
237 ParsingContext *ctxt = NULL;
238 ParsingContext **ctxtptr = NULL;
239 CRStatement *stmts = NULL;
241 g_return_if_fail (a_this);
243 g_return_if_fail (a_this);
244 ctxtptr = &ctxt;
245 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
246 g_return_if_fail (status == CR_OK && ctxt);
247 g_return_if_fail
248 (ctxt->cur_stmt
249 && ctxt->cur_stmt->type == AT_FONT_FACE_RULE_STMT
250 && ctxt->stylesheet);
252 stmts = cr_statement_append (ctxt->stylesheet->statements,
253 ctxt->cur_stmt);
254 if (!stmts)
255 goto error;
257 ctxt->stylesheet->statements = stmts;
258 stmts = NULL;
259 ctxt->cur_stmt = NULL;
261 return;
263 error:
265 if (ctxt->cur_stmt) {
266 cr_statement_destroy (ctxt->cur_stmt);
267 ctxt->cur_stmt = NULL;
268 }
270 if (!stmts) {
271 cr_statement_destroy (stmts);
272 stmts = NULL;
273 }
274 }
276 static void
277 end_document (CRDocHandler * a_this)
278 {
279 enum CRStatus status = CR_OK;
280 ParsingContext *ctxt = NULL;
281 ParsingContext **ctxtptr = NULL;
283 g_return_if_fail (a_this);
284 ctxtptr = &ctxt;
285 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
286 g_return_if_fail (status == CR_OK && ctxt);
288 if (!ctxt->stylesheet || ctxt->cur_stmt)
289 goto error;
291 status = cr_doc_handler_set_result (a_this, ctxt->stylesheet);
292 g_return_if_fail (status == CR_OK);
294 ctxt->stylesheet = NULL;
295 destroy_context (ctxt);
296 cr_doc_handler_set_ctxt (a_this, NULL);
298 return;
300 error:
301 if (ctxt) {
302 destroy_context (ctxt);
303 }
304 }
306 static void
307 charset (CRDocHandler * a_this, CRString * a_charset,
308 CRParsingLocation *a_location)
309 {
310 enum CRStatus status = CR_OK;
311 CRStatement *stmt = NULL,
312 *stmt2 = NULL;
313 CRString *charset = NULL;
315 ParsingContext *ctxt = NULL;
316 ParsingContext **ctxtptr = NULL;
318 UNUSED(a_location);
320 g_return_if_fail (a_this);
321 ctxtptr = &ctxt;
322 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
323 g_return_if_fail (status == CR_OK && ctxt);
324 g_return_if_fail (ctxt->stylesheet);
326 charset = cr_string_dup (a_charset) ;
327 stmt = cr_statement_new_at_charset_rule (ctxt->stylesheet, charset);
328 g_return_if_fail (stmt);
329 stmt2 = cr_statement_append (ctxt->stylesheet->statements, stmt);
330 if (!stmt2) {
331 if (stmt) {
332 cr_statement_destroy (stmt);
333 stmt = NULL;
334 }
335 if (charset) {
336 cr_string_destroy (charset);
337 }
338 return;
339 }
340 ctxt->stylesheet->statements = stmt2;
341 stmt2 = NULL;
342 }
344 static void
345 start_page (CRDocHandler * a_this,
346 CRString * a_page,
347 CRString * a_pseudo,
348 CRParsingLocation *a_location)
349 {
350 enum CRStatus status = CR_OK;
351 ParsingContext *ctxt = NULL;
352 ParsingContext **ctxtptr = NULL;
354 UNUSED(a_location);
356 g_return_if_fail (a_this);
357 ctxtptr = &ctxt;
358 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
359 g_return_if_fail (status == CR_OK && ctxt);
360 g_return_if_fail (ctxt->cur_stmt == NULL);
362 ctxt->cur_stmt = cr_statement_new_at_page_rule
363 (ctxt->stylesheet, NULL, NULL, NULL);
364 if (a_page) {
365 ctxt->cur_stmt->kind.page_rule->name =
366 cr_string_dup (a_page) ;
368 if (!ctxt->cur_stmt->kind.page_rule->name) {
369 goto error;
370 }
371 }
372 if (a_pseudo) {
373 ctxt->cur_stmt->kind.page_rule->pseudo =
374 cr_string_dup (a_pseudo) ;
375 if (!ctxt->cur_stmt->kind.page_rule->pseudo) {
376 goto error;
377 }
378 }
379 return;
381 error:
382 if (ctxt->cur_stmt) {
383 cr_statement_destroy (ctxt->cur_stmt);
384 ctxt->cur_stmt = NULL;
385 }
386 }
388 static void
389 end_page (CRDocHandler * a_this,
390 CRString * a_page,
391 CRString * a_pseudo_page)
392 {
393 enum CRStatus status = CR_OK;
394 ParsingContext *ctxt = NULL;
395 ParsingContext **ctxtptr = NULL;
396 CRStatement *stmt = NULL;
398 g_return_if_fail (a_this);
399 ctxtptr = &ctxt;
400 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
401 g_return_if_fail (status == CR_OK && ctxt);
402 g_return_if_fail (ctxt->cur_stmt
403 && ctxt->cur_stmt->type == AT_PAGE_RULE_STMT
404 && ctxt->stylesheet);
406 stmt = cr_statement_append (ctxt->stylesheet->statements,
407 ctxt->cur_stmt);
409 if (stmt) {
410 ctxt->stylesheet->statements = stmt;
411 stmt = NULL;
412 ctxt->cur_stmt = NULL;
413 }
415 if (ctxt->cur_stmt) {
416 cr_statement_destroy (ctxt->cur_stmt);
417 ctxt->cur_stmt = NULL;
418 }
419 a_page = NULL; /*keep compiler happy */
420 a_pseudo_page = NULL; /*keep compiler happy */
421 }
423 static void
424 start_media (CRDocHandler * a_this,
425 GList * a_media_list,
426 CRParsingLocation *a_location)
427 {
428 enum CRStatus status = CR_OK;
429 ParsingContext *ctxt = NULL;
430 ParsingContext **ctxtptr = NULL;
431 GList *media_list = NULL;
433 UNUSED(a_location);
435 g_return_if_fail (a_this);
436 ctxtptr = &ctxt;
437 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
438 g_return_if_fail (status == CR_OK && ctxt);
440 g_return_if_fail (ctxt
441 && ctxt->cur_stmt == NULL
442 && ctxt->cur_media_stmt == NULL
443 && ctxt->stylesheet);
444 if (a_media_list) {
445 /*duplicate the media_list */
446 media_list = cr_utils_dup_glist_of_cr_string
447 (a_media_list);
448 }
449 ctxt->cur_media_stmt =
450 cr_statement_new_at_media_rule
451 (ctxt->stylesheet, NULL, media_list);
453 }
455 static void
456 end_media (CRDocHandler * a_this, GList * a_media_list)
457 {
458 enum CRStatus status = CR_OK;
459 ParsingContext *ctxt = NULL;
460 ParsingContext **ctxtptr = NULL;
461 CRStatement *stmts = NULL;
463 g_return_if_fail (a_this);
464 ctxtptr = &ctxt;
465 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
466 g_return_if_fail (status == CR_OK && ctxt);
467 g_return_if_fail (ctxt
468 && ctxt->cur_media_stmt
469 && ctxt->cur_media_stmt->type == AT_MEDIA_RULE_STMT
470 && ctxt->stylesheet);
472 stmts = cr_statement_append (ctxt->stylesheet->statements,
473 ctxt->cur_media_stmt);
474 if (!stmts) {
475 cr_statement_destroy (ctxt->cur_media_stmt);
476 ctxt->cur_media_stmt = NULL;
477 }
479 ctxt->stylesheet->statements = stmts;
480 stmts = NULL;
482 ctxt->cur_stmt = NULL ;
483 ctxt->cur_media_stmt = NULL ;
484 a_media_list = NULL;
485 }
487 static void
488 import_style (CRDocHandler * a_this,
489 GList * a_media_list,
490 CRString * a_uri,
491 CRString * a_uri_default_ns,
492 CRParsingLocation *a_location)
493 {
494 enum CRStatus status = CR_OK;
495 CRString *uri = NULL;
496 CRStatement *stmt = NULL,
497 *stmt2 = NULL;
498 ParsingContext *ctxt = NULL;
499 ParsingContext **ctxtptr = NULL;
500 GList *media_list = NULL ;
502 UNUSED(a_location);
504 g_return_if_fail (a_this);
505 ctxtptr = &ctxt;
506 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
507 g_return_if_fail (status == CR_OK && ctxt);
508 g_return_if_fail (ctxt->stylesheet);
510 uri = cr_string_dup (a_uri) ;
511 if (a_media_list)
512 media_list = cr_utils_dup_glist_of_cr_string (a_media_list) ;
513 stmt = cr_statement_new_at_import_rule
514 (ctxt->stylesheet, uri, media_list, NULL);
515 if (!stmt)
516 goto error;
518 if (ctxt->cur_stmt) {
519 stmt2 = cr_statement_append (ctxt->cur_stmt, stmt);
520 if (!stmt2)
521 goto error;
522 ctxt->cur_stmt = stmt2;
523 stmt2 = NULL;
524 stmt = NULL;
525 } else {
526 stmt2 = cr_statement_append (ctxt->stylesheet->statements,
527 stmt);
528 if (!stmt2)
529 goto error;
530 ctxt->stylesheet->statements = stmt2;
531 stmt2 = NULL;
532 stmt = NULL;
533 }
535 return;
537 error:
538 if (uri) {
539 cr_string_destroy (uri);
540 }
542 if (stmt) {
543 cr_statement_destroy (stmt);
544 stmt = NULL;
545 }
546 a_uri_default_ns = NULL; /*keep compiler happy */
547 }
549 static void
550 start_selector (CRDocHandler * a_this, CRSelector * a_selector_list)
551 {
552 enum CRStatus status = CR_OK ;
553 ParsingContext *ctxt = NULL;
554 ParsingContext **ctxtptr = NULL;
556 g_return_if_fail (a_this);
557 ctxtptr = &ctxt;
558 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
559 g_return_if_fail (status == CR_OK && ctxt);
560 if (ctxt->cur_stmt) {
561 /*hmm, this should be NULL so free it */
562 cr_statement_destroy (ctxt->cur_stmt);
563 ctxt->cur_stmt = NULL;
564 }
566 ctxt->cur_stmt = cr_statement_new_ruleset
567 (ctxt->stylesheet, a_selector_list, NULL, NULL);
568 }
570 static void
571 end_selector (CRDocHandler * a_this, CRSelector * a_selector_list)
572 {
573 enum CRStatus status = CR_OK;
574 ParsingContext *ctxt = NULL;
575 ParsingContext **ctxtptr = NULL;
577 g_return_if_fail (a_this);
578 ctxtptr = &ctxt;
579 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
580 g_return_if_fail (status == CR_OK && ctxt);
581 g_return_if_fail (ctxt->cur_stmt && ctxt->stylesheet);
583 if (ctxt->cur_stmt) {
584 CRStatement *stmts = NULL;
586 if (ctxt->cur_media_stmt) {
587 CRAtMediaRule *media_rule = NULL;
589 media_rule = ctxt->cur_media_stmt->kind.media_rule;
591 stmts = cr_statement_append
592 (media_rule->rulesets, ctxt->cur_stmt);
594 if (!stmts) {
595 cr_utils_trace_info
596 ("Could not append a new statement");
597 cr_statement_destroy (media_rule->rulesets);
598 ctxt->cur_media_stmt->
599 kind.media_rule->rulesets = NULL;
600 return;
601 }
602 media_rule->rulesets = stmts;
603 ctxt->cur_stmt = NULL;
604 } else {
605 stmts = cr_statement_append
606 (ctxt->stylesheet->statements,
607 ctxt->cur_stmt);
608 if (!stmts) {
609 cr_utils_trace_info
610 ("Could not append a new statement");
611 cr_statement_destroy (ctxt->cur_stmt);
612 ctxt->cur_stmt = NULL;
613 return;
614 }
615 ctxt->stylesheet->statements = stmts;
616 ctxt->cur_stmt = NULL;
617 }
619 }
620 a_selector_list = NULL; /*keep compiler happy */
621 }
623 static void
624 property (CRDocHandler * a_this,
625 CRString * a_name,
626 CRTerm * a_expression,
627 gboolean a_important)
628 {
629 enum CRStatus status = CR_OK;
630 ParsingContext *ctxt = NULL;
631 ParsingContext **ctxtptr = NULL;
632 CRDeclaration *decl = NULL,
633 *decl2 = NULL;
634 CRString *str = NULL;
636 g_return_if_fail (a_this);
637 ctxtptr = &ctxt;
638 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
639 g_return_if_fail (status == CR_OK && ctxt);
641 /*
642 *make sure a current ruleset statement has been allocated
643 *already.
644 */
645 g_return_if_fail
646 (ctxt->cur_stmt
647 &&
648 (ctxt->cur_stmt->type == RULESET_STMT
649 || ctxt->cur_stmt->type == AT_FONT_FACE_RULE_STMT
650 || ctxt->cur_stmt->type == AT_PAGE_RULE_STMT));
652 if (a_name) {
653 str = cr_string_dup (a_name);
654 g_return_if_fail (str);
655 }
657 /*instanciates a new declaration */
658 decl = cr_declaration_new (ctxt->cur_stmt, str, a_expression);
659 g_return_if_fail (decl);
660 str = NULL;
661 decl->important = a_important;
662 /*
663 *add the new declaration to the current statement
664 *being build.
665 */
666 switch (ctxt->cur_stmt->type) {
667 case RULESET_STMT:
668 decl2 = cr_declaration_append
669 (ctxt->cur_stmt->kind.ruleset->decl_list, decl);
670 if (!decl2) {
671 cr_declaration_destroy (decl);
672 cr_utils_trace_info
673 ("Could not append decl to ruleset");
674 goto error;
675 }
676 ctxt->cur_stmt->kind.ruleset->decl_list = decl2;
677 decl = NULL;
678 decl2 = NULL;
679 break;
681 case AT_FONT_FACE_RULE_STMT:
682 decl2 = cr_declaration_append
683 (ctxt->cur_stmt->kind.font_face_rule->decl_list,
684 decl);
685 if (!decl2) {
686 cr_declaration_destroy (decl);
687 cr_utils_trace_info
688 ("Could not append decl to ruleset");
689 goto error;
690 }
691 ctxt->cur_stmt->kind.font_face_rule->decl_list = decl2;
692 decl = NULL;
693 decl2 = NULL;
694 break;
695 case AT_PAGE_RULE_STMT:
696 decl2 = cr_declaration_append
697 (ctxt->cur_stmt->kind.page_rule->decl_list, decl);
698 if (!decl2) {
699 cr_declaration_destroy (decl);
700 cr_utils_trace_info
701 ("Could not append decl to ruleset");
702 goto error;
703 }
704 ctxt->cur_stmt->kind.page_rule->decl_list = decl2;
705 decl = NULL;
706 decl2 = NULL;
707 break;
709 default:
710 goto error;
711 break;
712 }
714 return;
716 error:
717 if (str) {
718 g_free (str);
719 str = NULL;
720 }
722 if (decl) {
723 cr_declaration_destroy (decl);
724 decl = NULL;
725 }
726 }
728 static void
729 error (CRDocHandler * a_this)
730 {
731 enum CRStatus status = CR_OK;
732 ParsingContext *ctxt = NULL;
733 ParsingContext **ctxtptr = NULL;
735 g_return_if_fail (a_this);
736 ctxtptr = &ctxt;
737 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
738 g_return_if_fail (status == CR_OK && ctxt);
740 if (ctxt->cur_stmt) {
741 cr_statement_destroy (ctxt->cur_stmt);
742 ctxt->cur_stmt = NULL;
743 }
744 }
746 static void
747 unrecoverable_error (CRDocHandler * a_this)
748 {
749 enum CRStatus status = CR_OK;
750 ParsingContext *ctxt = NULL;
751 ParsingContext **ctxtptr = NULL;
753 ctxtptr = &ctxt;
754 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
755 g_return_if_fail (status == CR_OK);
757 if (ctxt) {
758 if (ctxt->stylesheet) {
759 status = cr_doc_handler_set_result
760 (a_this, ctxt->stylesheet);
761 g_return_if_fail (status == CR_OK);
762 }
763 g_free (ctxt);
764 cr_doc_handler_set_ctxt (a_this, NULL);
765 }
766 }
768 /********************************************
769 *Public methods
770 ********************************************/
772 /**
773 *Constructor of the CROMParser.
774 *@param a_input the input stream.
775 *@return the newly built instance of #CROMParser.
776 */
777 CROMParser *
778 cr_om_parser_new (CRInput * a_input)
779 {
780 enum CRStatus status = CR_OK;
782 CROMParser *result = (CROMParser *)g_try_malloc (sizeof (CROMParser));
784 if (!result) {
785 cr_utils_trace_info ("Out of memory");
786 return NULL;
787 }
789 memset (result, 0, sizeof (CROMParser));
790 PRIVATE (result) = (CROMParserPriv *)g_try_malloc (sizeof (CROMParserPriv));
792 if (!PRIVATE (result)) {
793 cr_utils_trace_info ("Out of memory");
794 goto error;
795 }
797 memset (PRIVATE (result), 0, sizeof (CROMParserPriv));
799 PRIVATE (result)->parser = cr_parser_new_from_input (a_input);
801 if (!PRIVATE (result)->parser) {
802 cr_utils_trace_info ("parsing instanciation failed");
803 goto error;
804 }
806 status = cr_om_parser_init_default_sac_handler (result);
808 if (status != CR_OK) {
809 goto error;
810 }
812 return result;
814 error:
816 if (result) {
817 cr_om_parser_destroy (result);
818 }
820 return NULL;
821 }
823 /**
824 *Parses the content of an in memory buffer.
825 *@param a_this the current instance of #CROMParser.
826 *@param a_buf the in memory buffer to parse.
827 *@param a_len the length of the in memory buffer in number of bytes.
828 *@param a_enc the encoding of the in memory buffer.
829 *@param a_result out parameter the resulting style sheet
830 *@return CR_OK upon successfull completion, an error code otherwise.
831 */
832 enum CRStatus
833 cr_om_parser_parse_buf (CROMParser * a_this,
834 const guchar * a_buf,
835 gulong a_len,
836 enum CREncoding a_enc, CRStyleSheet ** a_result)
837 {
839 enum CRStatus status = CR_OK;
841 g_return_val_if_fail (a_this && a_result, CR_BAD_PARAM_ERROR);
843 if (!PRIVATE (a_this)->parser) {
844 PRIVATE (a_this)->parser = cr_parser_new (NULL);
845 }
847 status = cr_parser_parse_buf (PRIVATE (a_this)->parser,
848 a_buf, a_len, a_enc);
850 if (status == CR_OK) {
851 CRStyleSheet *result = NULL;
852 CRStyleSheet **resultptr = NULL;
853 CRDocHandler *sac_handler = NULL;
855 cr_parser_get_sac_handler (PRIVATE (a_this)->parser,
856 &sac_handler);
857 g_return_val_if_fail (sac_handler, CR_ERROR);
858 resultptr = &result;
859 status = cr_doc_handler_get_result (sac_handler,
860 (gpointer *) resultptr);
861 g_return_val_if_fail (status == CR_OK, status);
863 if (result)
864 *a_result = result;
865 }
867 return status;
868 }
870 /**
871 *The simpler way to parse an in memory css2 buffer.
872 *@param a_buf the css2 in memory buffer.
873 *@param a_len the length of the in memory buffer.
874 *@param a_enc the encoding of the in memory buffer.
875 *@param a_result out parameter. The resulting css2 style sheet.
876 *@return CR_OK upon successfull completion, an error code otherwise.
877 */
878 enum CRStatus
879 cr_om_parser_simply_parse_buf (const guchar * a_buf,
880 gulong a_len,
881 enum CREncoding a_enc,
882 CRStyleSheet ** a_result)
883 {
884 CROMParser *parser = NULL;
885 enum CRStatus status = CR_OK;
887 parser = cr_om_parser_new (NULL);
888 if (!parser) {
889 cr_utils_trace_info ("Could not create om parser");
890 cr_utils_trace_info ("System possibly out of memory");
891 return CR_ERROR;
892 }
894 status = cr_om_parser_parse_buf (parser, a_buf, a_len,
895 a_enc, a_result);
897 if (parser) {
898 cr_om_parser_destroy (parser);
899 parser = NULL;
900 }
902 return status;
903 }
905 /**
906 *Parses a css2 stylesheet contained
907 *in a file.
908 *@param a_this the current instance of the cssom parser.
909 *@param a_file_uri the uri of the file.
910 *(only local file paths are suppported so far)
911 *@param a_enc the encoding of the file.
912 *@param a_result out parameter. A pointer
913 *the build css object model.
914 *@param CR_OK upon successfull completion, an error code
915 *otherwise.
916 */
917 enum CRStatus
918 cr_om_parser_parse_file (CROMParser * a_this,
919 const guchar * a_file_uri,
920 enum CREncoding a_enc, CRStyleSheet ** a_result)
921 {
922 enum CRStatus status = CR_OK;
924 g_return_val_if_fail (a_this && a_file_uri && a_result,
925 CR_BAD_PARAM_ERROR);
927 if (!PRIVATE (a_this)->parser) {
928 PRIVATE (a_this)->parser = cr_parser_new_from_file
929 (a_file_uri, a_enc);
930 }
932 status = cr_parser_parse_file (PRIVATE (a_this)->parser,
933 a_file_uri, a_enc);
935 if (status == CR_OK) {
936 CRStyleSheet *result = NULL;
937 CRStyleSheet **resultptr = NULL;
938 CRDocHandler *sac_handler = NULL;
940 cr_parser_get_sac_handler (PRIVATE (a_this)->parser,
941 &sac_handler);
942 g_return_val_if_fail (sac_handler, CR_ERROR);
943 resultptr = &result;
944 status = cr_doc_handler_get_result
945 (sac_handler, (gpointer *) resultptr);
946 g_return_val_if_fail (status == CR_OK, status);
947 if (result)
948 *a_result = result;
949 }
951 return status;
952 }
954 /**
955 *The simpler method to parse a css2 file.
956 *@param a_file_path the css2 local file path.
957 *@param a_enc the file encoding.
958 *@param a_result out parameter. The returned css stylesheet.
959 *Must be freed by the caller using cr_stylesheet_destroy.
960 *@return CR_OK upon successfull completion, an error code otherwise.
961 *Note that this method uses cr_om_parser_parse_file() so both methods
962 *have the same return values.
963 */
964 enum CRStatus
965 cr_om_parser_simply_parse_file (const guchar * a_file_path,
966 enum CREncoding a_enc,
967 CRStyleSheet ** a_result)
968 {
969 CROMParser *parser = NULL;
970 enum CRStatus status = CR_OK;
972 parser = cr_om_parser_new (NULL);
973 if (!parser) {
974 cr_utils_trace_info ("Could not allocate om parser");
975 cr_utils_trace_info ("System may be out of memory");
976 return CR_ERROR;
977 }
979 status = cr_om_parser_parse_file (parser, a_file_path,
980 a_enc, a_result);
981 if (parser) {
982 cr_om_parser_destroy (parser);
983 parser = NULL;
984 }
986 return status;
987 }
989 /**
990 *Parses three sheets located by their paths and build a cascade
991 *@param a_this the current instance of #CROMParser
992 *@param a_author_path the path to the author stylesheet
993 *@param a_user_path the path to the user stylesheet
994 *@param a_ua_path the path to the User Agent stylesheet
995 *@param a_result out parameter. The resulting cascade if the parsing
996 *was okay
997 *@return CR_OK upon successful completion, an error code otherwise
998 */
999 enum CRStatus
1000 cr_om_parser_parse_paths_to_cascade (CROMParser * a_this,
1001 const guchar * a_author_path,
1002 const guchar * a_user_path,
1003 const guchar * a_ua_path,
1004 enum CREncoding a_encoding,
1005 CRCascade ** a_result)
1006 {
1007 enum CRStatus status = CR_OK;
1009 /*0->author sheet, 1->user sheet, 2->UA sheet */
1010 CRStyleSheet *sheets[3];
1011 guchar *paths[3];
1012 CRCascade *result = NULL;
1013 gint i = 0;
1015 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
1017 memset (sheets, 0, sizeof (sheets));
1018 paths[0] = (guchar *) a_author_path;
1019 paths[1] = (guchar *) a_user_path;
1020 paths[2] = (guchar *) a_ua_path;
1022 for (i = 0; i < 3; i++) {
1023 status = cr_om_parser_parse_file (a_this, paths[i],
1024 a_encoding, &sheets[i]);
1025 if (status != CR_OK) {
1026 if (sheets[i]) {
1027 cr_stylesheet_unref (sheets[i]);
1028 sheets[i] = NULL;
1029 }
1030 continue;
1031 }
1032 }
1033 result = cr_cascade_new (sheets[0], sheets[1], sheets[2]);
1034 if (!result) {
1035 for (i = 0; i < 3; i++) {
1036 cr_stylesheet_unref (sheets[i]);
1037 sheets[i] = 0;
1038 }
1039 return CR_ERROR;
1040 }
1041 *a_result = result;
1042 return CR_OK;
1043 }
1045 /**
1046 *Parses three sheets located by their paths and build a cascade
1047 *@param a_author_path the path to the author stylesheet
1048 *@param a_user_path the path to the user stylesheet
1049 *@param a_ua_path the path to the User Agent stylesheet
1050 *@param a_result out parameter. The resulting cascade if the parsing
1051 *was okay
1052 *@return CR_OK upon successful completion, an error code otherwise
1053 */
1054 enum CRStatus
1055 cr_om_parser_simply_parse_paths_to_cascade (const guchar * a_author_path,
1056 const guchar * a_user_path,
1057 const guchar * a_ua_path,
1058 enum CREncoding a_encoding,
1059 CRCascade ** a_result)
1060 {
1061 enum CRStatus status = CR_OK;
1062 CROMParser *parser = NULL;
1064 parser = cr_om_parser_new (NULL);
1065 if (!parser) {
1066 cr_utils_trace_info ("could not allocated om parser");
1067 cr_utils_trace_info ("System may be out of memory");
1068 return CR_ERROR;
1069 }
1070 status = cr_om_parser_parse_paths_to_cascade (parser,
1071 a_author_path,
1072 a_user_path,
1073 a_ua_path,
1074 a_encoding, a_result);
1075 if (parser) {
1076 cr_om_parser_destroy (parser);
1077 parser = NULL;
1078 }
1079 return status;
1080 }
1082 /**
1083 *Destructor of the #CROMParser.
1084 *@param a_this the current instance of #CROMParser.
1085 */
1086 void
1087 cr_om_parser_destroy (CROMParser * a_this)
1088 {
1089 g_return_if_fail (a_this && PRIVATE (a_this));
1091 if (PRIVATE (a_this)->parser) {
1092 cr_parser_destroy (PRIVATE (a_this)->parser);
1093 PRIVATE (a_this)->parser = NULL;
1094 }
1096 if (PRIVATE (a_this)) {
1097 g_free (PRIVATE (a_this));
1098 PRIVATE (a_this) = NULL;
1099 }
1101 if (a_this) {
1102 g_free (a_this);
1103 a_this = NULL;
1104 }
1105 }