Libcroco
cr-om-parser.c
Go to the documentation of this file.
00001 /* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
00002 
00003 /*
00004  * This file is part of The Croco Library
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of version 2.1 of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00018  * USA
00019  *
00020  * Author: Dodji Seketeli
00021  * See COPYRIGHTS file for copyright information.
00022  */
00023 
00024 #include <string.h>
00025 #include "cr-utils.h"
00026 #include "cr-om-parser.h"
00027 
00028 /**
00029  *@CROMParser:
00030  *
00031  *The definition of the CSS Object Model Parser.
00032  *This parser uses (and sits) the SAC api of libcroco defined
00033  *in cr-parser.h and cr-doc-handler.h
00034  */
00035 
00036 struct _CROMParserPriv {
00037         CRParser *parser;
00038 };
00039 
00040 #define PRIVATE(a_this) ((a_this)->priv)
00041 
00042 /*
00043  *Forward declaration of a type defined later
00044  *in this file.
00045  */
00046 struct _ParsingContext;
00047 typedef struct _ParsingContext ParsingContext;
00048 
00049 static ParsingContext *new_parsing_context (void);
00050 
00051 static void destroy_context (ParsingContext * a_ctxt);
00052 
00053 static void unrecoverable_error (CRDocHandler * a_this);
00054 
00055 static void error (CRDocHandler * a_this);
00056 
00057 static void property (CRDocHandler * a_this,
00058                       CRString * a_name, 
00059                       CRTerm * a_expression, 
00060                       gboolean a_important);
00061 
00062 static void end_selector (CRDocHandler * a_this, 
00063                           CRSelector * a_selector_list);
00064 
00065 static void start_selector (CRDocHandler * a_this, 
00066                             CRSelector * a_selector_list);
00067 
00068 static void start_font_face (CRDocHandler * a_this,
00069                              CRParsingLocation *a_location);
00070 
00071 static void end_font_face (CRDocHandler * a_this);
00072 
00073 static void end_document (CRDocHandler * a_this);
00074 
00075 static void start_document (CRDocHandler * a_this);
00076 
00077 static void charset (CRDocHandler * a_this, 
00078                      CRString * a_charset,
00079                      CRParsingLocation *a_location);
00080 
00081 static void start_page (CRDocHandler * a_this, CRString * a_page,
00082                         CRString * a_pseudo_page, 
00083                         CRParsingLocation *a_location);
00084 
00085 static void end_page (CRDocHandler * a_this, CRString * a_page, 
00086                       CRString * a_pseudo_page);
00087 
00088 static void start_media (CRDocHandler * a_this, 
00089                          GList * a_media_list,
00090                          CRParsingLocation *a_location);
00091 
00092 static void end_media (CRDocHandler * a_this, 
00093                        GList * a_media_list);
00094 
00095 static void import_style (CRDocHandler * a_this, 
00096                           GList * a_media_list,
00097                           CRString * a_uri, 
00098                           CRString * a_uri_default_ns,
00099                           CRParsingLocation *a_location);
00100 
00101 struct _ParsingContext {
00102         CRStyleSheet *stylesheet;
00103         CRStatement *cur_stmt;
00104         CRStatement *cur_media_stmt;
00105 };
00106 
00107 /********************************************
00108  *Private methods
00109  ********************************************/
00110 
00111 static ParsingContext *
00112 new_parsing_context (void)
00113 {
00114         ParsingContext *result = NULL;
00115 
00116         result = g_try_malloc (sizeof (ParsingContext));
00117         if (!result) {
00118                 cr_utils_trace_info ("Out of Memory");
00119                 return NULL;
00120         }
00121         memset (result, 0, sizeof (ParsingContext));
00122         return result;
00123 }
00124 
00125 static void
00126 destroy_context (ParsingContext * a_ctxt)
00127 {
00128         g_return_if_fail (a_ctxt);
00129 
00130         if (a_ctxt->stylesheet) {
00131                 cr_stylesheet_destroy (a_ctxt->stylesheet);
00132                 a_ctxt->stylesheet = NULL;
00133         }
00134         if (a_ctxt->cur_stmt) {
00135                 cr_statement_destroy (a_ctxt->cur_stmt);
00136                 a_ctxt->cur_stmt = NULL;
00137         }
00138         g_free (a_ctxt);
00139 }
00140 
00141 static enum CRStatus
00142 cr_om_parser_init_default_sac_handler (CROMParser * a_this)
00143 {
00144         CRDocHandler *sac_handler = NULL;
00145         gboolean created_handler = FALSE;
00146         enum CRStatus status = CR_OK;
00147 
00148         g_return_val_if_fail (a_this && PRIVATE (a_this)
00149                               && PRIVATE (a_this)->parser,
00150                               CR_BAD_PARAM_ERROR);
00151 
00152         status = cr_parser_get_sac_handler (PRIVATE (a_this)->parser,
00153                                             &sac_handler);
00154         g_return_val_if_fail (status == CR_OK, status);
00155 
00156         if (!sac_handler) {
00157                 sac_handler = cr_doc_handler_new ();
00158                 created_handler = TRUE;
00159         }
00160 
00161         /*
00162          *initialyze here the sac handler.
00163          */
00164         sac_handler->start_document = start_document;
00165         sac_handler->end_document = end_document;
00166         sac_handler->start_selector = start_selector;
00167         sac_handler->end_selector = end_selector;
00168         sac_handler->property = property;
00169         sac_handler->start_font_face = start_font_face;
00170         sac_handler->end_font_face = end_font_face;
00171         sac_handler->error = error;
00172         sac_handler->unrecoverable_error = unrecoverable_error;
00173         sac_handler->charset = charset;
00174         sac_handler->start_page = start_page;
00175         sac_handler->end_page = end_page;
00176         sac_handler->start_media = start_media;
00177         sac_handler->end_media = end_media;
00178         sac_handler->import_style = import_style;
00179 
00180         if (created_handler) {
00181                 status = cr_parser_set_sac_handler (PRIVATE (a_this)->parser,
00182                                                     sac_handler);
00183                 cr_doc_handler_unref (sac_handler);
00184         }
00185 
00186         return status;
00187 
00188 }
00189 
00190 static void
00191 start_document (CRDocHandler * a_this)
00192 {
00193         ParsingContext *ctxt = NULL;
00194         CRStyleSheet *stylesheet = NULL;
00195 
00196         g_return_if_fail (a_this);
00197 
00198         ctxt = new_parsing_context ();
00199         g_return_if_fail (ctxt);
00200 
00201         stylesheet = cr_stylesheet_new (NULL);
00202         ctxt->stylesheet = stylesheet;
00203         cr_doc_handler_set_ctxt (a_this, ctxt);
00204 }
00205 
00206 static void
00207 start_font_face (CRDocHandler * a_this,
00208                  CRParsingLocation *a_location)
00209 {
00210         enum CRStatus status = CR_OK;
00211         ParsingContext *ctxt = NULL;
00212         ParsingContext **ctxtptr = NULL;
00213 
00214         g_return_if_fail (a_this);
00215 
00216         g_return_if_fail (a_this);
00217         ctxtptr = &ctxt;
00218         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00219         g_return_if_fail (status == CR_OK && ctxt);
00220         g_return_if_fail (ctxt->cur_stmt == NULL);
00221 
00222         ctxt->cur_stmt =
00223                 cr_statement_new_at_font_face_rule (ctxt->stylesheet, NULL);
00224 
00225         g_return_if_fail (ctxt->cur_stmt);
00226 }
00227 
00228 static void
00229 end_font_face (CRDocHandler * a_this)
00230 {
00231         enum CRStatus status = CR_OK;
00232         ParsingContext *ctxt = NULL;
00233         ParsingContext **ctxtptr = NULL;
00234         CRStatement *stmts = NULL;
00235 
00236         g_return_if_fail (a_this);
00237 
00238         g_return_if_fail (a_this);
00239         ctxtptr = &ctxt;
00240         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00241         g_return_if_fail (status == CR_OK && ctxt);
00242         g_return_if_fail
00243                 (ctxt->cur_stmt
00244                  && ctxt->cur_stmt->type == AT_FONT_FACE_RULE_STMT
00245                  && ctxt->stylesheet);
00246 
00247         stmts = cr_statement_append (ctxt->stylesheet->statements,
00248                                      ctxt->cur_stmt);
00249         if (!stmts)
00250                 goto error;
00251 
00252         ctxt->stylesheet->statements = stmts;
00253         stmts = NULL;
00254         ctxt->cur_stmt = NULL;
00255 
00256         return;
00257 
00258       error:
00259 
00260         if (ctxt->cur_stmt) {
00261                 cr_statement_destroy (ctxt->cur_stmt);
00262                 ctxt->cur_stmt = NULL;
00263         }
00264 
00265         if (!stmts) {
00266                 cr_statement_destroy (stmts);
00267                 stmts = NULL;
00268         }
00269 }
00270 
00271 static void
00272 end_document (CRDocHandler * a_this)
00273 {
00274         enum CRStatus status = CR_OK;
00275         ParsingContext *ctxt = NULL;
00276         ParsingContext **ctxtptr = NULL;
00277 
00278         g_return_if_fail (a_this);
00279         ctxtptr = &ctxt;
00280         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00281         g_return_if_fail (status == CR_OK && ctxt);
00282 
00283         if (!ctxt->stylesheet || ctxt->cur_stmt)
00284                 goto error;
00285 
00286         status = cr_doc_handler_set_result (a_this, ctxt->stylesheet);
00287         g_return_if_fail (status == CR_OK);
00288 
00289         ctxt->stylesheet = NULL;
00290         destroy_context (ctxt);
00291         cr_doc_handler_set_ctxt (a_this, NULL);
00292 
00293         return;
00294 
00295       error:
00296         if (ctxt) {
00297                 destroy_context (ctxt);
00298         }
00299 }
00300 
00301 static void
00302 charset (CRDocHandler * a_this, CRString * a_charset,
00303          CRParsingLocation *a_location)
00304 {
00305         enum CRStatus status = CR_OK;
00306         CRStatement *stmt = NULL,
00307                 *stmt2 = NULL;
00308         CRString *charset = NULL;
00309 
00310         ParsingContext *ctxt = NULL;
00311         ParsingContext **ctxtptr = NULL;
00312 
00313         g_return_if_fail (a_this);
00314         ctxtptr = &ctxt;
00315         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00316         g_return_if_fail (status == CR_OK && ctxt);
00317         g_return_if_fail (ctxt->stylesheet);
00318 
00319         charset = cr_string_dup (a_charset) ;
00320         stmt = cr_statement_new_at_charset_rule (ctxt->stylesheet, charset);
00321         g_return_if_fail (stmt);
00322         stmt2 = cr_statement_append (ctxt->stylesheet->statements, stmt);
00323         if (!stmt2) {
00324                 if (stmt) {
00325                         cr_statement_destroy (stmt);
00326                         stmt = NULL;
00327                 }
00328                 if (charset) {
00329                         cr_string_destroy (charset);
00330                 }
00331                 return;
00332         }
00333         ctxt->stylesheet->statements = stmt2;
00334         stmt2 = NULL;
00335 }
00336 
00337 static void
00338 start_page (CRDocHandler * a_this, 
00339             CRString * a_page, 
00340             CRString * a_pseudo,
00341             CRParsingLocation *a_location)
00342 {
00343         enum CRStatus status = CR_OK;
00344         ParsingContext *ctxt = NULL;
00345         ParsingContext **ctxtptr = NULL;
00346 
00347         g_return_if_fail (a_this);
00348         ctxtptr = &ctxt;
00349         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00350         g_return_if_fail (status == CR_OK && ctxt);
00351         g_return_if_fail (ctxt->cur_stmt == NULL);
00352 
00353         ctxt->cur_stmt = cr_statement_new_at_page_rule
00354                 (ctxt->stylesheet, NULL, NULL, NULL);
00355         if (a_page) {
00356                 ctxt->cur_stmt->kind.page_rule->name =
00357                         cr_string_dup (a_page) ;
00358 
00359                 if (!ctxt->cur_stmt->kind.page_rule->name) {
00360                         goto error;
00361                 }
00362         }
00363         if (a_pseudo) {
00364                 ctxt->cur_stmt->kind.page_rule->pseudo =
00365                         cr_string_dup (a_pseudo) ;
00366                 if (!ctxt->cur_stmt->kind.page_rule->pseudo) {
00367                         goto error;
00368                 }
00369         }
00370         return;
00371 
00372  error:
00373         if (ctxt->cur_stmt) {
00374                 cr_statement_destroy (ctxt->cur_stmt);
00375                 ctxt->cur_stmt = NULL;
00376         }
00377 }
00378 
00379 static void
00380 end_page (CRDocHandler * a_this, 
00381           CRString * a_page, 
00382           CRString * a_pseudo_page)
00383 {
00384         enum CRStatus status = CR_OK;
00385         ParsingContext *ctxt = NULL;
00386         ParsingContext **ctxtptr = NULL;
00387         CRStatement *stmt = NULL;
00388 
00389         (void) a_page;
00390         (void) a_pseudo_page;
00391 
00392         g_return_if_fail (a_this);
00393 
00394         ctxtptr = &ctxt;
00395         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00396 
00397         g_return_if_fail (status == CR_OK && ctxt);
00398 
00399         g_return_if_fail (ctxt->cur_stmt
00400                           && ctxt->cur_stmt->type == AT_PAGE_RULE_STMT
00401                           && ctxt->stylesheet);
00402 
00403         stmt = cr_statement_append (ctxt->stylesheet->statements,
00404                                     ctxt->cur_stmt);
00405 
00406         if (stmt) {
00407                 ctxt->stylesheet->statements = stmt;
00408                 stmt = NULL;
00409                 ctxt->cur_stmt = NULL;
00410         }
00411 
00412         if (ctxt->cur_stmt) {
00413                 cr_statement_destroy (ctxt->cur_stmt);
00414                 ctxt->cur_stmt = NULL;
00415         }
00416         a_page = NULL;          /*keep compiler happy */
00417         a_pseudo_page = NULL;   /*keep compiler happy */
00418 }
00419 
00420 static void
00421 start_media (CRDocHandler * a_this, 
00422              GList * a_media_list,
00423              CRParsingLocation *a_location)
00424 {
00425         enum CRStatus status = CR_OK;
00426         ParsingContext *ctxt = NULL;
00427         ParsingContext **ctxtptr = NULL;
00428         GList *media_list = NULL;
00429 
00430         g_return_if_fail (a_this);
00431         ctxtptr = &ctxt;
00432         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00433         g_return_if_fail (status == CR_OK && ctxt);
00434 
00435         g_return_if_fail (ctxt
00436                           && ctxt->cur_stmt == NULL
00437                           && ctxt->cur_media_stmt == NULL
00438                           && ctxt->stylesheet);
00439         if (a_media_list) {
00440                 /*duplicate the media_list */
00441                 media_list = cr_utils_dup_glist_of_cr_string 
00442                         (a_media_list);
00443         }
00444         ctxt->cur_media_stmt =
00445                 cr_statement_new_at_media_rule
00446                 (ctxt->stylesheet, NULL, media_list);
00447 
00448 }
00449 
00450 static void
00451 end_media (CRDocHandler * a_this, GList * a_media_list)
00452 {
00453         enum CRStatus status = CR_OK;
00454         ParsingContext *ctxt = NULL;
00455         ParsingContext **ctxtptr = NULL;
00456         CRStatement *stmts = NULL;
00457 
00458         (void) a_media_list;
00459 
00460         g_return_if_fail (a_this);
00461 
00462         ctxtptr = &ctxt;
00463         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00464 
00465         g_return_if_fail (status == CR_OK && ctxt);
00466 
00467         g_return_if_fail (ctxt
00468                           && ctxt->cur_media_stmt
00469                           && ctxt->cur_media_stmt->type == AT_MEDIA_RULE_STMT
00470                           && ctxt->stylesheet);
00471 
00472         stmts = cr_statement_append (ctxt->stylesheet->statements,
00473                                      ctxt->cur_media_stmt);
00474 
00475         if (!stmts) {
00476                 cr_statement_destroy (ctxt->cur_media_stmt);
00477                 ctxt->cur_media_stmt = NULL;
00478         }
00479 
00480         ctxt->stylesheet->statements = stmts;
00481         stmts = NULL;
00482 
00483         ctxt->cur_stmt = NULL ;
00484         ctxt->cur_media_stmt = NULL ;
00485         a_media_list = NULL;
00486 }
00487 
00488 static void
00489 import_style (CRDocHandler * a_this, 
00490               GList * a_media_list,
00491               CRString * a_uri, 
00492               CRString * a_uri_default_ns,
00493               CRParsingLocation *a_location)
00494 {
00495         enum CRStatus status = CR_OK;
00496         CRString *uri = NULL;
00497         CRStatement *stmt = NULL,
00498                 *stmt2 = NULL;
00499         ParsingContext *ctxt = NULL;
00500         ParsingContext **ctxtptr = NULL;
00501         GList *media_list = NULL ;
00502 
00503         (void) a_uri_default_ns;
00504 
00505         g_return_if_fail (a_this);
00506 
00507         ctxtptr = &ctxt;
00508         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00509 
00510         g_return_if_fail (status == CR_OK && ctxt);
00511 
00512         g_return_if_fail (ctxt->stylesheet);
00513 
00514         uri = cr_string_dup (a_uri) ;
00515 
00516         if (a_media_list)
00517                 media_list = cr_utils_dup_glist_of_cr_string (a_media_list) ;
00518 
00519         stmt = cr_statement_new_at_import_rule
00520                 (ctxt->stylesheet, uri, media_list, NULL);
00521 
00522         if (!stmt)
00523                 goto error;
00524 
00525         if (ctxt->cur_stmt) {
00526                 stmt2 = cr_statement_append (ctxt->cur_stmt, stmt);
00527                 if (!stmt2)
00528                         goto error;
00529                 ctxt->cur_stmt = stmt2;
00530                 stmt2 = NULL;
00531                 stmt = NULL;
00532         } else {
00533                 stmt2 = cr_statement_append (ctxt->stylesheet->statements,
00534                                              stmt);
00535                 if (!stmt2)
00536                         goto error;
00537                 ctxt->stylesheet->statements = stmt2;
00538                 stmt2 = NULL;
00539                 stmt = NULL;
00540         }
00541 
00542         return;
00543 
00544       error:
00545         if (uri) {
00546                 cr_string_destroy (uri);
00547         }
00548 
00549         if (stmt) {
00550                 cr_statement_destroy (stmt);
00551                 stmt = NULL;
00552         }
00553         a_uri_default_ns = NULL; /*keep compiler happy */
00554 }
00555 
00556 static void
00557 start_selector (CRDocHandler * a_this, CRSelector * a_selector_list)
00558 {
00559         enum CRStatus status = CR_OK ;
00560         ParsingContext *ctxt = NULL;
00561         ParsingContext **ctxtptr = NULL;
00562 
00563         g_return_if_fail (a_this);
00564         ctxtptr = &ctxt;
00565         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00566         g_return_if_fail (status == CR_OK && ctxt);
00567         if (ctxt->cur_stmt) {
00568                 /*hmm, this should be NULL so free it */
00569                 cr_statement_destroy (ctxt->cur_stmt);
00570                 ctxt->cur_stmt = NULL;
00571         }
00572 
00573         ctxt->cur_stmt = cr_statement_new_ruleset
00574                 (ctxt->stylesheet, a_selector_list, NULL, NULL);
00575 }
00576 
00577 static void
00578 end_selector (CRDocHandler * a_this, CRSelector * a_selector_list)
00579 {
00580         enum CRStatus status = CR_OK;
00581         ParsingContext *ctxt = NULL;
00582         ParsingContext **ctxtptr = NULL;
00583 
00584         (void) a_selector_list;
00585 
00586         g_return_if_fail (a_this);
00587 
00588         ctxtptr = &ctxt;
00589         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00590 
00591         g_return_if_fail (status == CR_OK && ctxt);
00592 
00593         g_return_if_fail (ctxt->cur_stmt && ctxt->stylesheet);
00594 
00595         if (ctxt->cur_stmt) {
00596                 CRStatement *stmts = NULL;
00597 
00598                 if (ctxt->cur_media_stmt) {
00599                         CRAtMediaRule *media_rule = NULL;
00600 
00601                         media_rule = ctxt->cur_media_stmt->kind.media_rule;
00602 
00603                         stmts = cr_statement_append
00604                                 (media_rule->rulesets, ctxt->cur_stmt);
00605 
00606                         if (!stmts) {
00607                                 cr_utils_trace_info
00608                                         ("Could not append a new statement");
00609                                 cr_statement_destroy (media_rule->rulesets);
00610                                 ctxt->cur_media_stmt->
00611                                         kind.media_rule->rulesets = NULL;
00612                                 return;
00613                         }
00614                         media_rule->rulesets = stmts;
00615                         ctxt->cur_stmt = NULL;
00616                 } else {
00617                         stmts = cr_statement_append
00618                                 (ctxt->stylesheet->statements,
00619                                  ctxt->cur_stmt);
00620                         if (!stmts) {
00621                                 cr_utils_trace_info
00622                                         ("Could not append a new statement");
00623                                 cr_statement_destroy (ctxt->cur_stmt);
00624                                 ctxt->cur_stmt = NULL;
00625                                 return;
00626                         }
00627                         ctxt->stylesheet->statements = stmts;
00628                         ctxt->cur_stmt = NULL;
00629                 }
00630 
00631         }
00632 
00633         a_selector_list = NULL; /*keep compiler happy */
00634 }
00635 
00636 static void
00637 property (CRDocHandler * a_this,
00638           CRString * a_name, 
00639           CRTerm * a_expression, 
00640           gboolean a_important)
00641 {
00642         enum CRStatus status = CR_OK;
00643         ParsingContext *ctxt = NULL;
00644         ParsingContext **ctxtptr = NULL;
00645         CRDeclaration *decl = NULL,
00646                 *decl2 = NULL;
00647         CRString *str = NULL;
00648 
00649         g_return_if_fail (a_this);
00650         ctxtptr = &ctxt;
00651         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00652         g_return_if_fail (status == CR_OK && ctxt);
00653 
00654         /*
00655          *make sure a current ruleset statement has been allocated
00656          *already.
00657          */
00658         g_return_if_fail
00659                 (ctxt->cur_stmt
00660                  &&
00661                  (ctxt->cur_stmt->type == RULESET_STMT
00662                   || ctxt->cur_stmt->type == AT_FONT_FACE_RULE_STMT
00663                   || ctxt->cur_stmt->type == AT_PAGE_RULE_STMT));
00664 
00665         if (a_name) {
00666                 str = cr_string_dup (a_name);
00667                 g_return_if_fail (str);
00668         }
00669 
00670         /*instanciates a new declaration */
00671         decl = cr_declaration_new (ctxt->cur_stmt, str, a_expression);
00672         g_return_if_fail (decl);
00673         str = NULL;
00674         decl->important = a_important;
00675         /*
00676          *add the new declaration to the current statement
00677          *being build.
00678          */
00679         switch (ctxt->cur_stmt->type) {
00680         case RULESET_STMT:
00681                 decl2 = cr_declaration_append
00682                         (ctxt->cur_stmt->kind.ruleset->decl_list, decl);
00683                 if (!decl2) {
00684                         cr_declaration_destroy (decl);
00685                         cr_utils_trace_info
00686                                 ("Could not append decl to ruleset");
00687                         goto error;
00688                 }
00689                 ctxt->cur_stmt->kind.ruleset->decl_list = decl2;
00690                 decl = NULL;
00691                 decl2 = NULL;
00692                 break;
00693 
00694         case AT_FONT_FACE_RULE_STMT:
00695                 decl2 = cr_declaration_append
00696                         (ctxt->cur_stmt->kind.font_face_rule->decl_list,
00697                          decl);
00698                 if (!decl2) {
00699                         cr_declaration_destroy (decl);
00700                         cr_utils_trace_info
00701                                 ("Could not append decl to ruleset");
00702                         goto error;
00703                 }
00704                 ctxt->cur_stmt->kind.font_face_rule->decl_list = decl2;
00705                 decl = NULL;
00706                 decl2 = NULL;
00707                 break;
00708         case AT_PAGE_RULE_STMT:
00709                 decl2 = cr_declaration_append
00710                         (ctxt->cur_stmt->kind.page_rule->decl_list, decl);
00711                 if (!decl2) {
00712                         cr_declaration_destroy (decl);
00713                         cr_utils_trace_info
00714                                 ("Could not append decl to ruleset");
00715                         goto error;
00716                 }
00717                 ctxt->cur_stmt->kind.page_rule->decl_list = decl2;
00718                 decl = NULL;
00719                 decl2 = NULL;
00720                 break;
00721 
00722         default:
00723                 goto error;
00724                 break;
00725         }
00726 
00727         return;
00728 
00729       error:
00730         if (str) {
00731                 g_free (str);
00732                 str = NULL;
00733         }
00734 
00735         if (decl) {
00736                 cr_declaration_destroy (decl);
00737                 decl = NULL;
00738         }
00739 }
00740 
00741 static void
00742 error (CRDocHandler * a_this)
00743 {
00744         enum CRStatus status = CR_OK;
00745         ParsingContext *ctxt = NULL;
00746         ParsingContext **ctxtptr = NULL;
00747 
00748         g_return_if_fail (a_this);
00749         ctxtptr = &ctxt;
00750         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00751         g_return_if_fail (status == CR_OK && ctxt);
00752 
00753         if (ctxt->cur_stmt) {
00754                 cr_statement_destroy (ctxt->cur_stmt);
00755                 ctxt->cur_stmt = NULL;
00756         }
00757 }
00758 
00759 static void
00760 unrecoverable_error (CRDocHandler * a_this)
00761 {
00762         enum CRStatus status = CR_OK;
00763         ParsingContext *ctxt = NULL;
00764         ParsingContext **ctxtptr = NULL;
00765 
00766         ctxtptr = &ctxt;
00767         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00768         g_return_if_fail (status == CR_OK);
00769 
00770         if (ctxt) {
00771                 if (ctxt->stylesheet) {
00772                         status = cr_doc_handler_set_result
00773                                 (a_this, ctxt->stylesheet);
00774                         g_return_if_fail (status == CR_OK);
00775                 }
00776                 g_free (ctxt);
00777                 cr_doc_handler_set_ctxt (a_this, NULL);
00778         }
00779 }
00780 
00781 /********************************************
00782  *Public methods
00783  ********************************************/
00784 
00785 /**
00786  * cr_om_parser_new:
00787  *@a_input: the input stream.
00788  *
00789  *Constructor of the CROMParser.
00790  *Returns the newly built instance of #CROMParser.
00791  */
00792 CROMParser *
00793 cr_om_parser_new (CRInput * a_input)
00794 {
00795         CROMParser *result = NULL;
00796         enum CRStatus status = CR_OK;
00797 
00798         result = g_try_malloc (sizeof (CROMParser));
00799 
00800         if (!result) {
00801                 cr_utils_trace_info ("Out of memory");
00802                 return NULL;
00803         }
00804 
00805         memset (result, 0, sizeof (CROMParser));
00806         PRIVATE (result) = g_try_malloc (sizeof (CROMParserPriv));
00807 
00808         if (!PRIVATE (result)) {
00809                 cr_utils_trace_info ("Out of memory");
00810                 goto error;
00811         }
00812 
00813         memset (PRIVATE (result), 0, sizeof (CROMParserPriv));
00814 
00815         PRIVATE (result)->parser = cr_parser_new_from_input (a_input);
00816 
00817         if (!PRIVATE (result)->parser) {
00818                 cr_utils_trace_info ("parsing instantiation failed");
00819                 goto error;
00820         }
00821 
00822         status = cr_om_parser_init_default_sac_handler (result);
00823 
00824         if (status != CR_OK) {
00825                 goto error;
00826         }
00827 
00828         return result;
00829 
00830       error:
00831 
00832         if (result) {
00833                 cr_om_parser_destroy (result);
00834         }
00835 
00836         return NULL;
00837 }
00838 
00839 /**
00840  * cr_om_parser_parse_buf:
00841  *@a_this: the current instance of #CROMParser.
00842  *@a_buf: the in memory buffer to parse.
00843  *@a_len: the length of the in memory buffer in number of bytes.
00844  *@a_enc: the encoding of the in memory buffer.
00845  *@a_result: out parameter the resulting style sheet
00846  *
00847  *Parses the content of an in memory  buffer.
00848  *
00849  *Returns CR_OK upon successfull completion, an error code otherwise.
00850  */
00851 enum CRStatus
00852 cr_om_parser_parse_buf (CROMParser * a_this,
00853                         const guchar * a_buf,
00854                         gulong a_len,
00855                         enum CREncoding a_enc, CRStyleSheet ** a_result)
00856 {
00857 
00858         enum CRStatus status = CR_OK;
00859 
00860         g_return_val_if_fail (a_this && a_result, CR_BAD_PARAM_ERROR);
00861 
00862         if (!PRIVATE (a_this)->parser) {
00863                 PRIVATE (a_this)->parser = cr_parser_new (NULL);
00864         }
00865 
00866         status = cr_parser_parse_buf (PRIVATE (a_this)->parser,
00867                                       a_buf, a_len, a_enc);
00868 
00869         if (status == CR_OK) {
00870                 CRStyleSheet *result = NULL;
00871                 CRStyleSheet **resultptr = NULL;
00872                 CRDocHandler *sac_handler = NULL;
00873 
00874                 cr_parser_get_sac_handler (PRIVATE (a_this)->parser,
00875                                            &sac_handler);
00876                 g_return_val_if_fail (sac_handler, CR_ERROR);
00877                 resultptr = &result;
00878                 status = cr_doc_handler_get_result (sac_handler,
00879                                                     (gpointer *) resultptr);
00880                 g_return_val_if_fail (status == CR_OK, status);
00881 
00882                 if (result)
00883                         *a_result = result;
00884         }
00885 
00886         return status;
00887 }
00888 
00889 /**
00890  * cr_om_parser_simply_parse_buf:
00891  *@a_buf: the css2 in memory buffer.
00892  *@a_len: the length of the in memory buffer.
00893  *@a_enc: the encoding of the in memory buffer.
00894  *@a_result: out parameter. The resulting css2 style sheet.
00895  *
00896  *The simpler way to parse an in memory css2 buffer.
00897  *
00898  *Returns CR_OK upon successfull completion, an error code otherwise.
00899  */
00900 enum CRStatus
00901 cr_om_parser_simply_parse_buf (const guchar * a_buf,
00902                                gulong a_len,
00903                                enum CREncoding a_enc,
00904                                CRStyleSheet ** a_result)
00905 {
00906         CROMParser *parser = NULL;
00907         enum CRStatus status = CR_OK;
00908 
00909         parser = cr_om_parser_new (NULL);
00910         if (!parser) {
00911                 cr_utils_trace_info ("Could not create om parser");
00912                 cr_utils_trace_info ("System possibly out of memory");
00913                 return CR_ERROR;
00914         }
00915 
00916         status = cr_om_parser_parse_buf (parser, a_buf, a_len,
00917                                          a_enc, a_result);
00918 
00919         if (parser) {
00920                 cr_om_parser_destroy (parser);
00921                 parser = NULL;
00922         }
00923 
00924         return status;
00925 }
00926 
00927 /**
00928  * cr_om_parser_parse_file:
00929  *@a_this: the current instance of the cssom parser.
00930  *@a_file_uri: the uri of the file. 
00931  *(only local file paths are suppported so far)
00932  *@a_enc: the encoding of the file.
00933  *@a_result: out parameter. A pointer 
00934  *the build css object model.
00935  *
00936  *Parses a css2 stylesheet contained
00937  *in a file.
00938  *
00939  * Returns CR_OK upon succesful completion, an error code otherwise.
00940  */
00941 enum CRStatus
00942 cr_om_parser_parse_file (CROMParser * a_this,
00943                          const guchar * a_file_uri,
00944                          enum CREncoding a_enc, CRStyleSheet ** a_result)
00945 {
00946         enum CRStatus status = CR_OK;
00947 
00948         g_return_val_if_fail (a_this && a_file_uri && a_result,
00949                               CR_BAD_PARAM_ERROR);
00950 
00951         if (!PRIVATE (a_this)->parser) {
00952                 PRIVATE (a_this)->parser = cr_parser_new_from_file
00953                         (a_file_uri, a_enc);
00954         }
00955 
00956         status = cr_parser_parse_file (PRIVATE (a_this)->parser,
00957                                        a_file_uri, a_enc);
00958 
00959         if (status == CR_OK) {
00960                 CRStyleSheet *result = NULL;
00961                 CRStyleSheet **resultptr = NULL;
00962                 CRDocHandler *sac_handler = NULL;
00963 
00964                 cr_parser_get_sac_handler (PRIVATE (a_this)->parser,
00965                                            &sac_handler);
00966                 g_return_val_if_fail (sac_handler, CR_ERROR);
00967                 resultptr = &result;
00968                 status = cr_doc_handler_get_result
00969                         (sac_handler, (gpointer *) resultptr);
00970                 g_return_val_if_fail (status == CR_OK, status);
00971                 if (result)
00972                         *a_result = result;
00973         }
00974 
00975         return status;
00976 }
00977 
00978 /**
00979  * cr_om_parser_simply_parse_file:
00980  *@a_file_path: the css2 local file path.
00981  *@a_enc: the file encoding.
00982  *@a_result: out parameter. The returned css stylesheet.
00983  *Must be freed by the caller using cr_stylesheet_destroy.
00984  *
00985  *The simpler method to parse a css2 file.
00986  *
00987  *Returns CR_OK upon successfull completion, an error code otherwise.
00988  *Note that this method uses cr_om_parser_parse_file() so both methods
00989  *have the same return values.
00990  */
00991 enum CRStatus
00992 cr_om_parser_simply_parse_file (const guchar * a_file_path,
00993                                 enum CREncoding a_enc,
00994                                 CRStyleSheet ** a_result)
00995 {
00996         CROMParser *parser = NULL;
00997         enum CRStatus status = CR_OK;
00998 
00999         parser = cr_om_parser_new (NULL);
01000         if (!parser) {
01001                 cr_utils_trace_info ("Could not allocate om parser");
01002                 cr_utils_trace_info ("System may be out of memory");
01003                 return CR_ERROR;
01004         }
01005 
01006         status = cr_om_parser_parse_file (parser, a_file_path,
01007                                           a_enc, a_result);
01008         if (parser) {
01009                 cr_om_parser_destroy (parser);
01010                 parser = NULL;
01011         }
01012 
01013         return status;
01014 }
01015 
01016 /**
01017  * cr_om_parser_parse_paths_to_cascade:
01018  *@a_this: the current instance of #CROMParser
01019  *@a_author_path: the path to the author stylesheet
01020  *@a_user_path: the path to the user stylesheet
01021  *@a_ua_path: the path to the User Agent stylesheet
01022  *@a_encoding: the encoding of the sheets.
01023  *@a_result: out parameter. The resulting cascade if the parsing
01024  *was okay
01025  *
01026  *Parses three sheets located by their paths and build a cascade
01027  *
01028  *Returns CR_OK upon successful completion, an error code otherwise
01029  */
01030 enum CRStatus
01031 cr_om_parser_parse_paths_to_cascade (CROMParser * a_this,
01032                                      const guchar * a_author_path,
01033                                      const guchar * a_user_path,
01034                                      const guchar * a_ua_path,
01035                                      enum CREncoding a_encoding,
01036                                      CRCascade ** a_result)
01037 {
01038         enum CRStatus status = CR_OK;
01039 
01040         /*0->author sheet, 1->user sheet, 2->UA sheet */
01041         CRStyleSheet *sheets[3];
01042         guchar *paths[3];
01043         CRCascade *result = NULL;
01044         gint i = 0;
01045 
01046         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
01047 
01048         memset (sheets, 0, sizeof (CRStyleSheet*) * 3);
01049         paths[0] = (guchar *) a_author_path;
01050         paths[1] = (guchar *) a_user_path;
01051         paths[2] = (guchar *) a_ua_path;
01052 
01053         for (i = 0; i < 3; i++) {
01054                 status = cr_om_parser_parse_file (a_this, paths[i],
01055                                                   a_encoding, &sheets[i]);
01056                 if (status != CR_OK) {
01057                         if (sheets[i]) {
01058                                 cr_stylesheet_unref (sheets[i]);
01059                                 sheets[i] = NULL;
01060                         }
01061                         continue;
01062                 }
01063         }
01064         result = cr_cascade_new (sheets[0], sheets[1], sheets[2]);
01065         if (!result) {
01066                 for (i = 0; i < 3; i++) {
01067                         cr_stylesheet_unref (sheets[i]);
01068                         sheets[i] = 0;
01069                 }
01070                 return CR_ERROR;
01071         }
01072         *a_result = result;
01073         return CR_OK;
01074 }
01075 
01076 /**
01077  * cr_om_parser_simply_parse_paths_to_cascade:
01078  *@a_author_path: the path to the author stylesheet
01079  *@a_user_path: the path to the user stylesheet
01080  *@a_ua_path: the path to the User Agent stylesheet
01081  *@a_encoding: the encoding of the sheets.
01082  *@a_result: out parameter. The resulting cascade if the parsing
01083  *was okay
01084  *
01085  *Parses three sheets located by their paths and build a cascade
01086  *
01087  *Returns CR_OK upon successful completion, an error code otherwise
01088  */
01089 enum CRStatus
01090 cr_om_parser_simply_parse_paths_to_cascade (const guchar * a_author_path,
01091                                             const guchar * a_user_path,
01092                                             const guchar * a_ua_path,
01093                                             enum CREncoding a_encoding,
01094                                             CRCascade ** a_result)
01095 {
01096         enum CRStatus status = CR_OK;
01097         CROMParser *parser = NULL;
01098 
01099         parser = cr_om_parser_new (NULL);
01100         if (!parser) {
01101                 cr_utils_trace_info ("could not allocated om parser");
01102                 cr_utils_trace_info ("System may be out of memory");
01103                 return CR_ERROR;
01104         }
01105         status = cr_om_parser_parse_paths_to_cascade (parser,
01106                                                       a_author_path,
01107                                                       a_user_path,
01108                                                       a_ua_path,
01109                                                       a_encoding, a_result);
01110         if (parser) {
01111                 cr_om_parser_destroy (parser);
01112                 parser = NULL;
01113         }
01114         return status;
01115 }
01116 
01117 /**
01118  * cr_om_parser_destroy:
01119  *@a_this: the current instance of #CROMParser.
01120  *
01121  *Destructor of the #CROMParser.
01122  */
01123 void
01124 cr_om_parser_destroy (CROMParser * a_this)
01125 {
01126         g_return_if_fail (a_this && PRIVATE (a_this));
01127 
01128         if (PRIVATE (a_this)->parser) {
01129                 cr_parser_destroy (PRIVATE (a_this)->parser);
01130                 PRIVATE (a_this)->parser = NULL;
01131         }
01132 
01133         if (PRIVATE (a_this)) {
01134                 g_free (PRIVATE (a_this));
01135                 PRIVATE (a_this) = NULL;
01136         }
01137 
01138         if (a_this) {
01139                 g_free (a_this);
01140                 a_this = NULL;
01141         }
01142 }