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 = NULL;
117 result = g_try_malloc (sizeof (ParsingContext));
118 if (!result) {
119 cr_utils_trace_info ("Out of Memory");
120 return NULL;
121 }
122 memset (result, 0, sizeof (ParsingContext));
123 return result;
124 }
126 static void
127 destroy_context (ParsingContext * a_ctxt)
128 {
129 g_return_if_fail (a_ctxt);
131 if (a_ctxt->stylesheet) {
132 cr_stylesheet_destroy (a_ctxt->stylesheet);
133 a_ctxt->stylesheet = NULL;
134 }
135 if (a_ctxt->cur_stmt) {
136 cr_statement_destroy (a_ctxt->cur_stmt);
137 a_ctxt->cur_stmt = NULL;
138 }
139 g_free (a_ctxt);
140 }
142 static enum CRStatus
143 cr_om_parser_init_default_sac_handler (CROMParser * a_this)
144 {
145 CRDocHandler *sac_handler = NULL;
146 gboolean free_hdlr_if_error = FALSE;
147 enum CRStatus status = CR_OK;
149 g_return_val_if_fail (a_this && PRIVATE (a_this)
150 && PRIVATE (a_this)->parser,
151 CR_BAD_PARAM_ERROR);
153 status = cr_parser_get_sac_handler (PRIVATE (a_this)->parser,
154 &sac_handler);
155 g_return_val_if_fail (status == CR_OK, status);
157 if (!sac_handler) {
158 sac_handler = cr_doc_handler_new ();
159 free_hdlr_if_error = TRUE;
160 }
162 /*
163 *initialyze here the sac handler.
164 */
165 sac_handler->start_document = start_document;
166 sac_handler->end_document = end_document;
167 sac_handler->start_selector = start_selector;
168 sac_handler->end_selector = end_selector;
169 sac_handler->property = property;
170 sac_handler->start_font_face = start_font_face;
171 sac_handler->end_font_face = end_font_face;
172 sac_handler->error = error;
173 sac_handler->unrecoverable_error = unrecoverable_error;
174 sac_handler->charset = charset;
175 sac_handler->start_page = start_page;
176 sac_handler->end_page = end_page;
177 sac_handler->start_media = start_media;
178 sac_handler->end_media = end_media;
179 sac_handler->import_style = import_style;
181 status = cr_parser_set_sac_handler (PRIVATE (a_this)->parser,
182 sac_handler);
183 if (status == CR_OK) {
184 return CR_OK;
185 }
187 if (sac_handler && free_hdlr_if_error == TRUE) {
188 cr_doc_handler_destroy (sac_handler);
189 sac_handler = NULL;
190 }
192 return status;
194 }
196 static void
197 start_document (CRDocHandler * a_this)
198 {
199 ParsingContext *ctxt = NULL;
200 CRStyleSheet *stylesheet = NULL;
202 g_return_if_fail (a_this);
204 ctxt = new_parsing_context ();
205 g_return_if_fail (ctxt);
207 stylesheet = cr_stylesheet_new (NULL);
208 ctxt->stylesheet = stylesheet;
209 cr_doc_handler_set_ctxt (a_this, ctxt);
210 }
212 static void
213 start_font_face (CRDocHandler * a_this,
214 CRParsingLocation *a_location)
215 {
216 enum CRStatus status = CR_OK;
217 ParsingContext *ctxt = NULL;
218 ParsingContext **ctxtptr = NULL;
220 UNUSED(a_location);
222 g_return_if_fail (a_this);
223 ctxtptr = &ctxt;
224 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
225 g_return_if_fail (status == CR_OK && ctxt);
226 g_return_if_fail (ctxt->cur_stmt == NULL);
228 ctxt->cur_stmt =
229 cr_statement_new_at_font_face_rule (ctxt->stylesheet, NULL);
231 g_return_if_fail (ctxt->cur_stmt);
232 }
234 static void
235 end_font_face (CRDocHandler * a_this)
236 {
237 enum CRStatus status = CR_OK;
238 ParsingContext *ctxt = NULL;
239 ParsingContext **ctxtptr = NULL;
240 CRStatement *stmts = NULL;
242 g_return_if_fail (a_this);
244 g_return_if_fail (a_this);
245 ctxtptr = &ctxt;
246 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
247 g_return_if_fail (status == CR_OK && ctxt);
248 g_return_if_fail
249 (ctxt->cur_stmt
250 && ctxt->cur_stmt->type == AT_FONT_FACE_RULE_STMT
251 && ctxt->stylesheet);
253 stmts = cr_statement_append (ctxt->stylesheet->statements,
254 ctxt->cur_stmt);
255 if (!stmts)
256 goto error;
258 ctxt->stylesheet->statements = stmts;
259 stmts = NULL;
260 ctxt->cur_stmt = NULL;
262 return;
264 error:
266 if (ctxt->cur_stmt) {
267 cr_statement_destroy (ctxt->cur_stmt);
268 ctxt->cur_stmt = NULL;
269 }
271 if (!stmts) {
272 cr_statement_destroy (stmts);
273 stmts = NULL;
274 }
275 }
277 static void
278 end_document (CRDocHandler * a_this)
279 {
280 enum CRStatus status = CR_OK;
281 ParsingContext *ctxt = NULL;
282 ParsingContext **ctxtptr = NULL;
284 g_return_if_fail (a_this);
285 ctxtptr = &ctxt;
286 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
287 g_return_if_fail (status == CR_OK && ctxt);
289 if (!ctxt->stylesheet || ctxt->cur_stmt)
290 goto error;
292 status = cr_doc_handler_set_result (a_this, ctxt->stylesheet);
293 g_return_if_fail (status == CR_OK);
295 ctxt->stylesheet = NULL;
296 destroy_context (ctxt);
297 cr_doc_handler_set_ctxt (a_this, NULL);
299 return;
301 error:
302 if (ctxt) {
303 destroy_context (ctxt);
304 }
305 }
307 static void
308 charset (CRDocHandler * a_this, CRString * a_charset,
309 CRParsingLocation *a_location)
310 {
311 enum CRStatus status = CR_OK;
312 CRStatement *stmt = NULL,
313 *stmt2 = NULL;
314 CRString *charset = NULL;
316 ParsingContext *ctxt = NULL;
317 ParsingContext **ctxtptr = NULL;
319 UNUSED(a_location);
321 g_return_if_fail (a_this);
322 ctxtptr = &ctxt;
323 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
324 g_return_if_fail (status == CR_OK && ctxt);
325 g_return_if_fail (ctxt->stylesheet);
327 charset = cr_string_dup (a_charset) ;
328 stmt = cr_statement_new_at_charset_rule (ctxt->stylesheet, charset);
329 g_return_if_fail (stmt);
330 stmt2 = cr_statement_append (ctxt->stylesheet->statements, stmt);
331 if (!stmt2) {
332 if (stmt) {
333 cr_statement_destroy (stmt);
334 stmt = NULL;
335 }
336 if (charset) {
337 cr_string_destroy (charset);
338 }
339 return;
340 }
341 ctxt->stylesheet->statements = stmt2;
342 stmt2 = NULL;
343 }
345 static void
346 start_page (CRDocHandler * a_this,
347 CRString * a_page,
348 CRString * a_pseudo,
349 CRParsingLocation *a_location)
350 {
351 enum CRStatus status = CR_OK;
352 ParsingContext *ctxt = NULL;
353 ParsingContext **ctxtptr = NULL;
355 UNUSED(a_location);
357 g_return_if_fail (a_this);
358 ctxtptr = &ctxt;
359 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
360 g_return_if_fail (status == CR_OK && ctxt);
361 g_return_if_fail (ctxt->cur_stmt == NULL);
363 ctxt->cur_stmt = cr_statement_new_at_page_rule
364 (ctxt->stylesheet, NULL, NULL, NULL);
365 if (a_page) {
366 ctxt->cur_stmt->kind.page_rule->name =
367 cr_string_dup (a_page) ;
369 if (!ctxt->cur_stmt->kind.page_rule->name) {
370 goto error;
371 }
372 }
373 if (a_pseudo) {
374 ctxt->cur_stmt->kind.page_rule->pseudo =
375 cr_string_dup (a_pseudo) ;
376 if (!ctxt->cur_stmt->kind.page_rule->pseudo) {
377 goto error;
378 }
379 }
380 return;
382 error:
383 if (ctxt->cur_stmt) {
384 cr_statement_destroy (ctxt->cur_stmt);
385 ctxt->cur_stmt = NULL;
386 }
387 }
389 static void
390 end_page (CRDocHandler * a_this,
391 CRString * a_page,
392 CRString * a_pseudo_page)
393 {
394 enum CRStatus status = CR_OK;
395 ParsingContext *ctxt = NULL;
396 ParsingContext **ctxtptr = NULL;
397 CRStatement *stmt = NULL;
399 g_return_if_fail (a_this);
400 ctxtptr = &ctxt;
401 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
402 g_return_if_fail (status == CR_OK && ctxt);
403 g_return_if_fail (ctxt->cur_stmt
404 && ctxt->cur_stmt->type == AT_PAGE_RULE_STMT
405 && ctxt->stylesheet);
407 stmt = cr_statement_append (ctxt->stylesheet->statements,
408 ctxt->cur_stmt);
410 if (stmt) {
411 ctxt->stylesheet->statements = stmt;
412 stmt = NULL;
413 ctxt->cur_stmt = NULL;
414 }
416 if (ctxt->cur_stmt) {
417 cr_statement_destroy (ctxt->cur_stmt);
418 ctxt->cur_stmt = NULL;
419 }
420 a_page = NULL; /*keep compiler happy */
421 a_pseudo_page = NULL; /*keep compiler happy */
422 }
424 static void
425 start_media (CRDocHandler * a_this,
426 GList * a_media_list,
427 CRParsingLocation *a_location)
428 {
429 enum CRStatus status = CR_OK;
430 ParsingContext *ctxt = NULL;
431 ParsingContext **ctxtptr = NULL;
432 GList *media_list = NULL;
434 UNUSED(a_location);
436 g_return_if_fail (a_this);
437 ctxtptr = &ctxt;
438 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
439 g_return_if_fail (status == CR_OK && ctxt);
441 g_return_if_fail (ctxt
442 && ctxt->cur_stmt == NULL
443 && ctxt->cur_media_stmt == NULL
444 && ctxt->stylesheet);
445 if (a_media_list) {
446 /*duplicate the media_list */
447 media_list = cr_utils_dup_glist_of_cr_string
448 (a_media_list);
449 }
450 ctxt->cur_media_stmt =
451 cr_statement_new_at_media_rule
452 (ctxt->stylesheet, NULL, media_list);
454 }
456 static void
457 end_media (CRDocHandler * a_this, GList * a_media_list)
458 {
459 enum CRStatus status = CR_OK;
460 ParsingContext *ctxt = NULL;
461 ParsingContext **ctxtptr = NULL;
462 CRStatement *stmts = NULL;
464 g_return_if_fail (a_this);
465 ctxtptr = &ctxt;
466 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
467 g_return_if_fail (status == CR_OK && ctxt);
468 g_return_if_fail (ctxt
469 && ctxt->cur_media_stmt
470 && ctxt->cur_media_stmt->type == AT_MEDIA_RULE_STMT
471 && ctxt->stylesheet);
473 stmts = cr_statement_append (ctxt->stylesheet->statements,
474 ctxt->cur_media_stmt);
475 if (!stmts) {
476 cr_statement_destroy (ctxt->cur_media_stmt);
477 ctxt->cur_media_stmt = NULL;
478 }
480 ctxt->stylesheet->statements = stmts;
481 stmts = NULL;
483 ctxt->cur_stmt = NULL ;
484 ctxt->cur_media_stmt = NULL ;
485 a_media_list = NULL;
486 }
488 static void
489 import_style (CRDocHandler * a_this,
490 GList * a_media_list,
491 CRString * a_uri,
492 CRString * a_uri_default_ns,
493 CRParsingLocation *a_location)
494 {
495 enum CRStatus status = CR_OK;
496 CRString *uri = NULL;
497 CRStatement *stmt = NULL,
498 *stmt2 = NULL;
499 ParsingContext *ctxt = NULL;
500 ParsingContext **ctxtptr = NULL;
501 GList *media_list = NULL ;
503 UNUSED(a_location);
505 g_return_if_fail (a_this);
506 ctxtptr = &ctxt;
507 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
508 g_return_if_fail (status == CR_OK && ctxt);
509 g_return_if_fail (ctxt->stylesheet);
511 uri = cr_string_dup (a_uri) ;
512 if (a_media_list)
513 media_list = cr_utils_dup_glist_of_cr_string (a_media_list) ;
514 stmt = cr_statement_new_at_import_rule
515 (ctxt->stylesheet, uri, media_list, NULL);
516 if (!stmt)
517 goto error;
519 if (ctxt->cur_stmt) {
520 stmt2 = cr_statement_append (ctxt->cur_stmt, stmt);
521 if (!stmt2)
522 goto error;
523 ctxt->cur_stmt = stmt2;
524 stmt2 = NULL;
525 stmt = NULL;
526 } else {
527 stmt2 = cr_statement_append (ctxt->stylesheet->statements,
528 stmt);
529 if (!stmt2)
530 goto error;
531 ctxt->stylesheet->statements = stmt2;
532 stmt2 = NULL;
533 stmt = NULL;
534 }
536 return;
538 error:
539 if (uri) {
540 cr_string_destroy (uri);
541 }
543 if (stmt) {
544 cr_statement_destroy (stmt);
545 stmt = NULL;
546 }
547 a_uri_default_ns = NULL; /*keep compiler happy */
548 }
550 static void
551 start_selector (CRDocHandler * a_this, CRSelector * a_selector_list)
552 {
553 enum CRStatus status = CR_OK ;
554 ParsingContext *ctxt = NULL;
555 ParsingContext **ctxtptr = NULL;
557 g_return_if_fail (a_this);
558 ctxtptr = &ctxt;
559 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
560 g_return_if_fail (status == CR_OK && ctxt);
561 if (ctxt->cur_stmt) {
562 /*hmm, this should be NULL so free it */
563 cr_statement_destroy (ctxt->cur_stmt);
564 ctxt->cur_stmt = NULL;
565 }
567 ctxt->cur_stmt = cr_statement_new_ruleset
568 (ctxt->stylesheet, a_selector_list, NULL, NULL);
569 }
571 static void
572 end_selector (CRDocHandler * a_this, CRSelector * a_selector_list)
573 {
574 enum CRStatus status = CR_OK;
575 ParsingContext *ctxt = NULL;
576 ParsingContext **ctxtptr = NULL;
578 g_return_if_fail (a_this);
579 ctxtptr = &ctxt;
580 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
581 g_return_if_fail (status == CR_OK && ctxt);
582 g_return_if_fail (ctxt->cur_stmt && ctxt->stylesheet);
584 if (ctxt->cur_stmt) {
585 CRStatement *stmts = NULL;
587 if (ctxt->cur_media_stmt) {
588 CRAtMediaRule *media_rule = NULL;
590 media_rule = ctxt->cur_media_stmt->kind.media_rule;
592 stmts = cr_statement_append
593 (media_rule->rulesets, ctxt->cur_stmt);
595 if (!stmts) {
596 cr_utils_trace_info
597 ("Could not append a new statement");
598 cr_statement_destroy (media_rule->rulesets);
599 ctxt->cur_media_stmt->
600 kind.media_rule->rulesets = NULL;
601 return;
602 }
603 media_rule->rulesets = stmts;
604 ctxt->cur_stmt = NULL;
605 } else {
606 stmts = cr_statement_append
607 (ctxt->stylesheet->statements,
608 ctxt->cur_stmt);
609 if (!stmts) {
610 cr_utils_trace_info
611 ("Could not append a new statement");
612 cr_statement_destroy (ctxt->cur_stmt);
613 ctxt->cur_stmt = NULL;
614 return;
615 }
616 ctxt->stylesheet->statements = stmts;
617 ctxt->cur_stmt = NULL;
618 }
620 }
621 a_selector_list = NULL; /*keep compiler happy */
622 }
624 static void
625 property (CRDocHandler * a_this,
626 CRString * a_name,
627 CRTerm * a_expression,
628 gboolean a_important)
629 {
630 enum CRStatus status = CR_OK;
631 ParsingContext *ctxt = NULL;
632 ParsingContext **ctxtptr = NULL;
633 CRDeclaration *decl = NULL,
634 *decl2 = NULL;
635 CRString *str = NULL;
637 g_return_if_fail (a_this);
638 ctxtptr = &ctxt;
639 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
640 g_return_if_fail (status == CR_OK && ctxt);
642 /*
643 *make sure a current ruleset statement has been allocated
644 *already.
645 */
646 g_return_if_fail
647 (ctxt->cur_stmt
648 &&
649 (ctxt->cur_stmt->type == RULESET_STMT
650 || ctxt->cur_stmt->type == AT_FONT_FACE_RULE_STMT
651 || ctxt->cur_stmt->type == AT_PAGE_RULE_STMT));
653 if (a_name) {
654 str = cr_string_dup (a_name);
655 g_return_if_fail (str);
656 }
658 /*instanciates a new declaration */
659 decl = cr_declaration_new (ctxt->cur_stmt, str, a_expression);
660 g_return_if_fail (decl);
661 str = NULL;
662 decl->important = a_important;
663 /*
664 *add the new declaration to the current statement
665 *being build.
666 */
667 switch (ctxt->cur_stmt->type) {
668 case RULESET_STMT:
669 decl2 = cr_declaration_append
670 (ctxt->cur_stmt->kind.ruleset->decl_list, decl);
671 if (!decl2) {
672 cr_declaration_destroy (decl);
673 cr_utils_trace_info
674 ("Could not append decl to ruleset");
675 goto error;
676 }
677 ctxt->cur_stmt->kind.ruleset->decl_list = decl2;
678 decl = NULL;
679 decl2 = NULL;
680 break;
682 case AT_FONT_FACE_RULE_STMT:
683 decl2 = cr_declaration_append
684 (ctxt->cur_stmt->kind.font_face_rule->decl_list,
685 decl);
686 if (!decl2) {
687 cr_declaration_destroy (decl);
688 cr_utils_trace_info
689 ("Could not append decl to ruleset");
690 goto error;
691 }
692 ctxt->cur_stmt->kind.font_face_rule->decl_list = decl2;
693 decl = NULL;
694 decl2 = NULL;
695 break;
696 case AT_PAGE_RULE_STMT:
697 decl2 = cr_declaration_append
698 (ctxt->cur_stmt->kind.page_rule->decl_list, decl);
699 if (!decl2) {
700 cr_declaration_destroy (decl);
701 cr_utils_trace_info
702 ("Could not append decl to ruleset");
703 goto error;
704 }
705 ctxt->cur_stmt->kind.page_rule->decl_list = decl2;
706 decl = NULL;
707 decl2 = NULL;
708 break;
710 default:
711 goto error;
712 break;
713 }
715 return;
717 error:
718 if (str) {
719 g_free (str);
720 str = NULL;
721 }
723 if (decl) {
724 cr_declaration_destroy (decl);
725 decl = NULL;
726 }
727 }
729 static void
730 error (CRDocHandler * a_this)
731 {
732 enum CRStatus status = CR_OK;
733 ParsingContext *ctxt = NULL;
734 ParsingContext **ctxtptr = NULL;
736 g_return_if_fail (a_this);
737 ctxtptr = &ctxt;
738 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
739 g_return_if_fail (status == CR_OK && ctxt);
741 if (ctxt->cur_stmt) {
742 cr_statement_destroy (ctxt->cur_stmt);
743 ctxt->cur_stmt = NULL;
744 }
745 }
747 static void
748 unrecoverable_error (CRDocHandler * a_this)
749 {
750 enum CRStatus status = CR_OK;
751 ParsingContext *ctxt = NULL;
752 ParsingContext **ctxtptr = NULL;
754 ctxtptr = &ctxt;
755 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
756 g_return_if_fail (status == CR_OK);
758 if (ctxt) {
759 if (ctxt->stylesheet) {
760 status = cr_doc_handler_set_result
761 (a_this, ctxt->stylesheet);
762 g_return_if_fail (status == CR_OK);
763 }
764 g_free (ctxt);
765 cr_doc_handler_set_ctxt (a_this, NULL);
766 }
767 }
769 /********************************************
770 *Public methods
771 ********************************************/
773 /**
774 *Constructor of the CROMParser.
775 *@param a_input the input stream.
776 *@return the newly built instance of #CROMParser.
777 */
778 CROMParser *
779 cr_om_parser_new (CRInput * a_input)
780 {
781 CROMParser *result = NULL;
782 enum CRStatus status = CR_OK;
784 result = g_try_malloc (sizeof (CROMParser));
786 if (!result) {
787 cr_utils_trace_info ("Out of memory");
788 return NULL;
789 }
791 memset (result, 0, sizeof (CROMParser));
792 PRIVATE (result) = g_try_malloc (sizeof (CROMParserPriv));
794 if (!PRIVATE (result)) {
795 cr_utils_trace_info ("Out of memory");
796 goto error;
797 }
799 memset (PRIVATE (result), 0, sizeof (CROMParserPriv));
801 PRIVATE (result)->parser = cr_parser_new_from_input (a_input);
803 if (!PRIVATE (result)->parser) {
804 cr_utils_trace_info ("parsing instanciation failed");
805 goto error;
806 }
808 status = cr_om_parser_init_default_sac_handler (result);
810 if (status != CR_OK) {
811 goto error;
812 }
814 return result;
816 error:
818 if (result) {
819 cr_om_parser_destroy (result);
820 }
822 return NULL;
823 }
825 /**
826 *Parses the content of an in memory buffer.
827 *@param a_this the current instance of #CROMParser.
828 *@param a_buf the in memory buffer to parse.
829 *@param a_len the length of the in memory buffer in number of bytes.
830 *@param a_enc the encoding of the in memory buffer.
831 *@param a_result out parameter the resulting style sheet
832 *@return CR_OK upon successfull completion, an error code otherwise.
833 */
834 enum CRStatus
835 cr_om_parser_parse_buf (CROMParser * a_this,
836 const guchar * a_buf,
837 gulong a_len,
838 enum CREncoding a_enc, CRStyleSheet ** a_result)
839 {
841 enum CRStatus status = CR_OK;
843 g_return_val_if_fail (a_this && a_result, CR_BAD_PARAM_ERROR);
845 if (!PRIVATE (a_this)->parser) {
846 PRIVATE (a_this)->parser = cr_parser_new (NULL);
847 }
849 status = cr_parser_parse_buf (PRIVATE (a_this)->parser,
850 a_buf, a_len, a_enc);
852 if (status == CR_OK) {
853 CRStyleSheet *result = NULL;
854 CRStyleSheet **resultptr = NULL;
855 CRDocHandler *sac_handler = NULL;
857 cr_parser_get_sac_handler (PRIVATE (a_this)->parser,
858 &sac_handler);
859 g_return_val_if_fail (sac_handler, CR_ERROR);
860 resultptr = &result;
861 status = cr_doc_handler_get_result (sac_handler,
862 (gpointer *) resultptr);
863 g_return_val_if_fail (status == CR_OK, status);
865 if (result)
866 *a_result = result;
867 }
869 return status;
870 }
872 /**
873 *The simpler way to parse an in memory css2 buffer.
874 *@param a_buf the css2 in memory buffer.
875 *@param a_len the length of the in memory buffer.
876 *@param a_enc the encoding of the in memory buffer.
877 *@param a_result out parameter. The resulting css2 style sheet.
878 *@return CR_OK upon successfull completion, an error code otherwise.
879 */
880 enum CRStatus
881 cr_om_parser_simply_parse_buf (const guchar * a_buf,
882 gulong a_len,
883 enum CREncoding a_enc,
884 CRStyleSheet ** a_result)
885 {
886 CROMParser *parser = NULL;
887 enum CRStatus status = CR_OK;
889 parser = cr_om_parser_new (NULL);
890 if (!parser) {
891 cr_utils_trace_info ("Could not create om parser");
892 cr_utils_trace_info ("System possibly out of memory");
893 return CR_ERROR;
894 }
896 status = cr_om_parser_parse_buf (parser, a_buf, a_len,
897 a_enc, a_result);
899 if (parser) {
900 cr_om_parser_destroy (parser);
901 parser = NULL;
902 }
904 return status;
905 }
907 /**
908 *Parses a css2 stylesheet contained
909 *in a file.
910 *@param a_this the current instance of the cssom parser.
911 *@param a_file_uri the uri of the file.
912 *(only local file paths are suppported so far)
913 *@param a_enc the encoding of the file.
914 *@param a_result out parameter. A pointer
915 *the build css object model.
916 *@param CR_OK upon successfull completion, an error code
917 *otherwise.
918 */
919 enum CRStatus
920 cr_om_parser_parse_file (CROMParser * a_this,
921 const guchar * a_file_uri,
922 enum CREncoding a_enc, CRStyleSheet ** a_result)
923 {
924 enum CRStatus status = CR_OK;
926 g_return_val_if_fail (a_this && a_file_uri && a_result,
927 CR_BAD_PARAM_ERROR);
929 if (!PRIVATE (a_this)->parser) {
930 PRIVATE (a_this)->parser = cr_parser_new_from_file
931 (a_file_uri, a_enc);
932 }
934 status = cr_parser_parse_file (PRIVATE (a_this)->parser,
935 a_file_uri, a_enc);
937 if (status == CR_OK) {
938 CRStyleSheet *result = NULL;
939 CRStyleSheet **resultptr = NULL;
940 CRDocHandler *sac_handler = NULL;
942 cr_parser_get_sac_handler (PRIVATE (a_this)->parser,
943 &sac_handler);
944 g_return_val_if_fail (sac_handler, CR_ERROR);
945 resultptr = &result;
946 status = cr_doc_handler_get_result
947 (sac_handler, (gpointer *) resultptr);
948 g_return_val_if_fail (status == CR_OK, status);
949 if (result)
950 *a_result = result;
951 }
953 return status;
954 }
956 /**
957 *The simpler method to parse a css2 file.
958 *@param a_file_path the css2 local file path.
959 *@param a_enc the file encoding.
960 *@param a_result out parameter. The returned css stylesheet.
961 *Must be freed by the caller using cr_stylesheet_destroy.
962 *@return CR_OK upon successfull completion, an error code otherwise.
963 *Note that this method uses cr_om_parser_parse_file() so both methods
964 *have the same return values.
965 */
966 enum CRStatus
967 cr_om_parser_simply_parse_file (const guchar * a_file_path,
968 enum CREncoding a_enc,
969 CRStyleSheet ** a_result)
970 {
971 CROMParser *parser = NULL;
972 enum CRStatus status = CR_OK;
974 parser = cr_om_parser_new (NULL);
975 if (!parser) {
976 cr_utils_trace_info ("Could not allocate om parser");
977 cr_utils_trace_info ("System may be out of memory");
978 return CR_ERROR;
979 }
981 status = cr_om_parser_parse_file (parser, a_file_path,
982 a_enc, a_result);
983 if (parser) {
984 cr_om_parser_destroy (parser);
985 parser = NULL;
986 }
988 return status;
989 }
991 /**
992 *Parses three sheets located by their paths and build a cascade
993 *@param a_this the current instance of #CROMParser
994 *@param a_author_path the path to the author stylesheet
995 *@param a_user_path the path to the user stylesheet
996 *@param a_ua_path the path to the User Agent stylesheet
997 *@param a_result out parameter. The resulting cascade if the parsing
998 *was okay
999 *@return CR_OK upon successful completion, an error code otherwise
1000 */
1001 enum CRStatus
1002 cr_om_parser_parse_paths_to_cascade (CROMParser * a_this,
1003 const guchar * a_author_path,
1004 const guchar * a_user_path,
1005 const guchar * a_ua_path,
1006 enum CREncoding a_encoding,
1007 CRCascade ** a_result)
1008 {
1009 enum CRStatus status = CR_OK;
1011 /*0->author sheet, 1->user sheet, 2->UA sheet */
1012 CRStyleSheet *sheets[3];
1013 guchar *paths[3];
1014 CRCascade *result = NULL;
1015 gint i = 0;
1017 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
1019 memset (sheets, 0, sizeof (sheets));
1020 paths[0] = (guchar *) a_author_path;
1021 paths[1] = (guchar *) a_user_path;
1022 paths[2] = (guchar *) a_ua_path;
1024 for (i = 0; i < 3; i++) {
1025 status = cr_om_parser_parse_file (a_this, paths[i],
1026 a_encoding, &sheets[i]);
1027 if (status != CR_OK) {
1028 if (sheets[i]) {
1029 cr_stylesheet_unref (sheets[i]);
1030 sheets[i] = NULL;
1031 }
1032 continue;
1033 }
1034 }
1035 result = cr_cascade_new (sheets[0], sheets[1], sheets[2]);
1036 if (!result) {
1037 for (i = 0; i < 3; i++) {
1038 cr_stylesheet_unref (sheets[i]);
1039 sheets[i] = 0;
1040 }
1041 return CR_ERROR;
1042 }
1043 *a_result = result;
1044 return CR_OK;
1045 }
1047 /**
1048 *Parses three sheets located by their paths and build a cascade
1049 *@param a_author_path the path to the author stylesheet
1050 *@param a_user_path the path to the user stylesheet
1051 *@param a_ua_path the path to the User Agent stylesheet
1052 *@param a_result out parameter. The resulting cascade if the parsing
1053 *was okay
1054 *@return CR_OK upon successful completion, an error code otherwise
1055 */
1056 enum CRStatus
1057 cr_om_parser_simply_parse_paths_to_cascade (const guchar * a_author_path,
1058 const guchar * a_user_path,
1059 const guchar * a_ua_path,
1060 enum CREncoding a_encoding,
1061 CRCascade ** a_result)
1062 {
1063 enum CRStatus status = CR_OK;
1064 CROMParser *parser = NULL;
1066 parser = cr_om_parser_new (NULL);
1067 if (!parser) {
1068 cr_utils_trace_info ("could not allocated om parser");
1069 cr_utils_trace_info ("System may be out of memory");
1070 return CR_ERROR;
1071 }
1072 status = cr_om_parser_parse_paths_to_cascade (parser,
1073 a_author_path,
1074 a_user_path,
1075 a_ua_path,
1076 a_encoding, a_result);
1077 if (parser) {
1078 cr_om_parser_destroy (parser);
1079 parser = NULL;
1080 }
1081 return status;
1082 }
1084 /**
1085 *Destructor of the #CROMParser.
1086 *@param a_this the current instance of #CROMParser.
1087 */
1088 void
1089 cr_om_parser_destroy (CROMParser * a_this)
1090 {
1091 g_return_if_fail (a_this && PRIVATE (a_this));
1093 if (PRIVATE (a_this)->parser) {
1094 cr_parser_destroy (PRIVATE (a_this)->parser);
1095 PRIVATE (a_this)->parser = NULL;
1096 }
1098 if (PRIVATE (a_this)) {
1099 g_free (PRIVATE (a_this));
1100 PRIVATE (a_this) = NULL;
1101 }
1103 if (a_this) {
1104 g_free (a_this);
1105 a_this = NULL;
1106 }
1107 }