Code

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