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