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         g_return_if_fail (a_this);
00390         ctxtptr = &ctxt;
00391         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00392         g_return_if_fail (status == CR_OK && ctxt);
00393         g_return_if_fail (ctxt->cur_stmt
00394                           && ctxt->cur_stmt->type == AT_PAGE_RULE_STMT
00395                           && ctxt->stylesheet);
00396 
00397         stmt = cr_statement_append (ctxt->stylesheet->statements,
00398                                     ctxt->cur_stmt);
00399 
00400         if (stmt) {
00401                 ctxt->stylesheet->statements = stmt;
00402                 stmt = NULL;
00403                 ctxt->cur_stmt = NULL;
00404         }
00405 
00406         if (ctxt->cur_stmt) {
00407                 cr_statement_destroy (ctxt->cur_stmt);
00408                 ctxt->cur_stmt = NULL;
00409         }
00410         a_page = NULL;          /*keep compiler happy */
00411         a_pseudo_page = NULL;   /*keep compiler happy */
00412 }
00413 
00414 static void
00415 start_media (CRDocHandler * a_this, 
00416              GList * a_media_list,
00417              CRParsingLocation *a_location)
00418 {
00419         enum CRStatus status = CR_OK;
00420         ParsingContext *ctxt = NULL;
00421         ParsingContext **ctxtptr = NULL;
00422         GList *media_list = NULL;
00423 
00424         g_return_if_fail (a_this);
00425         ctxtptr = &ctxt;
00426         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00427         g_return_if_fail (status == CR_OK && ctxt);
00428 
00429         g_return_if_fail (ctxt
00430                           && ctxt->cur_stmt == NULL
00431                           && ctxt->cur_media_stmt == NULL
00432                           && ctxt->stylesheet);
00433         if (a_media_list) {
00434                 /*duplicate the media_list */
00435                 media_list = cr_utils_dup_glist_of_cr_string 
00436                         (a_media_list);
00437         }
00438         ctxt->cur_media_stmt =
00439                 cr_statement_new_at_media_rule
00440                 (ctxt->stylesheet, NULL, media_list);
00441 
00442 }
00443 
00444 static void
00445 end_media (CRDocHandler * a_this, GList * a_media_list)
00446 {
00447         enum CRStatus status = CR_OK;
00448         ParsingContext *ctxt = NULL;
00449         ParsingContext **ctxtptr = NULL;
00450         CRStatement *stmts = NULL;
00451 
00452         g_return_if_fail (a_this);
00453         ctxtptr = &ctxt;
00454         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00455         g_return_if_fail (status == CR_OK && ctxt);
00456         g_return_if_fail (ctxt
00457                           && ctxt->cur_media_stmt
00458                           && ctxt->cur_media_stmt->type == AT_MEDIA_RULE_STMT
00459                           && ctxt->stylesheet);
00460 
00461         stmts = cr_statement_append (ctxt->stylesheet->statements,
00462                                      ctxt->cur_media_stmt);
00463         if (!stmts) {
00464                 cr_statement_destroy (ctxt->cur_media_stmt);
00465                 ctxt->cur_media_stmt = NULL;
00466         }
00467 
00468         ctxt->stylesheet->statements = stmts;
00469         stmts = NULL;
00470 
00471         ctxt->cur_stmt = NULL ;
00472         ctxt->cur_media_stmt = NULL ;
00473         a_media_list = NULL;
00474 }
00475 
00476 static void
00477 import_style (CRDocHandler * a_this, 
00478               GList * a_media_list,
00479               CRString * a_uri, 
00480               CRString * a_uri_default_ns,
00481               CRParsingLocation *a_location)
00482 {
00483         enum CRStatus status = CR_OK;
00484         CRString *uri = NULL;
00485         CRStatement *stmt = NULL,
00486                 *stmt2 = NULL;
00487         ParsingContext *ctxt = NULL;
00488         ParsingContext **ctxtptr = NULL;
00489         GList *media_list = NULL ;
00490 
00491         g_return_if_fail (a_this);
00492         ctxtptr = &ctxt;
00493         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00494         g_return_if_fail (status == CR_OK && ctxt);
00495         g_return_if_fail (ctxt->stylesheet);
00496 
00497         uri = cr_string_dup (a_uri) ;
00498         if (a_media_list)
00499                 media_list = cr_utils_dup_glist_of_cr_string (a_media_list) ;
00500         stmt = cr_statement_new_at_import_rule
00501                 (ctxt->stylesheet, uri, media_list, NULL);
00502         if (!stmt)
00503                 goto error;
00504 
00505         if (ctxt->cur_stmt) {
00506                 stmt2 = cr_statement_append (ctxt->cur_stmt, stmt);
00507                 if (!stmt2)
00508                         goto error;
00509                 ctxt->cur_stmt = stmt2;
00510                 stmt2 = NULL;
00511                 stmt = NULL;
00512         } else {
00513                 stmt2 = cr_statement_append (ctxt->stylesheet->statements,
00514                                              stmt);
00515                 if (!stmt2)
00516                         goto error;
00517                 ctxt->stylesheet->statements = stmt2;
00518                 stmt2 = NULL;
00519                 stmt = NULL;
00520         }
00521 
00522         return;
00523 
00524       error:
00525         if (uri) {
00526                 cr_string_destroy (uri);
00527         }
00528 
00529         if (stmt) {
00530                 cr_statement_destroy (stmt);
00531                 stmt = NULL;
00532         }
00533         a_uri_default_ns = NULL; /*keep compiler happy */
00534 }
00535 
00536 static void
00537 start_selector (CRDocHandler * a_this, CRSelector * a_selector_list)
00538 {
00539         enum CRStatus status = CR_OK ;
00540         ParsingContext *ctxt = NULL;
00541         ParsingContext **ctxtptr = NULL;
00542 
00543         g_return_if_fail (a_this);
00544         ctxtptr = &ctxt;
00545         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00546         g_return_if_fail (status == CR_OK && ctxt);
00547         if (ctxt->cur_stmt) {
00548                 /*hmm, this should be NULL so free it */
00549                 cr_statement_destroy (ctxt->cur_stmt);
00550                 ctxt->cur_stmt = NULL;
00551         }
00552 
00553         ctxt->cur_stmt = cr_statement_new_ruleset
00554                 (ctxt->stylesheet, a_selector_list, NULL, NULL);
00555 }
00556 
00557 static void
00558 end_selector (CRDocHandler * a_this, CRSelector * a_selector_list)
00559 {
00560         enum CRStatus status = CR_OK;
00561         ParsingContext *ctxt = NULL;
00562         ParsingContext **ctxtptr = NULL;
00563 
00564         g_return_if_fail (a_this);
00565         ctxtptr = &ctxt;
00566         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00567         g_return_if_fail (status == CR_OK && ctxt);
00568         g_return_if_fail (ctxt->cur_stmt && ctxt->stylesheet);
00569 
00570         if (ctxt->cur_stmt) {
00571                 CRStatement *stmts = NULL;
00572 
00573                 if (ctxt->cur_media_stmt) {
00574                         CRAtMediaRule *media_rule = NULL;
00575 
00576                         media_rule = ctxt->cur_media_stmt->kind.media_rule;
00577 
00578                         stmts = cr_statement_append
00579                                 (media_rule->rulesets, ctxt->cur_stmt);
00580 
00581                         if (!stmts) {
00582                                 cr_utils_trace_info
00583                                         ("Could not append a new statement");
00584                                 cr_statement_destroy (media_rule->rulesets);
00585                                 ctxt->cur_media_stmt->
00586                                         kind.media_rule->rulesets = NULL;
00587                                 return;
00588                         }
00589                         media_rule->rulesets = stmts;
00590                         ctxt->cur_stmt = NULL;
00591                 } else {
00592                         stmts = cr_statement_append
00593                                 (ctxt->stylesheet->statements,
00594                                  ctxt->cur_stmt);
00595                         if (!stmts) {
00596                                 cr_utils_trace_info
00597                                         ("Could not append a new statement");
00598                                 cr_statement_destroy (ctxt->cur_stmt);
00599                                 ctxt->cur_stmt = NULL;
00600                                 return;
00601                         }
00602                         ctxt->stylesheet->statements = stmts;
00603                         ctxt->cur_stmt = NULL;
00604                 }
00605 
00606         }
00607         a_selector_list = NULL; /*keep compiler happy */
00608 }
00609 
00610 static void
00611 property (CRDocHandler * a_this,
00612           CRString * a_name, 
00613           CRTerm * a_expression, 
00614           gboolean a_important)
00615 {
00616         enum CRStatus status = CR_OK;
00617         ParsingContext *ctxt = NULL;
00618         ParsingContext **ctxtptr = NULL;
00619         CRDeclaration *decl = NULL,
00620                 *decl2 = NULL;
00621         CRString *str = NULL;
00622 
00623         g_return_if_fail (a_this);
00624         ctxtptr = &ctxt;
00625         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00626         g_return_if_fail (status == CR_OK && ctxt);
00627 
00628         /*
00629          *make sure a current ruleset statement has been allocated
00630          *already.
00631          */
00632         g_return_if_fail
00633                 (ctxt->cur_stmt
00634                  &&
00635                  (ctxt->cur_stmt->type == RULESET_STMT
00636                   || ctxt->cur_stmt->type == AT_FONT_FACE_RULE_STMT
00637                   || ctxt->cur_stmt->type == AT_PAGE_RULE_STMT));
00638 
00639         if (a_name) {
00640                 str = cr_string_dup (a_name);
00641                 g_return_if_fail (str);
00642         }
00643 
00644         /*instanciates a new declaration */
00645         decl = cr_declaration_new (ctxt->cur_stmt, str, a_expression);
00646         g_return_if_fail (decl);
00647         str = NULL;
00648         decl->important = a_important;
00649         /*
00650          *add the new declaration to the current statement
00651          *being build.
00652          */
00653         switch (ctxt->cur_stmt->type) {
00654         case RULESET_STMT:
00655                 decl2 = cr_declaration_append
00656                         (ctxt->cur_stmt->kind.ruleset->decl_list, decl);
00657                 if (!decl2) {
00658                         cr_declaration_destroy (decl);
00659                         cr_utils_trace_info
00660                                 ("Could not append decl to ruleset");
00661                         goto error;
00662                 }
00663                 ctxt->cur_stmt->kind.ruleset->decl_list = decl2;
00664                 decl = NULL;
00665                 decl2 = NULL;
00666                 break;
00667 
00668         case AT_FONT_FACE_RULE_STMT:
00669                 decl2 = cr_declaration_append
00670                         (ctxt->cur_stmt->kind.font_face_rule->decl_list,
00671                          decl);
00672                 if (!decl2) {
00673                         cr_declaration_destroy (decl);
00674                         cr_utils_trace_info
00675                                 ("Could not append decl to ruleset");
00676                         goto error;
00677                 }
00678                 ctxt->cur_stmt->kind.font_face_rule->decl_list = decl2;
00679                 decl = NULL;
00680                 decl2 = NULL;
00681                 break;
00682         case AT_PAGE_RULE_STMT:
00683                 decl2 = cr_declaration_append
00684                         (ctxt->cur_stmt->kind.page_rule->decl_list, decl);
00685                 if (!decl2) {
00686                         cr_declaration_destroy (decl);
00687                         cr_utils_trace_info
00688                                 ("Could not append decl to ruleset");
00689                         goto error;
00690                 }
00691                 ctxt->cur_stmt->kind.page_rule->decl_list = decl2;
00692                 decl = NULL;
00693                 decl2 = NULL;
00694                 break;
00695 
00696         default:
00697                 goto error;
00698                 break;
00699         }
00700 
00701         return;
00702 
00703       error:
00704         if (str) {
00705                 g_free (str);
00706                 str = NULL;
00707         }
00708 
00709         if (decl) {
00710                 cr_declaration_destroy (decl);
00711                 decl = NULL;
00712         }
00713 }
00714 
00715 static void
00716 error (CRDocHandler * a_this)
00717 {
00718         enum CRStatus status = CR_OK;
00719         ParsingContext *ctxt = NULL;
00720         ParsingContext **ctxtptr = NULL;
00721 
00722         g_return_if_fail (a_this);
00723         ctxtptr = &ctxt;
00724         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00725         g_return_if_fail (status == CR_OK && ctxt);
00726 
00727         if (ctxt->cur_stmt) {
00728                 cr_statement_destroy (ctxt->cur_stmt);
00729                 ctxt->cur_stmt = NULL;
00730         }
00731 }
00732 
00733 static void
00734 unrecoverable_error (CRDocHandler * a_this)
00735 {
00736         enum CRStatus status = CR_OK;
00737         ParsingContext *ctxt = NULL;
00738         ParsingContext **ctxtptr = NULL;
00739 
00740         ctxtptr = &ctxt;
00741         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
00742         g_return_if_fail (status == CR_OK);
00743 
00744         if (ctxt) {
00745                 if (ctxt->stylesheet) {
00746                         status = cr_doc_handler_set_result
00747                                 (a_this, ctxt->stylesheet);
00748                         g_return_if_fail (status == CR_OK);
00749                 }
00750                 g_free (ctxt);
00751                 cr_doc_handler_set_ctxt (a_this, NULL);
00752         }
00753 }
00754 
00755 /********************************************
00756  *Public methods
00757  ********************************************/
00758 
00759 /**
00760  * cr_om_parser_new:
00761  *@a_input: the input stream.
00762  *
00763  *Constructor of the CROMParser.
00764  *Returns the newly built instance of #CROMParser.
00765  */
00766 CROMParser *
00767 cr_om_parser_new (CRInput * a_input)
00768 {
00769         CROMParser *result = NULL;
00770         enum CRStatus status = CR_OK;
00771 
00772         result = g_try_malloc (sizeof (CROMParser));
00773 
00774         if (!result) {
00775                 cr_utils_trace_info ("Out of memory");
00776                 return NULL;
00777         }
00778 
00779         memset (result, 0, sizeof (CROMParser));
00780         PRIVATE (result) = g_try_malloc (sizeof (CROMParserPriv));
00781 
00782         if (!PRIVATE (result)) {
00783                 cr_utils_trace_info ("Out of memory");
00784                 goto error;
00785         }
00786 
00787         memset (PRIVATE (result), 0, sizeof (CROMParserPriv));
00788 
00789         PRIVATE (result)->parser = cr_parser_new_from_input (a_input);
00790 
00791         if (!PRIVATE (result)->parser) {
00792                 cr_utils_trace_info ("parsing instanciation failed");
00793                 goto error;
00794         }
00795 
00796         status = cr_om_parser_init_default_sac_handler (result);
00797 
00798         if (status != CR_OK) {
00799                 goto error;
00800         }
00801 
00802         return result;
00803 
00804       error:
00805 
00806         if (result) {
00807                 cr_om_parser_destroy (result);
00808         }
00809 
00810         return NULL;
00811 }
00812 
00813 /**
00814  * cr_om_parser_parse_buf:
00815  *@a_this: the current instance of #CROMParser.
00816  *@a_buf: the in memory buffer to parse.
00817  *@a_len: the length of the in memory buffer in number of bytes.
00818  *@a_enc: the encoding of the in memory buffer.
00819  *@a_result: out parameter the resulting style sheet
00820  *
00821  *Parses the content of an in memory  buffer.
00822  *
00823  *Returns CR_OK upon successfull completion, an error code otherwise.
00824  */
00825 enum CRStatus
00826 cr_om_parser_parse_buf (CROMParser * a_this,
00827                         const guchar * a_buf,
00828                         gulong a_len,
00829                         enum CREncoding a_enc, CRStyleSheet ** a_result)
00830 {
00831 
00832         enum CRStatus status = CR_OK;
00833 
00834         g_return_val_if_fail (a_this && a_result, CR_BAD_PARAM_ERROR);
00835 
00836         if (!PRIVATE (a_this)->parser) {
00837                 PRIVATE (a_this)->parser = cr_parser_new (NULL);
00838         }
00839 
00840         status = cr_parser_parse_buf (PRIVATE (a_this)->parser,
00841                                       a_buf, a_len, a_enc);
00842 
00843         if (status == CR_OK) {
00844                 CRStyleSheet *result = NULL;
00845                 CRStyleSheet **resultptr = NULL;
00846                 CRDocHandler *sac_handler = NULL;
00847 
00848                 cr_parser_get_sac_handler (PRIVATE (a_this)->parser,
00849                                            &sac_handler);
00850                 g_return_val_if_fail (sac_handler, CR_ERROR);
00851                 resultptr = &result;
00852                 status = cr_doc_handler_get_result (sac_handler,
00853                                                     (gpointer *) resultptr);
00854                 g_return_val_if_fail (status == CR_OK, status);
00855 
00856                 if (result)
00857                         *a_result = result;
00858         }
00859 
00860         return status;
00861 }
00862 
00863 /**
00864  * cr_om_parser_simply_parse_buf:
00865  *@a_buf: the css2 in memory buffer.
00866  *@a_len: the length of the in memory buffer.
00867  *@a_enc: the encoding of the in memory buffer.
00868  *@a_result: out parameter. The resulting css2 style sheet.
00869  *
00870  *The simpler way to parse an in memory css2 buffer.
00871  *
00872  *Returns CR_OK upon successfull completion, an error code otherwise.
00873  */
00874 enum CRStatus
00875 cr_om_parser_simply_parse_buf (const guchar * a_buf,
00876                                gulong a_len,
00877                                enum CREncoding a_enc,
00878                                CRStyleSheet ** a_result)
00879 {
00880         CROMParser *parser = NULL;
00881         enum CRStatus status = CR_OK;
00882 
00883         parser = cr_om_parser_new (NULL);
00884         if (!parser) {
00885                 cr_utils_trace_info ("Could not create om parser");
00886                 cr_utils_trace_info ("System possibly out of memory");
00887                 return CR_ERROR;
00888         }
00889 
00890         status = cr_om_parser_parse_buf (parser, a_buf, a_len,
00891                                          a_enc, a_result);
00892 
00893         if (parser) {
00894                 cr_om_parser_destroy (parser);
00895                 parser = NULL;
00896         }
00897 
00898         return status;
00899 }
00900 
00901 /**
00902  * cr_om_parser_parse_file:
00903  *@a_this: the current instance of the cssom parser.
00904  *@a_file_uri: the uri of the file. 
00905  *(only local file paths are suppported so far)
00906  *@a_enc: the encoding of the file.
00907  *@a_result: out parameter. A pointer 
00908  *the build css object model.
00909  *
00910  *Parses a css2 stylesheet contained
00911  *in a file.
00912  *
00913  * Returns CR_OK upon succesful completion, an error code otherwise.
00914  */
00915 enum CRStatus
00916 cr_om_parser_parse_file (CROMParser * a_this,
00917                          const guchar * a_file_uri,
00918                          enum CREncoding a_enc, CRStyleSheet ** a_result)
00919 {
00920         enum CRStatus status = CR_OK;
00921 
00922         g_return_val_if_fail (a_this && a_file_uri && a_result,
00923                               CR_BAD_PARAM_ERROR);
00924 
00925         if (!PRIVATE (a_this)->parser) {
00926                 PRIVATE (a_this)->parser = cr_parser_new_from_file
00927                         (a_file_uri, a_enc);
00928         }
00929 
00930         status = cr_parser_parse_file (PRIVATE (a_this)->parser,
00931                                        a_file_uri, a_enc);
00932 
00933         if (status == CR_OK) {
00934                 CRStyleSheet *result = NULL;
00935                 CRStyleSheet **resultptr = NULL;
00936                 CRDocHandler *sac_handler = NULL;
00937 
00938                 cr_parser_get_sac_handler (PRIVATE (a_this)->parser,
00939                                            &sac_handler);
00940                 g_return_val_if_fail (sac_handler, CR_ERROR);
00941                 resultptr = &result;
00942                 status = cr_doc_handler_get_result
00943                         (sac_handler, (gpointer *) resultptr);
00944                 g_return_val_if_fail (status == CR_OK, status);
00945                 if (result)
00946                         *a_result = result;
00947         }
00948 
00949         return status;
00950 }
00951 
00952 /**
00953  * cr_om_parser_simply_parse_file:
00954  *@a_file_path: the css2 local file path.
00955  *@a_enc: the file encoding.
00956  *@a_result: out parameter. The returned css stylesheet.
00957  *Must be freed by the caller using cr_stylesheet_destroy.
00958  *
00959  *The simpler method to parse a css2 file.
00960  *
00961  *Returns CR_OK upon successfull completion, an error code otherwise.
00962  *Note that this method uses cr_om_parser_parse_file() so both methods
00963  *have the same return values.
00964  */
00965 enum CRStatus
00966 cr_om_parser_simply_parse_file (const guchar * a_file_path,
00967                                 enum CREncoding a_enc,
00968                                 CRStyleSheet ** a_result)
00969 {
00970         CROMParser *parser = NULL;
00971         enum CRStatus status = CR_OK;
00972 
00973         parser = cr_om_parser_new (NULL);
00974         if (!parser) {
00975                 cr_utils_trace_info ("Could not allocate om parser");
00976                 cr_utils_trace_info ("System may be out of memory");
00977                 return CR_ERROR;
00978         }
00979 
00980         status = cr_om_parser_parse_file (parser, a_file_path,
00981                                           a_enc, a_result);
00982         if (parser) {
00983                 cr_om_parser_destroy (parser);
00984                 parser = NULL;
00985         }
00986 
00987         return status;
00988 }
00989 
00990 /**
00991  * cr_om_parser_parse_paths_to_cascade:
00992  *@a_this: the current instance of #CROMParser
00993  *@a_author_path: the path to the author stylesheet
00994  *@a_user_path: the path to the user stylesheet
00995  *@a_ua_path: the path to the User Agent stylesheet
00996  *@a_encoding: the encoding of the sheets.
00997  *@a_result: out parameter. The resulting cascade if the parsing
00998  *was okay
00999  *
01000  *Parses three sheets located by their paths and build a cascade
01001  *
01002  *Returns CR_OK upon successful completion, an error code otherwise
01003  */
01004 enum CRStatus
01005 cr_om_parser_parse_paths_to_cascade (CROMParser * a_this,
01006                                      const guchar * a_author_path,
01007                                      const guchar * a_user_path,
01008                                      const guchar * a_ua_path,
01009                                      enum CREncoding a_encoding,
01010                                      CRCascade ** a_result)
01011 {
01012         enum CRStatus status = CR_OK;
01013 
01014         /*0->author sheet, 1->user sheet, 2->UA sheet */
01015         CRStyleSheet *sheets[3];
01016         guchar *paths[3];
01017         CRCascade *result = NULL;
01018         gint i = 0;
01019 
01020         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
01021 
01022         memset (sheets, 0, sizeof (CRStyleSheet*) * 3);
01023         paths[0] = (guchar *) a_author_path;
01024         paths[1] = (guchar *) a_user_path;
01025         paths[2] = (guchar *) a_ua_path;
01026 
01027         for (i = 0; i < 3; i++) {
01028                 status = cr_om_parser_parse_file (a_this, paths[i],
01029                                                   a_encoding, &sheets[i]);
01030                 if (status != CR_OK) {
01031                         if (sheets[i]) {
01032                                 cr_stylesheet_unref (sheets[i]);
01033                                 sheets[i] = NULL;
01034                         }
01035                         continue;
01036                 }
01037         }
01038         result = cr_cascade_new (sheets[0], sheets[1], sheets[2]);
01039         if (!result) {
01040                 for (i = 0; i < 3; i++) {
01041                         cr_stylesheet_unref (sheets[i]);
01042                         sheets[i] = 0;
01043                 }
01044                 return CR_ERROR;
01045         }
01046         *a_result = result;
01047         return CR_OK;
01048 }
01049 
01050 /**
01051  * cr_om_parser_simply_parse_paths_to_cascade:
01052  *@a_author_path: the path to the author stylesheet
01053  *@a_user_path: the path to the user stylesheet
01054  *@a_ua_path: the path to the User Agent stylesheet
01055  *@a_encoding: the encoding of the sheets.
01056  *@a_result: out parameter. The resulting cascade if the parsing
01057  *was okay
01058  *
01059  *Parses three sheets located by their paths and build a cascade
01060  *
01061  *Returns CR_OK upon successful completion, an error code otherwise
01062  */
01063 enum CRStatus
01064 cr_om_parser_simply_parse_paths_to_cascade (const guchar * a_author_path,
01065                                             const guchar * a_user_path,
01066                                             const guchar * a_ua_path,
01067                                             enum CREncoding a_encoding,
01068                                             CRCascade ** a_result)
01069 {
01070         enum CRStatus status = CR_OK;
01071         CROMParser *parser = NULL;
01072 
01073         parser = cr_om_parser_new (NULL);
01074         if (!parser) {
01075                 cr_utils_trace_info ("could not allocated om parser");
01076                 cr_utils_trace_info ("System may be out of memory");
01077                 return CR_ERROR;
01078         }
01079         status = cr_om_parser_parse_paths_to_cascade (parser,
01080                                                       a_author_path,
01081                                                       a_user_path,
01082                                                       a_ua_path,
01083                                                       a_encoding, a_result);
01084         if (parser) {
01085                 cr_om_parser_destroy (parser);
01086                 parser = NULL;
01087         }
01088         return status;
01089 }
01090 
01091 /**
01092  * cr_om_parser_destroy:
01093  *@a_this: the current instance of #CROMParser.
01094  *
01095  *Destructor of the #CROMParser.
01096  */
01097 void
01098 cr_om_parser_destroy (CROMParser * a_this)
01099 {
01100         g_return_if_fail (a_this && PRIVATE (a_this));
01101 
01102         if (PRIVATE (a_this)->parser) {
01103                 cr_parser_destroy (PRIVATE (a_this)->parser);
01104                 PRIVATE (a_this)->parser = NULL;
01105         }
01106 
01107         if (PRIVATE (a_this)) {
01108                 g_free (PRIVATE (a_this));
01109                 PRIVATE (a_this) = NULL;
01110         }
01111 
01112         if (a_this) {
01113                 g_free (a_this);
01114                 a_this = NULL;
01115         }
01116 }