Code

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