• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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