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