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