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