Code

Rename *Parsers to Readers
authorishmal <ishmal@users.sourceforge.net>
Thu, 1 May 2008 19:23:00 +0000 (19:23 +0000)
committerishmal <ishmal@users.sourceforge.net>
Thu, 1 May 2008 19:23:00 +0000 (19:23 +0000)
src/dom/cssparser.cpp [deleted file]
src/dom/cssparser.h [deleted file]
src/dom/cssreader.cpp [new file with mode: 0644]
src/dom/cssreader.h [new file with mode: 0644]
src/dom/svgparser.cpp [deleted file]
src/dom/svgparser.h [deleted file]
src/dom/svgreader.cpp [new file with mode: 0644]
src/dom/svgreader.h [new file with mode: 0644]

diff --git a/src/dom/cssparser.cpp b/src/dom/cssparser.cpp
deleted file mode 100644 (file)
index 422c02e..0000000
+++ /dev/null
@@ -1,1670 +0,0 @@
-/**
- * Phoebe DOM Implementation.
- *
- * This is a C++ approximation of the W3C DOM model, which follows
- * fairly closely the specifications in the various .idl files, copies of
- * which are provided for reference.  Most important is this one:
- *
- * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html
- *
- * Authors:
- *   Bob Jamison
- *
- * Copyright (C) 2005-2008 Bob Jamison
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include "cssparser.h"
-#include "ucd.h"
-
-#include <stdio.h>
-#include <stdarg.h>
-
-namespace org
-{
-namespace w3c
-{
-namespace dom
-{
-namespace css
-{
-
-//#########################################################################
-//# M E S S A G E S
-//#########################################################################
-
-/**
- * Get the column and row number of the given character position
- */
-void CssParser::getColumnAndRow(int p, int &colResult, int &rowResult, int &lastNL)
-{
-    int col    = 1;
-    int row    = 1;
-    int lastnl = 0;
-
-    for (int i=0 ; i<p ; i++)
-        {
-        XMLCh ch = parsebuf[i];
-        if (ch == '\n')
-            {
-            lastnl = i;
-            row++;
-            col=0;
-            }
-        else
-            col++;
-        }
-
-    colResult  = col;
-    rowResult  = row;
-    lastNL     = lastnl;
-}
-
-/**
- *
- */
-void CssParser::error(char const *fmt, ...)
-{
-    int lineNr;
-    int colNr;
-    int lastNL;
-    getColumnAndRow(lastPosition, colNr, lineNr, lastNL);
-
-    va_list args;
-    fprintf(stderr, "CssParser:error at %d, line %d, column %d:",
-                        lastPosition, lineNr, colNr);
-    va_start(args, fmt);
-    vfprintf(stderr, fmt, args);
-    va_end(args) ;
-    fprintf(stderr, "\n");
-
-    /*
-    int lineLen = lastPosition - lastNL;
-    printf("lineLen:%d lastNL:%d\n", lineLen, lastNL);
-    for (int i=lastNL+1 ; i<lastPosition ; i++)
-        fprintf(stderr, "%c", parsebuf[i]);
-    fprintf(stderr, "\n");
-    for (int i=0 ; i<lineLen-1 ; i++)
-        fprintf(stderr, " ");
-    fprintf(stderr, "^\n");
-    */
-    for (int i=0 ; i<lastPosition ; i++)
-        fprintf(stderr, "%c", parsebuf[i]);
-    fprintf(stderr, "\n");
-}
-
-
-
-//#########################################################################
-//# P A R S I N G
-//#########################################################################
-
-/**
- *  Get the character at the position and record the fact
- */
-XMLCh CssParser::get(int p)
-{
-    if (p >= parselen)
-        return 0;
-    XMLCh ch = parsebuf[p];
-    //printf("%c", ch);
-    lastPosition = p;
-    return ch;
-}
-
-
-
-/**
- *  Test if the given substring exists at the given position
- *  in parsebuf.  Use get() in case of out-of-bounds
- */
-bool CssParser::match(int pos, const char *str)
-{
-    while (*str)
-       {
-       if (get(pos++) != (XMLCh) *str++)
-           return false;
-       }
-   return true;
-}
-
-/**
- *
- */
-int CssParser::skipwhite(int p)
-{
-  while (p < parselen)
-    {
-    //# XML COMMENT
-    if (match(p, "<!--"))
-        {
-        p+=4;
-        bool done=false;
-        while (p<parselen)
-            {
-            if (match(p, "-->"))
-                {
-                p+=3;
-                done=true;
-                break;
-                }
-            p++;
-            }
-        lastPosition = p;
-        if (!done)
-            {
-            error("unterminated <!-- .. --> comment");
-            return -1;
-            }
-        }
-    //# C comment
-    else if (match(p, "/*"))
-        {
-        p+=2;
-        bool done=false;
-        while (p<parselen)
-            {
-            if (match(p, "*/"))
-                {
-                p+=2;
-                done=true;
-                break;
-                }
-            p++;
-            }
-        lastPosition = p;
-        if (!done)
-            {
-            error("unterminated /* .. */ comment");
-            return -1;
-            }
-        }
-    else if (!uni_is_space(get(p)))
-        break;
-    else
-        p++;
-    }
-  lastPosition = p;
-  return p;
-}
-
-/**
- * get a word from the buffer
- */
-int CssParser::getWord(int p, DOMString &result)
-{
-    XMLCh ch = get(p);
-    if (!uni_is_letter(ch))
-        return p;
-    DOMString str;
-    str.push_back(ch);
-    p++;
-
-    while (p < parselen)
-        {
-        ch = get(p);
-        if (uni_is_letter_or_digit(ch) || ch=='-' || ch=='_')
-            {
-            str.push_back(ch);
-            p++;
-            }
-        else if (ch == '\\')
-            {
-            p+=2;
-            }
-        else
-            break;
-        }
-    result = str;
-    return p;
-}
-
-
-/**
- * get a word from the buffer
- */
-int CssParser::getNumber(int p0, double &result)
-{
-    int p=p0;
-    DOMString str;
-    while (p < parselen)
-        {
-        XMLCh ch = get(p);
-        if (ch<'0' || ch>'9')
-            break;
-        str.push_back(ch);
-        p++;
-        }
-    if (get(p) == '.' && get(p+1)>='0' && get(p+1)<='9')
-        {
-        p++;
-        str.push_back('.');
-        while (p < parselen)
-            {
-            XMLCh ch = get(p);
-            if (ch<'0' || ch>'9')
-                break;
-            str.push_back(ch);
-            p++;
-            }
-        }
-    if (p>p0)
-        {
-        char *start = (char *)str.c_str();
-        char *end   = NULL;
-        double val = strtod(start, &end);
-        if (end > start)
-            {
-            result = val;
-            return p;
-            }
-        }
-
-    //not a number
-    return p0;
-}
-
-
-
-/**
- * Assume that we are starting on a quote.  Ends on the char
- * after the final '"'
- */
-int CssParser::getQuoted(int p0, DOMString &result)
-{
-
-    int p = p0;
-
-    XMLCh quoteChar = get(p);
-    if (quoteChar != '"' && quoteChar != '\'')
-        return p0;
-
-    p++;
-
-    DOMString buf;
-
-    bool done = false;
-    while (p<parselen )
-        {
-        XMLCh ch = get(p);
-        if (ch == quoteChar)
-            {
-            done = true;
-            p++;
-            break;
-            }
-        else
-            {
-            buf.push_back(ch);
-            }
-        p++;
-        }
-
-    if (!done)
-        {
-        error("unterminated quoted string");
-        return -1;
-        }
-
-    result.append(buf);
-
-    return p;
-}
-
-/**
- * Not in api.  replaces URI return by lexer
- */
-int CssParser::getUri(int p0, DOMString &str)
-{
-    int p = p0;
-    if (!match(p, "url("))
-        return p0;
-    p+=4;
-    p = skipwhite(p);
-    DOMString buf;
-    XMLCh ch;
-    while (p < parselen)
-        {
-        ch = get(p);
-        if (isspace(ch) || ch==')')
-            break;
-        buf.push_back(ch);
-        p++;
-        }
-    p = skipwhite(p);
-    ch = get(p);
-    if (ch != ')')
-        {
-        error("no closing ')' on url spec");
-        return -1;
-        }
-    p++;
-    str = buf;
-    return p;
-}
-
-/**
- * Skip to the end of the block
- */
-int CssParser::skipBlock(int p0)
-{
-    int p = p0;
-    while (p < parselen)
-        {
-        XMLCh ch = get(p);
-        if (ch == '}')
-            {
-            p++;
-            break;
-            }
-        else
-            {
-            p++;
-            }
-        }
-    return p;
-}
-
-//#########################################################################
-//# P R O D U C T I O N S
-//#########################################################################
-
-/**
- * stylesheet
- *   : [ CHARSET_SYM S* STRING S* ';' ]?
- *     [S|CDO|CDC]* [ import [S|CDO|CDC]* ]*
- *     [ [ ruleset | media | page ] [S|CDO|CDC]* ]*
- *   ;
- */
-int CssParser::getStyleSheet(int p0)
-{
-    int p = p0;
-    int p2 = p;
-    XMLCh ch;
-
-    //# CHARSET   0 or 1
-    if (match(p, "@charset"))
-        {
-        p+=8;
-        p = skipwhite(p);
-        DOMString str;
-        p2 = getQuoted(p, str);
-        if (p2<=p)
-            {
-            error("quoted string required after @charset");
-            return -1;
-            }
-        p = skipwhite(p2);
-        ch = get(p);
-        if (ch !=';')
-            {
-            error("';' required after @charset declaration");
-            return -1;
-            }
-        p++;
-        p = skipwhite(p);
-        }
-
-    //# IMPORT  0 to many
-    while (true)
-        {
-        p2 = getImport(p);
-        if (p2<0)
-            {
-            return -1;
-            }
-        if (p2<=p)
-            break;
-        p = p2;
-        }
-
-    //# RULESET | MEDIA | PAGE  0 to many
-    while (true)
-        {
-        //Ruleset
-        p2 = getRuleSet(p);
-        if (p2<0)
-            {
-            return -1;
-            }
-        if (p2>p)
-            {
-            p = p2;
-            continue;
-            }
-
-        //Media
-        p2 = getMedia(p);
-        if (p2<0)
-            {
-            return -1;
-            }
-        if (p2>p)
-            {
-            p = p2;
-            continue;
-            }
-
-        //Page
-        p2 = getPage(p);
-        if (p2<0)
-            {
-            return -1;
-            }
-        if (p2>p)
-            {
-            p = p2;
-            continue;
-            }
-
-        //none of the above
-        break;
-        }
-
-    return p;
-}
-
-/**
- * import
- *   : IMPORT_SYM S*
- *     [STRING|URI] S* [ medium [ COMMA S* medium]* ]? ';' S*
- *   ;
- */
-int CssParser::getImport(int p0)
-{
-    int p = p0;
-    if (!match(p, "@import"))
-        return p0;
-    p+=7;
-    p = skipwhite(p);
-
-    //# STRING | URI
-    DOMString str;
-    int p2 = getQuoted(p, str);
-    if (p2<0)
-        {
-        return -1;
-        }
-    if (p2<=p)
-        {
-        p2 = getUri(p, str);
-        if (p2<0)
-            {
-            return -1;
-            }
-        if (p2<=p)
-            {
-            error("quoted string or URI required after @import");
-            return -1;
-            }
-        }
-    p = p2;
-    p2 = getMedium(p);
-    if (p2<0)
-        return -1;
-
-    p = p2;
-    p = skipwhite(p);
-    XMLCh ch = get(p);
-    if (ch != ';')
-        {
-        error("@import must be terminated with ';'");
-        return -1;
-        }
-    p++;
-    return p;
-}
-
-/**
- * media
- *   : MEDIA_SYM S* medium [ COMMA S* medium ]* LBRACE S* ruleset* '}' S*
- *   ;
- */
-int CssParser::getMedia(int p0)
-{
-    int p = p0;
-    XMLCh ch;
-    if (!match(p, "@media"))
-        return p0;
-    p+=6;
-    p = skipwhite(p);
-
-    //# MEDIUM LIST
-    int p2 = getMedium(p);
-    if (p2<0)
-        return -1;
-    if (p2<=p)
-        {
-        error("@media must be followed by medium");
-        return -1;
-        }
-    p = p2;
-    while (true)
-        {
-        ch = get(p);
-        if (ch != ',')
-            break;
-        p2 = getMedium(p);
-        if (p2<0)
-            return -1;
-        if (p2<=p)
-            {
-            error("',' in medium list must be followed by medium");
-            return -1;
-            }
-        p = p2;
-        }
-
-    p = skipwhite(p);
-    ch = get(p);
-    if (ch!='{')
-        {
-        error("@media requires '{' for ruleset");
-        return -1;
-        }
-    p++;
-    p2 = getRuleSet(p);
-    if (p2<0)
-        return -1;
-    if (p2<=p)
-        {
-        error("@media requires ruleset after '{'");
-        return -1;
-        }
-    p = p2;
-    ch = get(p);
-    if (ch != '}')
-        {
-        error("@media requires '}' after ruleset");
-        return -1;
-        }
-    p++;
-    return p0;
-}
-
-/**
- * medium
- *   : IDENT S*
- *   ;
- */
-int CssParser::getMedium(int p0)
-{
-    int p = p0;
-    p = skipwhite(p);
-
-    DOMString ident;
-    int p2 = getWord(p, ident);
-    if (p2<0)
-        return -1;
-    if (p2<=p)
-        return p0;
-    p = p2;
-
-    return p;
-}
-
-/**
- * page
- *   : PAGE_SYM S* pseudo_page? S*
- *     LBRACE S* declaration [ ';' S* declaration ]* '}' S*
- *   ;
- */
-int CssParser::getPage(int p0)
-{
-    int p = p0;
-
-    //# @PAGE
-    p = skipwhite(p);
-    if (!match(p, "@page"))
-        return p0;
-    p+= 5;
-
-    //#PSEUDO PAGE 0 or 1
-    p = skipwhite(p);
-    int p2 = getPseudoPage(p);
-    if (p2<0)
-        return -1;
-    if (p2>p)
-        {
-        p = p2;
-        }
-
-    //# {
-    p=skipwhite(p);
-    XMLCh ch = get(p);
-    if (p != '{')
-        {
-        error("@page requires '{' before declarations");
-        }
-    p++;
-
-    //# DECLARATION LIST
-    p = skipwhite(p);
-    CSSStyleDeclaration declarationList;
-    p2 = getDeclaration(p, declarationList);
-    if (p2<0)
-        return -1;
-    if (p2<=p)
-        {
-        error("@page requires declaration(s) after '{'");
-        return -1;
-        }
-    while (true)
-        {
-        p = skipwhite(p2);
-        ch = get(p);
-        if (ch != ';')
-            break;
-        p++;
-        p = skipwhite(p);
-        p2 = getDeclaration(p, declarationList);
-        if (p2<0)
-            return -1;
-        if (p2<= p)
-            {
-            error("@page requires declaration after ';'");
-            return -1;
-            }
-        }
-
-    //# }
-    p=skipwhite(p);
-    ch = get(p);
-    if (p != '}')
-        {
-        error("@page requires '}' after declarations");
-        }
-    p++;
-
-    return p;
-}
-
-/**
- * pseudo_page
- *   : ':' IDENT
- *   ;
- */
-int CssParser::getPseudoPage(int p0)
-{
-    int p = p0;
-    if (!match(p, ":"))
-        return p0;
-    p++;
-    DOMString str;
-    int p2 = getWord(p, str);
-    if (p2<0)
-        return -1;
-    if (p2<=p)
-        {
-        error("pseudo-page requires identifier after ':'");
-        return -1;
-        }
-    p = p2;
-    return p;
-}
-
-/**
- * ruleset
- *   : selector [ COMMA S* selector ]*
- *     LBRACE S* declaration [ ';' S* declaration ]* '}' S*
- *   ;
- */
-int CssParser::getRuleSet(int p0)
-{
-    int p = p0;
-    XMLCh ch;
-
-    //## SELECTOR
-    p = skipwhite(p);
-    int p2 = getSelector(p);
-    if (p2<0)
-        return -1;
-    if (p2<=p)  //no selector
-        {
-        if (get(p) != '{')//check for selector-less rule
-            return p0;//not me
-        }
-    p = p2;
-    while (true)
-        {
-        p = skipwhite(p);
-        ch = get(p);
-        if (ch != ',')
-            break;
-        p++;
-        p = skipwhite(p);
-        int p2 = getSelector(p);
-        if (p2<0)
-            return -1;
-        if (p2<=p)
-            {
-            error("selector required after ',' in list");
-            return -1;
-            }
-        p = p2;
-        }
-
-    //## {
-    ch = get(p);
-    if (ch != '{')
-        {
-        error("'{' required before declarations of ruleset");
-        return -1;
-        }
-    p++;
-
-    //## DECLARATIONS ( 0 to many )
-    CSSStyleDeclaration declarationList;
-
-    p = skipwhite(p);
-    p2 = getDeclaration(p, declarationList);
-    if (p2<0)
-        return -1;
-    if (p2>p)
-        {
-        p = p2;
-        while (true)
-            {
-            p = skipwhite(p);
-            ch = get(p);
-            if (ch != ';')
-                break;
-            p++;
-            p = skipwhite(p);
-            p2 = getDeclaration(p, declarationList);
-            if (p2<0)
-                return -1;
-            if (p2<=p)
-                {
-                //apparently this is ok
-                //error("declaration required after ';' in ruleset");
-                //return -1;
-                break;
-                }
-            p = p2;
-            }
-        }
-    //## }
-    ch = get(p);
-    if (ch != '}')
-        {
-        error("ruleset requires closing '}'");
-        return -1;
-        }
-    p++;
-    p = skipwhite(p);
-
-    return p;
-}
-
-/**
- * selector
- *   : simple_selector [ combinator simple_selector ]*
- *   ;
- */
-int CssParser::getSelector(int p0)
-{
-    int p = p0;
-
-    //## SIMPLE SELECTOR
-    p = skipwhite(p);
-    int p2 = getSimpleSelector(p);
-    if (p2<0)
-        return -1;
-    if (p2<=p)
-        return p0; //not me
-    p = p2;
-
-    //## COMBINATORS + MORE SELECTORS
-    while (true)
-        {
-        XMLCh ch = get(p);
-        bool wasSpace = isspace(ch);
-        p = skipwhite(p);
-        ch = get(p);
-        //# Combinators
-        //easier to do here than have a getCombinator()
-        int visibleCombinator = false;
-        if (ch == '+')
-            {
-            visibleCombinator = true;
-            p++;
-            }
-        else if (ch == '>')
-            {
-            visibleCombinator = true;
-            p++;
-            }
-        else if (wasSpace)
-            {
-            }
-        else
-            {
-            break;
-            }
-        p = skipwhite(p);
-        p2 = getSimpleSelector(p);
-        if (p2<0)
-            return -1;
-        if (p2<=p)
-            {
-            if (visibleCombinator)
-                {
-                error("need simple selector after combinator");
-                return -1;
-                }
-            else
-                {
-                break;
-                }
-            }
-        p = p2;
-        }
-    return p;
-}
-
-/**
- * simple_selector
- *   : element_name [ HASH | class | attrib | pseudo ]*
- *   | [ HASH | class | attrib | pseudo ]+
- *   ;
- */
-int CssParser::getSimpleSelector(int p0)
-{
-    int p = p0;
-    int p2;
-
-    DOMString str;
-
-    p = skipwhite(p);
-
-    int selectorItems = 0;
-
-    XMLCh ch = get(p);
-
-    //######################
-    //# Note: do NOT skipwhite between items.  Only within the
-    //# pseudo function and attrib below
-    //######################
-
-    //#Element name 0 or 1
-    if (uni_is_letter(ch))
-        {
-        p2 = getWord(p, str);
-        if (p2<0)
-            return -1;
-        if (p2<=p)
-            {
-            error("null element name");
-            return -1;
-            }
-        selectorItems++;
-        p = p2;
-        }
-    else if (ch == '*')
-        {
-        str = "*";
-        p++;
-        selectorItems++;
-        }
-
-
-
-    //## HASH, CLASS, ATTRIB, PSEUDO  (0 to many with elem name, 1 to many without)
-    while (true)
-        {
-        XMLCh ch = get(p);
-
-        //# HASH
-        if (ch == '#')
-            {
-            p++;
-            p2 = getWord(p, str);
-            if (p2<0)
-                return -1;
-            if (p2<=p)
-                {
-                error("no name for hash");
-                return -1;
-                }
-            p = p2;
-            selectorItems++;
-            }
-
-        //# CLASS
-        else if (ch == '.')
-            {
-            p++;
-            p2 = getWord(p, str);
-            if (p2<0)
-                return -1;
-            if (p2<=p)
-                {
-                error("no name for class");
-                return -1;
-                }
-            p = p2;
-            selectorItems++;
-            }
-
-        //# ATTRIB
-        else if (ch == '[')
-            {
-            p++;
-            p = skipwhite(p);
-            p2 = getWord(p, str);
-            if (p2<0)
-                return -1;
-            if (p2<=p)
-                {
-                error("no name for class");
-                return -1;
-                }
-            p = skipwhite(p2);
-            bool getRHS=false;
-            if (match(p, "="))
-                {
-                p++;
-                getRHS=true;
-                }
-            else if (match(p, "~="))
-                {
-                p+=2;
-                getRHS=true;
-                }
-            else if (match(p, "|="))
-                {
-                p+=2;
-                getRHS=true;
-                }
-            if (getRHS)
-                {
-                p = skipwhite(p);
-                ch = get(p);
-                if (uni_is_letter(ch))
-                    {
-                    p2 = getWord(p, str);
-                    if (p2<0)
-                        return -1;
-                    if (p2<=p)
-                        {
-                        error("null ident on rhs of attrib");
-                        return -1;
-                        }
-                    p = p2;
-                    }
-                else if (ch == '\'' || ch =='"')
-                    {
-                    p2 = getQuoted(p, str);
-                    if (p2<0)
-                        return -1;
-                    if (p2<=p)
-                        {
-                        error("null literal string on rhs of attrib");
-                        return -1;
-                        }
-                    p = p2;
-                    }
-                }//getRHS
-            p = skipwhite(p);
-            ch = get(p);
-            if (ch != ']')
-                {
-                error("attrib needs closing ']'");
-                //return -1;
-                p = skipBlock(p);
-                return p;
-                }
-            p++;
-            selectorItems++;
-            }
-
-        //# PSEUDO
-        else if (ch == ':')
-            {
-            p++;
-            p2 = getWord(p, str);
-            if (p2<0)
-                return -1;
-            if (p2<=p)
-                {
-                error("no name for pseudo");
-                return -1;
-                }
-            p = p2;
-            selectorItems++;
-            ch = get(p);
-            if (ch == '(')
-                {
-                p++;
-                p = skipwhite(p);
-                ch = get(p);
-                if (uni_is_letter(ch))
-                    {
-                    p2 = getWord(p, str);
-                    if (p2<0)
-                        return -1;
-                    if (p2<=p)
-                        {
-                        error("null function parameter in pseudo");
-                        return -1;
-                        }
-                    p = skipwhite(p2);
-                    ch = get(p);
-                    }
-                if (ch != ')')
-                    {
-                    error("function in pseudo needs ')'");
-                    return -1;
-                    }
-                p++;
-                }// ch==(   -function-
-            }//pseudo
-
-        //# none of the above
-        else
-            {
-            break;
-            }
-
-        }//while
-
-
-    if (selectorItems > 0)
-        return p;
-    return p0;
-}
-
-/**
- * declaration
- *   : property ':' S* expr prio?
- *   | {empty}
- *   ;
- */
-int CssParser::getDeclaration(int p0, CSSStyleDeclaration &declarationList)
-{
-    int p = p0;
-
-    //## PROPERTY
-    p = skipwhite(p);
-    XMLCh ch = get(p);
-    if (!uni_is_letter(ch))
-        return p0; //not me
-    DOMString propName;
-    int p2 = getWord(p, propName);
-    if (p2<0)
-        return -1;
-
-    //## ':'
-    p = skipwhite(p2);
-    ch = get(p);
-    if (ch != ':')
-        {
-        error("declaration requires ':' between name and value");
-        return -1;
-        }
-    p++;
-
-    //## EXPR
-    p = skipwhite(p);
-    p2 = getExpr(p);
-    if (p2<0)
-        return -1;
-    if (p2<=p)
-        {
-        error("declaration requires value after ':'");
-        return -1;
-        }
-    DOMString propVal;
-    for (int i=p ; i<p2 ; i++)  //get our substring
-        propVal.push_back(get(i));
-    printf("propVal:%s\n", propVal.c_str());
-    p = p2;
-
-    //## PRIO (optional)
-    p = skipwhite(p);
-    DOMString prio;
-    p2 = getPrio(p, prio);
-    if (p2<0)
-        return -1;
-    if (p2>p)
-        {
-        //do something
-        p = p2;
-        }
-
-    return p;
-}
-
-/**
- * prio
- *   : IMPORTANT_SYM S*
- *   ;
- */
-int CssParser::getPrio(int p0, DOMString &val)
-{
-    int p = p0;
-
-    //## '!"
-    p = skipwhite(p);
-    XMLCh ch = get(p);
-    if (ch != '!')
-        return p0;
-    p++;
-
-    //## "important"
-    p = skipwhite(p);
-    if (!match(p, "important"))
-        {
-        error("priority symbol is 'important'");
-        return -1;
-        }
-    p += 9;
-    val = "important";
-    return p;
-}
-
-/**
- * expr
- *   : term [ operator term ]*
- *   ;
- */
-int CssParser::getExpr(int p0)
-{
-    int p = p0;
-
-    //## TERM
-    p = skipwhite(p);
-    int p2 = getTerm(p);
-    if (p2<0)
-        return -1;
-    if (p2<=p)
-        return p0;  //not me
-    p = p2;
-    while (p < parselen)
-        {
-        p = skipwhite(p);
-        //#Operator.  do this instead of getOperator()
-        XMLCh ch = get(p);
-        int visibleTerm = false;
-        if (ch == '/')
-            {
-            visibleTerm = true;
-            p++;
-            }
-        else if (ch == ',')
-            {
-            visibleTerm = true;
-            p++;
-            }
-        else
-            {
-            //just space.  this is allowable between terms,
-            // so we still need to check for another term
-            }
-        p = skipwhite(p);
-        p2 = getTerm(p);
-        if (p2<0)
-            return -1;
-        if (p2<=p)
-            {
-            if (visibleTerm)
-                {
-                error("expression requires term after operator");
-                return -1;
-                }
-            else
-                {
-                break;
-                }
-            }
-        p = p2;
-        }
-
-    return p;
-}
-
-/**
- * term
- *   : unary_operator?
- *     [ NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | ANGLE S* |
- *       TIME S* | FREQ S* | function ]
- *   | STRING S* | IDENT S* | URI S* | hexcolor
- *   ;
- */
-int CssParser::getTerm(int p0)
-{
-    int p = p0;
-    p = skipwhite(p);
-    int unitType = CSSPrimitiveValue::CSS_UNKNOWN;
-    //# Unary operator
-    XMLCh ch = get(p);
-    bool hasUnary = false;
-    if (ch == '-')
-        {
-        p++;
-        hasUnary = true;
-        }
-    else if (ch == '+')
-        {
-        p++;
-        hasUnary = true;
-        }
-    //# NUMERIC
-    double numVal;
-    int p2 = getNumber(p, numVal);
-    if (p2<0)
-        return -1;
-    if (p2>p)
-        {
-        p = p2;
-        if (match(p, "%"))
-            {
-            unitType = CSSPrimitiveValue::CSS_PERCENTAGE;
-            p++;
-            }
-        else if (match(p, "em"))
-            {
-            unitType = CSSPrimitiveValue::CSS_EMS;
-            p+=2;
-            }
-        else if (match(p, "ex"))
-            {
-            unitType = CSSPrimitiveValue::CSS_EXS;
-            p+=2;
-            }
-        else if (match(p, "px"))
-            {
-            unitType = CSSPrimitiveValue::CSS_PX;
-            p+=2;
-            }
-        else if (match(p, "cm"))
-            {
-            unitType = CSSPrimitiveValue::CSS_CM;
-            p+=2;
-            }
-        else if (match(p, "mm"))
-            {
-            unitType = CSSPrimitiveValue::CSS_MM;
-            p+=2;
-            }
-        else if (match(p, "in"))
-            {
-            unitType = CSSPrimitiveValue::CSS_IN;
-            p+=2;
-            }
-        else if (match(p, "pt"))
-            {
-            unitType = CSSPrimitiveValue::CSS_PT;
-            p+=2;
-            }
-        else if (match(p, "pc"))
-            {
-            unitType = CSSPrimitiveValue::CSS_PC;
-            p+=2;
-            }
-        else if (match(p, "deg"))
-            {
-            unitType = CSSPrimitiveValue::CSS_DEG;
-            p+=3;
-            }
-        else if (match(p, "rad"))
-            {
-            unitType = CSSPrimitiveValue::CSS_RAD;
-            p+=3;
-            }
-        else if (match(p, "grad"))
-            {
-            unitType = CSSPrimitiveValue::CSS_GRAD;
-            p+=4;
-            }
-        else if (match(p, "ms"))
-            {
-            unitType = CSSPrimitiveValue::CSS_MS;
-            p+=2;
-            }
-        else if (match(p, "s"))
-            {
-            unitType = CSSPrimitiveValue::CSS_S;
-            p+=1;
-            }
-        else if (match(p, "Hz"))
-            {
-            unitType = CSSPrimitiveValue::CSS_HZ;
-            p+=2;
-            }
-        else if (match(p, "kHz"))
-            {
-            unitType = CSSPrimitiveValue::CSS_KHZ;
-            p+=2;
-            }
-        else if (uni_is_letter(get(p)))//some other string
-            {
-            DOMString suffix;
-            p2 = getWord(p, suffix);
-            if (p2<0)
-                return -1;
-            unitType = CSSPrimitiveValue::CSS_DIMENSION;
-            p = p2;
-            }
-        else //plain number
-            {
-            unitType = CSSPrimitiveValue::CSS_NUMBER;
-            }
-        return p;
-        }
-
-    DOMString str;
-
-    //## URI --do before function, as syntax is similar
-    p2 = getUri(p, str);
-    if (p2<0)
-        return -1;
-    if (p2>p)
-        {
-        if (hasUnary)
-            {
-            error("+ or - not allowed on URI");
-            return -1;
-            }
-        p = p2;
-        unitType = CSSPrimitiveValue::CSS_URI;
-        return p;
-        }
-
-    //## FUNCTION
-    p2 = getFunction(p);
-    if (p2<0)
-        return -1;
-    if (p2>p)
-        {
-        p = p2;
-        return p;
-        }
-
-    //## STRING
-    ch = get(p);
-    if (ch == '"' || ch == '\'')
-        {
-        p2 = getQuoted(p, str);
-        if (p2<0)
-            return -1;
-        if (p2>p)
-            {
-            if (hasUnary)
-                {
-                error("+ or - not allowed on a string");
-                return -1;
-                }
-            p = p2;
-            unitType = CSSPrimitiveValue::CSS_STRING;
-            return p;
-            }
-        }
-
-    //## IDENT
-    ch = get(p);
-    if (uni_is_letter(ch))
-        {
-        p2 = getWord(p, str);
-        if (p2<0)
-            return -1;
-        if (p2>p)
-            {
-            if (hasUnary)
-                {
-                error("+ or - not allowed on an identifier");
-                return -1;
-                }
-            p = p2;
-            unitType = CSSPrimitiveValue::CSS_IDENT;
-            return p;
-            }
-        }
-
-
-    //## HEXCOLOR
-    p2 = getHexColor(p);
-    if (p2<0)
-        return -1;
-    if (p2>p)
-        {
-        if (hasUnary)
-            {
-            error("+ or - not allowed on hex color");
-            return -1;
-            }
-        p = p2;
-        unitType = CSSPrimitiveValue::CSS_RGBCOLOR;
-        return p;
-        }
-
-
-    return p0;
-}
-
-/**
- * function
- *   : FUNCTION S* expr ')' S*
- *   ;
- */
-int CssParser::getFunction(int p0)
-{
-    int p = p0;
-
-    //## IDENT + (   (both)
-    DOMString name;
-    p = skipwhite(p);
-    int p2 = getWord(p, name);
-    if (p2<0)
-        return -1;
-    if (p2<=p)
-        return p0; //not me
-    if (name == "uri" || name=="url")
-        return p0; //not me
-    p = skipwhite(p2);
-    XMLCh ch = get(p);
-    if (ch != '(')
-        return p0; //still not me
-    p++;
-
-    //## EXPR
-    p = skipwhite(p);
-    p2 = getExpr(p);
-    if (p2<0)
-        return -1;
-    if (p2<=p)
-        {
-        error("function requires expression");
-        return -1;
-        }
-    p = p2;
-
-    //## ')'
-    p = skipwhite(p);
-    ch = get(p);
-    if (ch != ')')
-        {
-        error("function requires closing ')'");
-        return -1;
-        }
-    p++;
-    p = skipwhite(p);
-
-    return p;
-}
-
-/**
- * There is a constraint on the color that it must
- * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F])
- * after the "#"; e.g., "#000" is OK, but "#abcd" is not.
- * hexcolor
- *   : HASH S*
- *   ;
- */
-int CssParser::getHexColor(int p0)
-{
-    int p = p0;
-
-    //## '#'
-    p = skipwhite(p);
-    if (!match(p, "#"))
-        return p0;
-    p++;
-
-    //## HEX
-    DOMString hex;
-    long hexVal = 0;
-    while (p < parselen)
-        {
-        XMLCh b = get(p);
-        if (b>='0' && b<='9')
-            {
-            hexVal = (hexVal << 4) + (b - '0');
-            hex.push_back(b);
-            p++;
-            }
-        else if (b>='a' && b<='f')
-            {
-            hexVal = (hexVal << 4) + (b - 'a' + 10);
-            hex.push_back(b);
-            p++;
-            }
-        else if (b>='A' && b<='F')
-            {
-            hexVal = (hexVal << 4) + (b - 'A' + 10);
-            hex.push_back(b);
-            p++;
-            }
-        else
-            {
-            break;
-            }
-        }
-
-    if (hex.size() != 3 && hex.size() != 6)
-        {
-        error("exactly 3 or 6 hex digits are required after '#'");
-        return -1;
-        }
-
-    return p;
-}
-
-
-
-/**
- *
- */
-bool CssParser::parse(const DOMString &str)
-{
-    /*
-    int len = str.size();
-    for (int i=0 ; i<len ; i++)
-        {
-        XMLCh ch = str[i];
-        if (ch == '\\' && i<(len-1)) //escape!
-            {
-            i++;
-            }
-        else
-            parsebuf.push_back(ch);
-        }
-    */
-    parsebuf = str;
-
-    parselen = parsebuf.size();
-    //printf("==============================\n%s\n========================\n", str.c_str());
-
-    lastPosition = 0;
-
-    int p = getStyleSheet(0);
-    if (p < parselen)
-        {
-        error("Not everything parsed");
-        return false;
-        }
-
-    return true;
-}
-
-
-/**
- *
- */
-bool CssParser::parseFile(const DOMString &fileName)
-{
-    DOMString tmp = fileName;
-    char *fname = (char *)tmp.c_str();
-    FILE *f = fopen(fname, "r");
-    if (!f)
-        {
-        printf("Could not open %s for reading\n", fname);
-        return false;
-        }
-
-    DOMString str;
-    while (!feof(f))
-        {
-        int ch = fgetc(f);
-        if (ch<0)
-            break;
-        str.push_back((XMLCh)ch);
-        }
-    fclose(f);
-
-    bool ret = parse(str);
-
-    return ret;
-}
-
-
-
-
-
-
-
-} // namespace css
-} // namespace dom
-} // namespace w3c
-} // namespace org
-
-
-#ifdef TEST
-
-int main(int argc, char **argv)
-{
-    org::w3c::dom::css::CssParser parser;
-    char *fileName;
-    fileName = "001.css";
-    //fileName = "acid.css";
-    //fileName = "base.css";
-    //fileName = "inkscape.css";
-    //fileName = "meyerweb.css";
-    if (!parser.parseFile(fileName))
-        {
-        printf("Test failed\n");
-        return 1;
-        }
-    return 0;
-}
-
-#endif /* TEST */
-
-//#########################################################################
-//# E N D    O F    F I L E
-//#########################################################################
-
diff --git a/src/dom/cssparser.h b/src/dom/cssparser.h
deleted file mode 100644 (file)
index ca137cb..0000000
+++ /dev/null
@@ -1,290 +0,0 @@
-#ifndef __CSSPARSER_H__
-#define __CSSPARSER_H__
-/**
- * Phoebe DOM Implementation.
- *
- * This is a C++ approximation of the W3C DOM model, which follows
- * fairly closely the specifications in the various .idl files, copies of
- * which are provided for reference.  Most important is this one:
- *
- * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html
- *
- * Authors:
- *   Bob Jamison
- *
- * Copyright (C) 2005-2008 Bob Jamison
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-
-#include "dom.h"
-
-#include "css.h"
-
-namespace org
-{
-namespace w3c
-{
-namespace dom
-{
-namespace css
-{
-
-class CssParser
-{
-
-public:
-
-    /**
-     *
-     */
-    CssParser()
-        {}
-
-    /**
-     *
-     */
-    virtual ~CssParser()
-        {}
-
-    /**
-     *
-     */
-    virtual bool parse(const DOMString &str);
-
-    /**
-     *
-     */
-    virtual bool parseFile(const DOMString &str);
-
-
-private:
-
-    DOMString parsebuf;
-    long parselen;
-    CSSStyleSheet stylesheet;
-
-
-    /**
-     *
-     */
-    void error(char const *fmt, ...)
-    #ifdef G_GNUC_PRINTF
-    G_GNUC_PRINTF(2, 3)
-    #endif
-    ;
-
-    /**
-     * Get the character at the given location in the buffer.
-     *  Return 0 if out-of-bounds
-     */
-    XMLCh get(int index);
-
-
-    /**
-     *  Test if the given substring exists at the given position
-     *  in parsebuf.  Use get() in case of out-of-bounds
-     */
-    bool match(int pos, const char *str);
-
-    /**
-     * Skip over whitespace
-     * Return new position
-     */
-    int skipwhite(int index);
-
-    /**
-     * Get the word at the current position.  Return the new
-     * position if successful, the current position if no word,
-     * -1 if error.
-     */
-    int getWord(int index, DOMString &str);
-
-
-    /**
-     * Get a number at the current position
-     * Return the new position if a proper number, else the original pos
-     */
-    int getNumber(int index, double &result);
-
-    /**
-     * Assume that we are starting on a quote.  Ends on the char
-     * after the final '"'
-     */
-    int getQuoted(int p0, DOMString &result);
-
-/**
- * Not in api.  replaces URI return by lexer
- */
-int getUri(int p0, DOMString &str);
-
-
-/**
- * Skip to the next rule
- */
-int skipBlock(int p0);
-
-//#########################################################################
-//# P R O D U C T I O N S
-//#########################################################################
-
-/**
- * stylesheet
- *   : [ CHARSET_SYM S* STRING S* ';' ]?
- *     [S|CDO|CDC]* [ import [S|CDO|CDC]* ]*
- *     [ [ ruleset | media | page ] [S|CDO|CDC]* ]*
- *   ;
- */
-int getStyleSheet(int p0);
-
-/**
- * import
- *   : IMPORT_SYM S*
- *     [STRING|URI] S* [ medium [ COMMA S* medium]* ]? ';' S*
- *   ;
- */
-int getImport(int p0);
-
-/**
- * media
- *   : MEDIA_SYM S* medium [ COMMA S* medium ]* LBRACE S* ruleset* '}' S*
- *   ;
- */
-int getMedia(int p0);
-
-/**
- * medium
- *   : IDENT S*
- *   ;
- */
-int getMedium(int p0);
-
-/**
- * page
- *   : PAGE_SYM S* pseudo_page? S*
- *     LBRACE S* declaration [ ';' S* declaration ]* '}' S*
- *   ;
- */
-int getPage(int p0);
-
-/**
- * pseudo_page
- *   : ':' IDENT
- *   ;
- */
-int getPseudoPage(int p0);
-
-/**
- * ruleset
- *   : selector [ COMMA S* selector ]*
- *     LBRACE S* declaration [ ';' S* declaration ]* '}' S*
- *   ;
- */
-int getRuleSet(int p0);
-
-/**
- * selector
- *   : simple_selector [ combinator simple_selector ]*
- *   ;
- */
-int getSelector(int p0);
-
-/**
- * simple_selector
- *   : element_name [ HASH | class | attrib | pseudo ]*
- *   | [ HASH | class | attrib | pseudo ]+
- *   ;
- */
-int getSimpleSelector(int p0);
-
-/**
- * declaration
- *   : property ':' S* expr prio?
- *   | {empty}
- *   ;
- */
-int getDeclaration(int p0, CSSStyleDeclaration &declarationList);
-
-/**
- * prio
- *   : IMPORTANT_SYM S*
- *   ;
- */
-int getPrio(int p0, DOMString &val);
-
-/**
- * expr
- *   : term [ operator term ]*
- *   ;
- */
-int getExpr(int p0);
-
-/**
- * term
- *   : unary_operator?
- *     [ NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | ANGLE S* |
- *       TIME S* | FREQ S* | function ]
- *   | STRING S* | IDENT S* | URI S* | hexcolor
- *   ;
- */
-int getTerm(int p0);
-
-/**
- * function
- *   : FUNCTION S* expr ')' S*
- *   ;
- */
-int getFunction(int p0);
-
-/**
- * There is a constraint on the color that it must
- * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F])
- * after the "#"; e.g., "#000" is OK, but "#abcd" is not.
- *
- * hexcolor
- *   : HASH S*
- *   ;
- */
-int getHexColor(int p0);
-
-
-int lastPosition;
-
-/**
- * Get the column and row number of the given character position.
- * Also gets the last-occuring newline before the position
- */
-void getColumnAndRow(int p, int &col, int &row, int &lastNL);
-
-};
-
-
-} // namespace css
-} // namespace dom
-} // namespace w3c
-} // namespace org
-
-
-
-
-
-
-
-#endif /* __CSSPARSER_H__ */
-//#########################################################################
-//# E N D    O F    F I L E
-//#########################################################################
-
diff --git a/src/dom/cssreader.cpp b/src/dom/cssreader.cpp
new file mode 100644 (file)
index 0000000..b3302dd
--- /dev/null
@@ -0,0 +1,1670 @@
+/**
+ * Phoebe DOM Implementation.
+ *
+ * This is a C++ approximation of the W3C DOM model, which follows
+ * fairly closely the specifications in the various .idl files, copies of
+ * which are provided for reference.  Most important is this one:
+ *
+ * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html
+ *
+ * Authors:
+ *   Bob Jamison
+ *
+ * Copyright (C) 2005-2008 Bob Jamison
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "cssreader.h"
+#include "ucd.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+
+namespace org
+{
+namespace w3c
+{
+namespace dom
+{
+namespace css
+{
+
+//#########################################################################
+//# M E S S A G E S
+//#########################################################################
+
+/**
+ * Get the column and row number of the given character position
+ */
+void CssParser::getColumnAndRow(int p, int &colResult, int &rowResult, int &lastNL)
+{
+    int col    = 1;
+    int row    = 1;
+    int lastnl = 0;
+
+    for (int i=0 ; i<p ; i++)
+        {
+        XMLCh ch = parsebuf[i];
+        if (ch == '\n')
+            {
+            lastnl = i;
+            row++;
+            col=0;
+            }
+        else
+            col++;
+        }
+
+    colResult  = col;
+    rowResult  = row;
+    lastNL     = lastnl;
+}
+
+/**
+ *
+ */
+void CssParser::error(char const *fmt, ...)
+{
+    int lineNr;
+    int colNr;
+    int lastNL;
+    getColumnAndRow(lastPosition, colNr, lineNr, lastNL);
+
+    va_list args;
+    fprintf(stderr, "CssParser:error at %d, line %d, column %d:",
+                        lastPosition, lineNr, colNr);
+    va_start(args, fmt);
+    vfprintf(stderr, fmt, args);
+    va_end(args) ;
+    fprintf(stderr, "\n");
+
+    /*
+    int lineLen = lastPosition - lastNL;
+    printf("lineLen:%d lastNL:%d\n", lineLen, lastNL);
+    for (int i=lastNL+1 ; i<lastPosition ; i++)
+        fprintf(stderr, "%c", parsebuf[i]);
+    fprintf(stderr, "\n");
+    for (int i=0 ; i<lineLen-1 ; i++)
+        fprintf(stderr, " ");
+    fprintf(stderr, "^\n");
+    */
+    for (int i=0 ; i<lastPosition ; i++)
+        fprintf(stderr, "%c", parsebuf[i]);
+    fprintf(stderr, "\n");
+}
+
+
+
+//#########################################################################
+//# P A R S I N G
+//#########################################################################
+
+/**
+ *  Get the character at the position and record the fact
+ */
+XMLCh CssParser::get(int p)
+{
+    if (p >= parselen)
+        return 0;
+    XMLCh ch = parsebuf[p];
+    //printf("%c", ch);
+    lastPosition = p;
+    return ch;
+}
+
+
+
+/**
+ *  Test if the given substring exists at the given position
+ *  in parsebuf.  Use get() in case of out-of-bounds
+ */
+bool CssParser::match(int pos, const char *str)
+{
+    while (*str)
+       {
+       if (get(pos++) != (XMLCh) *str++)
+           return false;
+       }
+   return true;
+}
+
+/**
+ *
+ */
+int CssParser::skipwhite(int p)
+{
+  while (p < parselen)
+    {
+    //# XML COMMENT
+    if (match(p, "<!--"))
+        {
+        p+=4;
+        bool done=false;
+        while (p<parselen)
+            {
+            if (match(p, "-->"))
+                {
+                p+=3;
+                done=true;
+                break;
+                }
+            p++;
+            }
+        lastPosition = p;
+        if (!done)
+            {
+            error("unterminated <!-- .. --> comment");
+            return -1;
+            }
+        }
+    //# C comment
+    else if (match(p, "/*"))
+        {
+        p+=2;
+        bool done=false;
+        while (p<parselen)
+            {
+            if (match(p, "*/"))
+                {
+                p+=2;
+                done=true;
+                break;
+                }
+            p++;
+            }
+        lastPosition = p;
+        if (!done)
+            {
+            error("unterminated /* .. */ comment");
+            return -1;
+            }
+        }
+    else if (!uni_is_space(get(p)))
+        break;
+    else
+        p++;
+    }
+  lastPosition = p;
+  return p;
+}
+
+/**
+ * get a word from the buffer
+ */
+int CssParser::getWord(int p, DOMString &result)
+{
+    XMLCh ch = get(p);
+    if (!uni_is_letter(ch))
+        return p;
+    DOMString str;
+    str.push_back(ch);
+    p++;
+
+    while (p < parselen)
+        {
+        ch = get(p);
+        if (uni_is_letter_or_digit(ch) || ch=='-' || ch=='_')
+            {
+            str.push_back(ch);
+            p++;
+            }
+        else if (ch == '\\')
+            {
+            p+=2;
+            }
+        else
+            break;
+        }
+    result = str;
+    return p;
+}
+
+
+/**
+ * get a word from the buffer
+ */
+int CssParser::getNumber(int p0, double &result)
+{
+    int p=p0;
+    DOMString str;
+    while (p < parselen)
+        {
+        XMLCh ch = get(p);
+        if (ch<'0' || ch>'9')
+            break;
+        str.push_back(ch);
+        p++;
+        }
+    if (get(p) == '.' && get(p+1)>='0' && get(p+1)<='9')
+        {
+        p++;
+        str.push_back('.');
+        while (p < parselen)
+            {
+            XMLCh ch = get(p);
+            if (ch<'0' || ch>'9')
+                break;
+            str.push_back(ch);
+            p++;
+            }
+        }
+    if (p>p0)
+        {
+        char *start = (char *)str.c_str();
+        char *end   = NULL;
+        double val = strtod(start, &end);
+        if (end > start)
+            {
+            result = val;
+            return p;
+            }
+        }
+
+    //not a number
+    return p0;
+}
+
+
+
+/**
+ * Assume that we are starting on a quote.  Ends on the char
+ * after the final '"'
+ */
+int CssParser::getQuoted(int p0, DOMString &result)
+{
+
+    int p = p0;
+
+    XMLCh quoteChar = get(p);
+    if (quoteChar != '"' && quoteChar != '\'')
+        return p0;
+
+    p++;
+
+    DOMString buf;
+
+    bool done = false;
+    while (p<parselen )
+        {
+        XMLCh ch = get(p);
+        if (ch == quoteChar)
+            {
+            done = true;
+            p++;
+            break;
+            }
+        else
+            {
+            buf.push_back(ch);
+            }
+        p++;
+        }
+
+    if (!done)
+        {
+        error("unterminated quoted string");
+        return -1;
+        }
+
+    result.append(buf);
+
+    return p;
+}
+
+/**
+ * Not in api.  replaces URI return by lexer
+ */
+int CssParser::getUri(int p0, DOMString &str)
+{
+    int p = p0;
+    if (!match(p, "url("))
+        return p0;
+    p+=4;
+    p = skipwhite(p);
+    DOMString buf;
+    XMLCh ch;
+    while (p < parselen)
+        {
+        ch = get(p);
+        if (isspace(ch) || ch==')')
+            break;
+        buf.push_back(ch);
+        p++;
+        }
+    p = skipwhite(p);
+    ch = get(p);
+    if (ch != ')')
+        {
+        error("no closing ')' on url spec");
+        return -1;
+        }
+    p++;
+    str = buf;
+    return p;
+}
+
+/**
+ * Skip to the end of the block
+ */
+int CssParser::skipBlock(int p0)
+{
+    int p = p0;
+    while (p < parselen)
+        {
+        XMLCh ch = get(p);
+        if (ch == '}')
+            {
+            p++;
+            break;
+            }
+        else
+            {
+            p++;
+            }
+        }
+    return p;
+}
+
+//#########################################################################
+//# P R O D U C T I O N S
+//#########################################################################
+
+/**
+ * stylesheet
+ *   : [ CHARSET_SYM S* STRING S* ';' ]?
+ *     [S|CDO|CDC]* [ import [S|CDO|CDC]* ]*
+ *     [ [ ruleset | media | page ] [S|CDO|CDC]* ]*
+ *   ;
+ */
+int CssParser::getStyleSheet(int p0)
+{
+    int p = p0;
+    int p2 = p;
+    XMLCh ch;
+
+    //# CHARSET   0 or 1
+    if (match(p, "@charset"))
+        {
+        p+=8;
+        p = skipwhite(p);
+        DOMString str;
+        p2 = getQuoted(p, str);
+        if (p2<=p)
+            {
+            error("quoted string required after @charset");
+            return -1;
+            }
+        p = skipwhite(p2);
+        ch = get(p);
+        if (ch !=';')
+            {
+            error("';' required after @charset declaration");
+            return -1;
+            }
+        p++;
+        p = skipwhite(p);
+        }
+
+    //# IMPORT  0 to many
+    while (true)
+        {
+        p2 = getImport(p);
+        if (p2<0)
+            {
+            return -1;
+            }
+        if (p2<=p)
+            break;
+        p = p2;
+        }
+
+    //# RULESET | MEDIA | PAGE  0 to many
+    while (true)
+        {
+        //Ruleset
+        p2 = getRuleSet(p);
+        if (p2<0)
+            {
+            return -1;
+            }
+        if (p2>p)
+            {
+            p = p2;
+            continue;
+            }
+
+        //Media
+        p2 = getMedia(p);
+        if (p2<0)
+            {
+            return -1;
+            }
+        if (p2>p)
+            {
+            p = p2;
+            continue;
+            }
+
+        //Page
+        p2 = getPage(p);
+        if (p2<0)
+            {
+            return -1;
+            }
+        if (p2>p)
+            {
+            p = p2;
+            continue;
+            }
+
+        //none of the above
+        break;
+        }
+
+    return p;
+}
+
+/**
+ * import
+ *   : IMPORT_SYM S*
+ *     [STRING|URI] S* [ medium [ COMMA S* medium]* ]? ';' S*
+ *   ;
+ */
+int CssParser::getImport(int p0)
+{
+    int p = p0;
+    if (!match(p, "@import"))
+        return p0;
+    p+=7;
+    p = skipwhite(p);
+
+    //# STRING | URI
+    DOMString str;
+    int p2 = getQuoted(p, str);
+    if (p2<0)
+        {
+        return -1;
+        }
+    if (p2<=p)
+        {
+        p2 = getUri(p, str);
+        if (p2<0)
+            {
+            return -1;
+            }
+        if (p2<=p)
+            {
+            error("quoted string or URI required after @import");
+            return -1;
+            }
+        }
+    p = p2;
+    p2 = getMedium(p);
+    if (p2<0)
+        return -1;
+
+    p = p2;
+    p = skipwhite(p);
+    XMLCh ch = get(p);
+    if (ch != ';')
+        {
+        error("@import must be terminated with ';'");
+        return -1;
+        }
+    p++;
+    return p;
+}
+
+/**
+ * media
+ *   : MEDIA_SYM S* medium [ COMMA S* medium ]* LBRACE S* ruleset* '}' S*
+ *   ;
+ */
+int CssParser::getMedia(int p0)
+{
+    int p = p0;
+    XMLCh ch;
+    if (!match(p, "@media"))
+        return p0;
+    p+=6;
+    p = skipwhite(p);
+
+    //# MEDIUM LIST
+    int p2 = getMedium(p);
+    if (p2<0)
+        return -1;
+    if (p2<=p)
+        {
+        error("@media must be followed by medium");
+        return -1;
+        }
+    p = p2;
+    while (true)
+        {
+        ch = get(p);
+        if (ch != ',')
+            break;
+        p2 = getMedium(p);
+        if (p2<0)
+            return -1;
+        if (p2<=p)
+            {
+            error("',' in medium list must be followed by medium");
+            return -1;
+            }
+        p = p2;
+        }
+
+    p = skipwhite(p);
+    ch = get(p);
+    if (ch!='{')
+        {
+        error("@media requires '{' for ruleset");
+        return -1;
+        }
+    p++;
+    p2 = getRuleSet(p);
+    if (p2<0)
+        return -1;
+    if (p2<=p)
+        {
+        error("@media requires ruleset after '{'");
+        return -1;
+        }
+    p = p2;
+    ch = get(p);
+    if (ch != '}')
+        {
+        error("@media requires '}' after ruleset");
+        return -1;
+        }
+    p++;
+    return p0;
+}
+
+/**
+ * medium
+ *   : IDENT S*
+ *   ;
+ */
+int CssParser::getMedium(int p0)
+{
+    int p = p0;
+    p = skipwhite(p);
+
+    DOMString ident;
+    int p2 = getWord(p, ident);
+    if (p2<0)
+        return -1;
+    if (p2<=p)
+        return p0;
+    p = p2;
+
+    return p;
+}
+
+/**
+ * page
+ *   : PAGE_SYM S* pseudo_page? S*
+ *     LBRACE S* declaration [ ';' S* declaration ]* '}' S*
+ *   ;
+ */
+int CssParser::getPage(int p0)
+{
+    int p = p0;
+
+    //# @PAGE
+    p = skipwhite(p);
+    if (!match(p, "@page"))
+        return p0;
+    p+= 5;
+
+    //#PSEUDO PAGE 0 or 1
+    p = skipwhite(p);
+    int p2 = getPseudoPage(p);
+    if (p2<0)
+        return -1;
+    if (p2>p)
+        {
+        p = p2;
+        }
+
+    //# {
+    p=skipwhite(p);
+    XMLCh ch = get(p);
+    if (p != '{')
+        {
+        error("@page requires '{' before declarations");
+        }
+    p++;
+
+    //# DECLARATION LIST
+    p = skipwhite(p);
+    CSSStyleDeclaration declarationList;
+    p2 = getDeclaration(p, declarationList);
+    if (p2<0)
+        return -1;
+    if (p2<=p)
+        {
+        error("@page requires declaration(s) after '{'");
+        return -1;
+        }
+    while (true)
+        {
+        p = skipwhite(p2);
+        ch = get(p);
+        if (ch != ';')
+            break;
+        p++;
+        p = skipwhite(p);
+        p2 = getDeclaration(p, declarationList);
+        if (p2<0)
+            return -1;
+        if (p2<= p)
+            {
+            error("@page requires declaration after ';'");
+            return -1;
+            }
+        }
+
+    //# }
+    p=skipwhite(p);
+    ch = get(p);
+    if (p != '}')
+        {
+        error("@page requires '}' after declarations");
+        }
+    p++;
+
+    return p;
+}
+
+/**
+ * pseudo_page
+ *   : ':' IDENT
+ *   ;
+ */
+int CssParser::getPseudoPage(int p0)
+{
+    int p = p0;
+    if (!match(p, ":"))
+        return p0;
+    p++;
+    DOMString str;
+    int p2 = getWord(p, str);
+    if (p2<0)
+        return -1;
+    if (p2<=p)
+        {
+        error("pseudo-page requires identifier after ':'");
+        return -1;
+        }
+    p = p2;
+    return p;
+}
+
+/**
+ * ruleset
+ *   : selector [ COMMA S* selector ]*
+ *     LBRACE S* declaration [ ';' S* declaration ]* '}' S*
+ *   ;
+ */
+int CssParser::getRuleSet(int p0)
+{
+    int p = p0;
+    XMLCh ch;
+
+    //## SELECTOR
+    p = skipwhite(p);
+    int p2 = getSelector(p);
+    if (p2<0)
+        return -1;
+    if (p2<=p)  //no selector
+        {
+        if (get(p) != '{')//check for selector-less rule
+            return p0;//not me
+        }
+    p = p2;
+    while (true)
+        {
+        p = skipwhite(p);
+        ch = get(p);
+        if (ch != ',')
+            break;
+        p++;
+        p = skipwhite(p);
+        int p2 = getSelector(p);
+        if (p2<0)
+            return -1;
+        if (p2<=p)
+            {
+            error("selector required after ',' in list");
+            return -1;
+            }
+        p = p2;
+        }
+
+    //## {
+    ch = get(p);
+    if (ch != '{')
+        {
+        error("'{' required before declarations of ruleset");
+        return -1;
+        }
+    p++;
+
+    //## DECLARATIONS ( 0 to many )
+    CSSStyleDeclaration declarationList;
+
+    p = skipwhite(p);
+    p2 = getDeclaration(p, declarationList);
+    if (p2<0)
+        return -1;
+    if (p2>p)
+        {
+        p = p2;
+        while (true)
+            {
+            p = skipwhite(p);
+            ch = get(p);
+            if (ch != ';')
+                break;
+            p++;
+            p = skipwhite(p);
+            p2 = getDeclaration(p, declarationList);
+            if (p2<0)
+                return -1;
+            if (p2<=p)
+                {
+                //apparently this is ok
+                //error("declaration required after ';' in ruleset");
+                //return -1;
+                break;
+                }
+            p = p2;
+            }
+        }
+    //## }
+    ch = get(p);
+    if (ch != '}')
+        {
+        error("ruleset requires closing '}'");
+        return -1;
+        }
+    p++;
+    p = skipwhite(p);
+
+    return p;
+}
+
+/**
+ * selector
+ *   : simple_selector [ combinator simple_selector ]*
+ *   ;
+ */
+int CssParser::getSelector(int p0)
+{
+    int p = p0;
+
+    //## SIMPLE SELECTOR
+    p = skipwhite(p);
+    int p2 = getSimpleSelector(p);
+    if (p2<0)
+        return -1;
+    if (p2<=p)
+        return p0; //not me
+    p = p2;
+
+    //## COMBINATORS + MORE SELECTORS
+    while (true)
+        {
+        XMLCh ch = get(p);
+        bool wasSpace = isspace(ch);
+        p = skipwhite(p);
+        ch = get(p);
+        //# Combinators
+        //easier to do here than have a getCombinator()
+        int visibleCombinator = false;
+        if (ch == '+')
+            {
+            visibleCombinator = true;
+            p++;
+            }
+        else if (ch == '>')
+            {
+            visibleCombinator = true;
+            p++;
+            }
+        else if (wasSpace)
+            {
+            }
+        else
+            {
+            break;
+            }
+        p = skipwhite(p);
+        p2 = getSimpleSelector(p);
+        if (p2<0)
+            return -1;
+        if (p2<=p)
+            {
+            if (visibleCombinator)
+                {
+                error("need simple selector after combinator");
+                return -1;
+                }
+            else
+                {
+                break;
+                }
+            }
+        p = p2;
+        }
+    return p;
+}
+
+/**
+ * simple_selector
+ *   : element_name [ HASH | class | attrib | pseudo ]*
+ *   | [ HASH | class | attrib | pseudo ]+
+ *   ;
+ */
+int CssParser::getSimpleSelector(int p0)
+{
+    int p = p0;
+    int p2;
+
+    DOMString str;
+
+    p = skipwhite(p);
+
+    int selectorItems = 0;
+
+    XMLCh ch = get(p);
+
+    //######################
+    //# Note: do NOT skipwhite between items.  Only within the
+    //# pseudo function and attrib below
+    //######################
+
+    //#Element name 0 or 1
+    if (uni_is_letter(ch))
+        {
+        p2 = getWord(p, str);
+        if (p2<0)
+            return -1;
+        if (p2<=p)
+            {
+            error("null element name");
+            return -1;
+            }
+        selectorItems++;
+        p = p2;
+        }
+    else if (ch == '*')
+        {
+        str = "*";
+        p++;
+        selectorItems++;
+        }
+
+
+
+    //## HASH, CLASS, ATTRIB, PSEUDO  (0 to many with elem name, 1 to many without)
+    while (true)
+        {
+        XMLCh ch = get(p);
+
+        //# HASH
+        if (ch == '#')
+            {
+            p++;
+            p2 = getWord(p, str);
+            if (p2<0)
+                return -1;
+            if (p2<=p)
+                {
+                error("no name for hash");
+                return -1;
+                }
+            p = p2;
+            selectorItems++;
+            }
+
+        //# CLASS
+        else if (ch == '.')
+            {
+            p++;
+            p2 = getWord(p, str);
+            if (p2<0)
+                return -1;
+            if (p2<=p)
+                {
+                error("no name for class");
+                return -1;
+                }
+            p = p2;
+            selectorItems++;
+            }
+
+        //# ATTRIB
+        else if (ch == '[')
+            {
+            p++;
+            p = skipwhite(p);
+            p2 = getWord(p, str);
+            if (p2<0)
+                return -1;
+            if (p2<=p)
+                {
+                error("no name for class");
+                return -1;
+                }
+            p = skipwhite(p2);
+            bool getRHS=false;
+            if (match(p, "="))
+                {
+                p++;
+                getRHS=true;
+                }
+            else if (match(p, "~="))
+                {
+                p+=2;
+                getRHS=true;
+                }
+            else if (match(p, "|="))
+                {
+                p+=2;
+                getRHS=true;
+                }
+            if (getRHS)
+                {
+                p = skipwhite(p);
+                ch = get(p);
+                if (uni_is_letter(ch))
+                    {
+                    p2 = getWord(p, str);
+                    if (p2<0)
+                        return -1;
+                    if (p2<=p)
+                        {
+                        error("null ident on rhs of attrib");
+                        return -1;
+                        }
+                    p = p2;
+                    }
+                else if (ch == '\'' || ch =='"')
+                    {
+                    p2 = getQuoted(p, str);
+                    if (p2<0)
+                        return -1;
+                    if (p2<=p)
+                        {
+                        error("null literal string on rhs of attrib");
+                        return -1;
+                        }
+                    p = p2;
+                    }
+                }//getRHS
+            p = skipwhite(p);
+            ch = get(p);
+            if (ch != ']')
+                {
+                error("attrib needs closing ']'");
+                //return -1;
+                p = skipBlock(p);
+                return p;
+                }
+            p++;
+            selectorItems++;
+            }
+
+        //# PSEUDO
+        else if (ch == ':')
+            {
+            p++;
+            p2 = getWord(p, str);
+            if (p2<0)
+                return -1;
+            if (p2<=p)
+                {
+                error("no name for pseudo");
+                return -1;
+                }
+            p = p2;
+            selectorItems++;
+            ch = get(p);
+            if (ch == '(')
+                {
+                p++;
+                p = skipwhite(p);
+                ch = get(p);
+                if (uni_is_letter(ch))
+                    {
+                    p2 = getWord(p, str);
+                    if (p2<0)
+                        return -1;
+                    if (p2<=p)
+                        {
+                        error("null function parameter in pseudo");
+                        return -1;
+                        }
+                    p = skipwhite(p2);
+                    ch = get(p);
+                    }
+                if (ch != ')')
+                    {
+                    error("function in pseudo needs ')'");
+                    return -1;
+                    }
+                p++;
+                }// ch==(   -function-
+            }//pseudo
+
+        //# none of the above
+        else
+            {
+            break;
+            }
+
+        }//while
+
+
+    if (selectorItems > 0)
+        return p;
+    return p0;
+}
+
+/**
+ * declaration
+ *   : property ':' S* expr prio?
+ *   | {empty}
+ *   ;
+ */
+int CssParser::getDeclaration(int p0, CSSStyleDeclaration &declarationList)
+{
+    int p = p0;
+
+    //## PROPERTY
+    p = skipwhite(p);
+    XMLCh ch = get(p);
+    if (!uni_is_letter(ch))
+        return p0; //not me
+    DOMString propName;
+    int p2 = getWord(p, propName);
+    if (p2<0)
+        return -1;
+
+    //## ':'
+    p = skipwhite(p2);
+    ch = get(p);
+    if (ch != ':')
+        {
+        error("declaration requires ':' between name and value");
+        return -1;
+        }
+    p++;
+
+    //## EXPR
+    p = skipwhite(p);
+    p2 = getExpr(p);
+    if (p2<0)
+        return -1;
+    if (p2<=p)
+        {
+        error("declaration requires value after ':'");
+        return -1;
+        }
+    DOMString propVal;
+    for (int i=p ; i<p2 ; i++)  //get our substring
+        propVal.push_back(get(i));
+    printf("propVal:%s\n", propVal.c_str());
+    p = p2;
+
+    //## PRIO (optional)
+    p = skipwhite(p);
+    DOMString prio;
+    p2 = getPrio(p, prio);
+    if (p2<0)
+        return -1;
+    if (p2>p)
+        {
+        //do something
+        p = p2;
+        }
+
+    return p;
+}
+
+/**
+ * prio
+ *   : IMPORTANT_SYM S*
+ *   ;
+ */
+int CssParser::getPrio(int p0, DOMString &val)
+{
+    int p = p0;
+
+    //## '!"
+    p = skipwhite(p);
+    XMLCh ch = get(p);
+    if (ch != '!')
+        return p0;
+    p++;
+
+    //## "important"
+    p = skipwhite(p);
+    if (!match(p, "important"))
+        {
+        error("priority symbol is 'important'");
+        return -1;
+        }
+    p += 9;
+    val = "important";
+    return p;
+}
+
+/**
+ * expr
+ *   : term [ operator term ]*
+ *   ;
+ */
+int CssParser::getExpr(int p0)
+{
+    int p = p0;
+
+    //## TERM
+    p = skipwhite(p);
+    int p2 = getTerm(p);
+    if (p2<0)
+        return -1;
+    if (p2<=p)
+        return p0;  //not me
+    p = p2;
+    while (p < parselen)
+        {
+        p = skipwhite(p);
+        //#Operator.  do this instead of getOperator()
+        XMLCh ch = get(p);
+        int visibleTerm = false;
+        if (ch == '/')
+            {
+            visibleTerm = true;
+            p++;
+            }
+        else if (ch == ',')
+            {
+            visibleTerm = true;
+            p++;
+            }
+        else
+            {
+            //just space.  this is allowable between terms,
+            // so we still need to check for another term
+            }
+        p = skipwhite(p);
+        p2 = getTerm(p);
+        if (p2<0)
+            return -1;
+        if (p2<=p)
+            {
+            if (visibleTerm)
+                {
+                error("expression requires term after operator");
+                return -1;
+                }
+            else
+                {
+                break;
+                }
+            }
+        p = p2;
+        }
+
+    return p;
+}
+
+/**
+ * term
+ *   : unary_operator?
+ *     [ NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | ANGLE S* |
+ *       TIME S* | FREQ S* | function ]
+ *   | STRING S* | IDENT S* | URI S* | hexcolor
+ *   ;
+ */
+int CssParser::getTerm(int p0)
+{
+    int p = p0;
+    p = skipwhite(p);
+    int unitType = CSSPrimitiveValue::CSS_UNKNOWN;
+    //# Unary operator
+    XMLCh ch = get(p);
+    bool hasUnary = false;
+    if (ch == '-')
+        {
+        p++;
+        hasUnary = true;
+        }
+    else if (ch == '+')
+        {
+        p++;
+        hasUnary = true;
+        }
+    //# NUMERIC
+    double numVal;
+    int p2 = getNumber(p, numVal);
+    if (p2<0)
+        return -1;
+    if (p2>p)
+        {
+        p = p2;
+        if (match(p, "%"))
+            {
+            unitType = CSSPrimitiveValue::CSS_PERCENTAGE;
+            p++;
+            }
+        else if (match(p, "em"))
+            {
+            unitType = CSSPrimitiveValue::CSS_EMS;
+            p+=2;
+            }
+        else if (match(p, "ex"))
+            {
+            unitType = CSSPrimitiveValue::CSS_EXS;
+            p+=2;
+            }
+        else if (match(p, "px"))
+            {
+            unitType = CSSPrimitiveValue::CSS_PX;
+            p+=2;
+            }
+        else if (match(p, "cm"))
+            {
+            unitType = CSSPrimitiveValue::CSS_CM;
+            p+=2;
+            }
+        else if (match(p, "mm"))
+            {
+            unitType = CSSPrimitiveValue::CSS_MM;
+            p+=2;
+            }
+        else if (match(p, "in"))
+            {
+            unitType = CSSPrimitiveValue::CSS_IN;
+            p+=2;
+            }
+        else if (match(p, "pt"))
+            {
+            unitType = CSSPrimitiveValue::CSS_PT;
+            p+=2;
+            }
+        else if (match(p, "pc"))
+            {
+            unitType = CSSPrimitiveValue::CSS_PC;
+            p+=2;
+            }
+        else if (match(p, "deg"))
+            {
+            unitType = CSSPrimitiveValue::CSS_DEG;
+            p+=3;
+            }
+        else if (match(p, "rad"))
+            {
+            unitType = CSSPrimitiveValue::CSS_RAD;
+            p+=3;
+            }
+        else if (match(p, "grad"))
+            {
+            unitType = CSSPrimitiveValue::CSS_GRAD;
+            p+=4;
+            }
+        else if (match(p, "ms"))
+            {
+            unitType = CSSPrimitiveValue::CSS_MS;
+            p+=2;
+            }
+        else if (match(p, "s"))
+            {
+            unitType = CSSPrimitiveValue::CSS_S;
+            p+=1;
+            }
+        else if (match(p, "Hz"))
+            {
+            unitType = CSSPrimitiveValue::CSS_HZ;
+            p+=2;
+            }
+        else if (match(p, "kHz"))
+            {
+            unitType = CSSPrimitiveValue::CSS_KHZ;
+            p+=2;
+            }
+        else if (uni_is_letter(get(p)))//some other string
+            {
+            DOMString suffix;
+            p2 = getWord(p, suffix);
+            if (p2<0)
+                return -1;
+            unitType = CSSPrimitiveValue::CSS_DIMENSION;
+            p = p2;
+            }
+        else //plain number
+            {
+            unitType = CSSPrimitiveValue::CSS_NUMBER;
+            }
+        return p;
+        }
+
+    DOMString str;
+
+    //## URI --do before function, as syntax is similar
+    p2 = getUri(p, str);
+    if (p2<0)
+        return -1;
+    if (p2>p)
+        {
+        if (hasUnary)
+            {
+            error("+ or - not allowed on URI");
+            return -1;
+            }
+        p = p2;
+        unitType = CSSPrimitiveValue::CSS_URI;
+        return p;
+        }
+
+    //## FUNCTION
+    p2 = getFunction(p);
+    if (p2<0)
+        return -1;
+    if (p2>p)
+        {
+        p = p2;
+        return p;
+        }
+
+    //## STRING
+    ch = get(p);
+    if (ch == '"' || ch == '\'')
+        {
+        p2 = getQuoted(p, str);
+        if (p2<0)
+            return -1;
+        if (p2>p)
+            {
+            if (hasUnary)
+                {
+                error("+ or - not allowed on a string");
+                return -1;
+                }
+            p = p2;
+            unitType = CSSPrimitiveValue::CSS_STRING;
+            return p;
+            }
+        }
+
+    //## IDENT
+    ch = get(p);
+    if (uni_is_letter(ch))
+        {
+        p2 = getWord(p, str);
+        if (p2<0)
+            return -1;
+        if (p2>p)
+            {
+            if (hasUnary)
+                {
+                error("+ or - not allowed on an identifier");
+                return -1;
+                }
+            p = p2;
+            unitType = CSSPrimitiveValue::CSS_IDENT;
+            return p;
+            }
+        }
+
+
+    //## HEXCOLOR
+    p2 = getHexColor(p);
+    if (p2<0)
+        return -1;
+    if (p2>p)
+        {
+        if (hasUnary)
+            {
+            error("+ or - not allowed on hex color");
+            return -1;
+            }
+        p = p2;
+        unitType = CSSPrimitiveValue::CSS_RGBCOLOR;
+        return p;
+        }
+
+
+    return p0;
+}
+
+/**
+ * function
+ *   : FUNCTION S* expr ')' S*
+ *   ;
+ */
+int CssParser::getFunction(int p0)
+{
+    int p = p0;
+
+    //## IDENT + (   (both)
+    DOMString name;
+    p = skipwhite(p);
+    int p2 = getWord(p, name);
+    if (p2<0)
+        return -1;
+    if (p2<=p)
+        return p0; //not me
+    if (name == "uri" || name=="url")
+        return p0; //not me
+    p = skipwhite(p2);
+    XMLCh ch = get(p);
+    if (ch != '(')
+        return p0; //still not me
+    p++;
+
+    //## EXPR
+    p = skipwhite(p);
+    p2 = getExpr(p);
+    if (p2<0)
+        return -1;
+    if (p2<=p)
+        {
+        error("function requires expression");
+        return -1;
+        }
+    p = p2;
+
+    //## ')'
+    p = skipwhite(p);
+    ch = get(p);
+    if (ch != ')')
+        {
+        error("function requires closing ')'");
+        return -1;
+        }
+    p++;
+    p = skipwhite(p);
+
+    return p;
+}
+
+/**
+ * There is a constraint on the color that it must
+ * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F])
+ * after the "#"; e.g., "#000" is OK, but "#abcd" is not.
+ * hexcolor
+ *   : HASH S*
+ *   ;
+ */
+int CssParser::getHexColor(int p0)
+{
+    int p = p0;
+
+    //## '#'
+    p = skipwhite(p);
+    if (!match(p, "#"))
+        return p0;
+    p++;
+
+    //## HEX
+    DOMString hex;
+    long hexVal = 0;
+    while (p < parselen)
+        {
+        XMLCh b = get(p);
+        if (b>='0' && b<='9')
+            {
+            hexVal = (hexVal << 4) + (b - '0');
+            hex.push_back(b);
+            p++;
+            }
+        else if (b>='a' && b<='f')
+            {
+            hexVal = (hexVal << 4) + (b - 'a' + 10);
+            hex.push_back(b);
+            p++;
+            }
+        else if (b>='A' && b<='F')
+            {
+            hexVal = (hexVal << 4) + (b - 'A' + 10);
+            hex.push_back(b);
+            p++;
+            }
+        else
+            {
+            break;
+            }
+        }
+
+    if (hex.size() != 3 && hex.size() != 6)
+        {
+        error("exactly 3 or 6 hex digits are required after '#'");
+        return -1;
+        }
+
+    return p;
+}
+
+
+
+/**
+ *
+ */
+bool CssParser::parse(const DOMString &str)
+{
+    /*
+    int len = str.size();
+    for (int i=0 ; i<len ; i++)
+        {
+        XMLCh ch = str[i];
+        if (ch == '\\' && i<(len-1)) //escape!
+            {
+            i++;
+            }
+        else
+            parsebuf.push_back(ch);
+        }
+    */
+    parsebuf = str;
+
+    parselen = parsebuf.size();
+    //printf("==============================\n%s\n========================\n", str.c_str());
+
+    lastPosition = 0;
+
+    int p = getStyleSheet(0);
+    if (p < parselen)
+        {
+        error("Not everything parsed");
+        return false;
+        }
+
+    return true;
+}
+
+
+/**
+ *
+ */
+bool CssParser::parseFile(const DOMString &fileName)
+{
+    DOMString tmp = fileName;
+    char *fname = (char *)tmp.c_str();
+    FILE *f = fopen(fname, "r");
+    if (!f)
+        {
+        printf("Could not open %s for reading\n", fname);
+        return false;
+        }
+
+    DOMString str;
+    while (!feof(f))
+        {
+        int ch = fgetc(f);
+        if (ch<0)
+            break;
+        str.push_back((XMLCh)ch);
+        }
+    fclose(f);
+
+    bool ret = parse(str);
+
+    return ret;
+}
+
+
+
+
+
+
+
+} // namespace css
+} // namespace dom
+} // namespace w3c
+} // namespace org
+
+
+#ifdef TEST
+
+int main(int argc, char **argv)
+{
+    org::w3c::dom::css::CssParser parser;
+    char *fileName;
+    fileName = "001.css";
+    //fileName = "acid.css";
+    //fileName = "base.css";
+    //fileName = "inkscape.css";
+    //fileName = "meyerweb.css";
+    if (!parser.parseFile(fileName))
+        {
+        printf("Test failed\n");
+        return 1;
+        }
+    return 0;
+}
+
+#endif /* TEST */
+
+//#########################################################################
+//# E N D    O F    F I L E
+//#########################################################################
+
diff --git a/src/dom/cssreader.h b/src/dom/cssreader.h
new file mode 100644 (file)
index 0000000..1569ab8
--- /dev/null
@@ -0,0 +1,290 @@
+#ifndef __CSSREADER_H__
+#define __CSSREADER_H__
+/**
+ * Phoebe DOM Implementation.
+ *
+ * This is a C++ approximation of the W3C DOM model, which follows
+ * fairly closely the specifications in the various .idl files, copies of
+ * which are provided for reference.  Most important is this one:
+ *
+ * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html
+ *
+ * Authors:
+ *   Bob Jamison
+ *
+ * Copyright (C) 2005-2008 Bob Jamison
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+#include "dom.h"
+
+#include "css.h"
+
+namespace org
+{
+namespace w3c
+{
+namespace dom
+{
+namespace css
+{
+
+class CssParser
+{
+
+public:
+
+    /**
+     *
+     */
+    CssParser()
+        {}
+
+    /**
+     *
+     */
+    virtual ~CssParser()
+        {}
+
+    /**
+     *
+     */
+    virtual bool parse(const DOMString &str);
+
+    /**
+     *
+     */
+    virtual bool parseFile(const DOMString &str);
+
+
+private:
+
+    DOMString parsebuf;
+    long parselen;
+    CSSStyleSheet stylesheet;
+
+
+    /**
+     *
+     */
+    void error(char const *fmt, ...)
+    #ifdef G_GNUC_PRINTF
+    G_GNUC_PRINTF(2, 3)
+    #endif
+    ;
+
+    /**
+     * Get the character at the given location in the buffer.
+     *  Return 0 if out-of-bounds
+     */
+    XMLCh get(int index);
+
+
+    /**
+     *  Test if the given substring exists at the given position
+     *  in parsebuf.  Use get() in case of out-of-bounds
+     */
+    bool match(int pos, const char *str);
+
+    /**
+     * Skip over whitespace
+     * Return new position
+     */
+    int skipwhite(int index);
+
+    /**
+     * Get the word at the current position.  Return the new
+     * position if successful, the current position if no word,
+     * -1 if error.
+     */
+    int getWord(int index, DOMString &str);
+
+
+    /**
+     * Get a number at the current position
+     * Return the new position if a proper number, else the original pos
+     */
+    int getNumber(int index, double &result);
+
+    /**
+     * Assume that we are starting on a quote.  Ends on the char
+     * after the final '"'
+     */
+    int getQuoted(int p0, DOMString &result);
+
+/**
+ * Not in api.  replaces URI return by lexer
+ */
+int getUri(int p0, DOMString &str);
+
+
+/**
+ * Skip to the next rule
+ */
+int skipBlock(int p0);
+
+//#########################################################################
+//# P R O D U C T I O N S
+//#########################################################################
+
+/**
+ * stylesheet
+ *   : [ CHARSET_SYM S* STRING S* ';' ]?
+ *     [S|CDO|CDC]* [ import [S|CDO|CDC]* ]*
+ *     [ [ ruleset | media | page ] [S|CDO|CDC]* ]*
+ *   ;
+ */
+int getStyleSheet(int p0);
+
+/**
+ * import
+ *   : IMPORT_SYM S*
+ *     [STRING|URI] S* [ medium [ COMMA S* medium]* ]? ';' S*
+ *   ;
+ */
+int getImport(int p0);
+
+/**
+ * media
+ *   : MEDIA_SYM S* medium [ COMMA S* medium ]* LBRACE S* ruleset* '}' S*
+ *   ;
+ */
+int getMedia(int p0);
+
+/**
+ * medium
+ *   : IDENT S*
+ *   ;
+ */
+int getMedium(int p0);
+
+/**
+ * page
+ *   : PAGE_SYM S* pseudo_page? S*
+ *     LBRACE S* declaration [ ';' S* declaration ]* '}' S*
+ *   ;
+ */
+int getPage(int p0);
+
+/**
+ * pseudo_page
+ *   : ':' IDENT
+ *   ;
+ */
+int getPseudoPage(int p0);
+
+/**
+ * ruleset
+ *   : selector [ COMMA S* selector ]*
+ *     LBRACE S* declaration [ ';' S* declaration ]* '}' S*
+ *   ;
+ */
+int getRuleSet(int p0);
+
+/**
+ * selector
+ *   : simple_selector [ combinator simple_selector ]*
+ *   ;
+ */
+int getSelector(int p0);
+
+/**
+ * simple_selector
+ *   : element_name [ HASH | class | attrib | pseudo ]*
+ *   | [ HASH | class | attrib | pseudo ]+
+ *   ;
+ */
+int getSimpleSelector(int p0);
+
+/**
+ * declaration
+ *   : property ':' S* expr prio?
+ *   | {empty}
+ *   ;
+ */
+int getDeclaration(int p0, CSSStyleDeclaration &declarationList);
+
+/**
+ * prio
+ *   : IMPORTANT_SYM S*
+ *   ;
+ */
+int getPrio(int p0, DOMString &val);
+
+/**
+ * expr
+ *   : term [ operator term ]*
+ *   ;
+ */
+int getExpr(int p0);
+
+/**
+ * term
+ *   : unary_operator?
+ *     [ NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | ANGLE S* |
+ *       TIME S* | FREQ S* | function ]
+ *   | STRING S* | IDENT S* | URI S* | hexcolor
+ *   ;
+ */
+int getTerm(int p0);
+
+/**
+ * function
+ *   : FUNCTION S* expr ')' S*
+ *   ;
+ */
+int getFunction(int p0);
+
+/**
+ * There is a constraint on the color that it must
+ * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F])
+ * after the "#"; e.g., "#000" is OK, but "#abcd" is not.
+ *
+ * hexcolor
+ *   : HASH S*
+ *   ;
+ */
+int getHexColor(int p0);
+
+
+int lastPosition;
+
+/**
+ * Get the column and row number of the given character position.
+ * Also gets the last-occuring newline before the position
+ */
+void getColumnAndRow(int p, int &col, int &row, int &lastNL);
+
+};
+
+
+} // namespace css
+} // namespace dom
+} // namespace w3c
+} // namespace org
+
+
+
+
+
+
+
+#endif /* __CSSREADER_H__ */
+//#########################################################################
+//# E N D    O F    F I L E
+//#########################################################################
+
diff --git a/src/dom/svgparser.cpp b/src/dom/svgparser.cpp
deleted file mode 100644 (file)
index 956112c..0000000
+++ /dev/null
@@ -1,805 +0,0 @@
-/**
- * Phoebe DOM Implementation.
- *
- * This is a C++ approximation of the W3C DOM model, which follows
- * fairly closely the specifications in the various .idl files, copies of
- * which are provided for reference.  Most important is this one:
- *
- * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html
- *
- * Authors:
- *   Bob Jamison
- *
- * Copyright (C) 2005-2008 Bob Jamison
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *  
- * =======================================================================
- * NOTES
- * 
- *      
- */
-
-
-#include "svgparser.h"
-#include "dom/cssparser.h"
-#include "dom/ucd.h"
-#include "xmlreader.h"
-
-#include <stdarg.h>
-
-#define SVG_NAMESPACE "http://www.w3.org/2000/svg"
-
-namespace org
-{
-namespace w3c
-{
-namespace dom
-{
-namespace svg
-{
-
-
-//#########################################################################
-//# M E S S A G E S
-//#########################################################################
-
-
-/**
- *
- */
-void SvgReader::error(char const *fmt, ...)
-{
-    va_list args;
-    fprintf(stderr, "SvgReader:error:");
-    va_start(args, fmt);
-    vfprintf(stderr, fmt, args);
-    va_end(args) ;
-    fprintf(stderr, "\n");
-}
-
-
-
-//#########################################################################
-//# P A R S I N G
-//#########################################################################
-
-/**
- *  Get the character at the position and record the fact
- */
-XMLCh SvgReader::get(int p)
-{
-    if (p >= parselen)
-        return 0;
-    XMLCh ch = parsebuf[p];
-    //printf("%c", ch);
-    lastPosition = p;
-    return ch;
-}
-
-
-
-/**
- *  Test if the given substring exists at the given position
- *  in parsebuf.  Use get() in case of out-of-bounds
- */
-bool SvgReader::match(int pos, char const *str)
-{
-    while (*str)
-       {
-       if (get(pos++) != (XMLCh) *str++)
-           return false;
-       }
-   return true;
-}
-
-/**
- *
- */
-int SvgReader::skipwhite(int p)
-{
-  while (p < parselen)
-    {
-    //# XML COMMENT
-    if (match(p, "<!--"))
-        {
-        p+=4;
-        bool done=false;
-        while (p<parselen)
-            {
-            if (match(p, "-->"))
-                {
-                p+=3;
-                done=true;
-                break;
-                }
-            p++;
-            }
-        lastPosition = p;
-        if (!done)
-            {
-            error("unterminated <!-- .. --> comment");
-            return -1;
-            }
-        }
-    //# C comment
-    else if (match(p, "/*"))
-        {
-        p+=2;
-        bool done=false;
-        while (p<parselen)
-            {
-            if (match(p, "*/"))
-                {
-                p+=2;
-                done=true;
-                break;
-                }
-            p++;
-            }
-        lastPosition = p;
-        if (!done)
-            {
-            error("unterminated /* .. */ comment");
-            return -1;
-            }
-        }
-    else if (!uni_is_space(get(p)))
-        break;
-    else
-        p++;
-    }
-  lastPosition = p;
-  return p;
-}
-
-/**
- * get a word from the buffer
- */
-int SvgReader::getWord(int p, DOMString &result)
-{
-    XMLCh ch = get(p);
-    if (!uni_is_letter(ch))
-        return p;
-    DOMString str;
-    str.push_back(ch);
-    p++;
-
-    while (p < parselen)
-        {
-        ch = get(p);
-        if (uni_is_letter_or_digit(ch) || ch=='-' || ch=='_')
-            {
-            str.push_back(ch);
-            p++;
-            }
-        else if (ch == '\\')
-            {
-            p+=2;
-            }
-        else
-            break;
-        }
-    result = str;
-    return p;
-}
-
-
-# if 0
-/**
- * get a word from the buffer
- */
-int SvgReader::getNumber(int p0, double &result)
-{
-    int p=p0;
-
-    DOMString str;
-
-    //allow sign
-    if (get(p) == '-')
-        {
-        p++;
-        }
-
-    while (p < parselen)
-        {
-        XMLCh ch = get(p);
-        if (ch<'0' || ch>'9')
-            break;
-        str.push_back(ch);
-        p++;
-        }
-    if (get(p) == '.' && get(p+1)>='0' && get(p+1)<='9')
-        {
-        p++;
-        str.push_back('.');
-        while (p < parselen)
-            {
-            XMLCh ch = get(p);
-            if (ch<'0' || ch>'9')
-                break;
-            str.push_back(ch);
-            p++;
-            }
-        }
-    if (p>p0)
-        {
-        char *start = (char *)str.c_str();
-        char *end   = NULL;
-        double val = strtod(start, &end);
-        if (end > start)
-            {
-            result = val;
-            return p;
-            }
-        }
-
-    //not a number
-    return p0;
-}
-#endif
-
-
-/**
- * get a word from the buffer
- */
-int SvgReader::getNumber(int p0, double &result)
-{
-    int p=p0;
-
-    char buf[64];
-
-    int i;
-    for (i=0 ; i<63 && p<parselen ; i++)
-        {
-        buf[i] = (char) get(p++);
-        }
-    buf[i] = '\0';
-
-    char *start = buf;
-    char *end   = NULL;
-    double val = strtod(start, &end);
-    if (end > start)
-        {
-        result = val;
-        int count = (int)(end - start);
-        p = p0 + count;
-        return p;
-        }
-
-    //not a number
-    return p0;
-}
-
-
-bool SvgReader::parseTransform(const DOMString &str)
-{
-    parsebuf = str;
-    parselen = str.size();
-
-    //printf("transform:%s\n", str.c_str());
-
-    SVGTransformList transformList;
-
-    int p = 0;
-
-    while (p < parselen)
-        {
-        p = skipwhite(p);
-        DOMString name;
-        int p2 = getWord(p, name);
-        if (p2<0)
-            return false;
-        if (p2<=p)
-            {
-            error("transform: need transform name");
-            //return false;
-            break;
-            }
-        p = p2;
-        //printf("transform name:%s\n", name.c_str());
-
-        //######### MATRIX
-        if (name == "matrix")
-            {
-            p = skipwhite(p);
-            if (get(p++) != '(')
-                {
-                error("matrix transform needs opening '('");
-                return false;
-                }
-            int nrVals = 0;
-            double vals[6];
-            bool seenBrace = false;
-            while (p < parselen && nrVals < 6)
-                {
-                p = skipwhite(p);
-                double val = 0.0;
-                p2 = getNumber(p, val);
-                if (p2<0)
-                    return false;
-                if (p2<=p)
-                    {
-                    error("matrix() expected number");
-                    return false;
-                    }
-                vals[nrVals++] = val;
-                p = skipwhite(p2);
-                XMLCh ch = get(p);
-                if (ch == ',')
-                    {
-                    p++;
-                    p = skipwhite(p);
-                    ch = get(p);
-                    }
-                if (ch == ')')
-                    {
-                    seenBrace = true;
-                    p++;
-                    break;
-                    }
-                }
-            if (!seenBrace)
-                {
-                error("matrix() needs closing brace");
-                return false;
-                }
-            if (nrVals != 6)
-                {
-                error("matrix() requires exactly 6 arguments");
-                return false;
-                }
-            //We got our arguments
-            //printf("translate: %f %f %f %f %f %f\n",
-            //      vals[0], vals[1], vals[2], vals[3], vals[4], vals[5]);
-            SVGMatrix matrix(vals[0], vals[1], vals[2],
-                             vals[3], vals[4], vals[5]);
-            SVGTransform transform;
-            transform.setMatrix(matrix);
-            transformList.appendItem(transform);
-            }
-
-        //######### TRANSLATE
-        else if (name == "translate")
-            {
-            p = skipwhite(p);
-            if (get(p++) != '(')
-                {
-                error("matrix transform needs opening '('");
-                return false;
-                }
-            p = skipwhite(p);
-            double x = 0.0;
-            p2 = getNumber(p, x);
-            if (p2<0)
-                return false;
-            if (p2<=p)
-                {
-                error("translate() expected 'x' value");
-                return false;
-                }
-            p = skipwhite(p2);
-            if (get(p) == ',')
-                {
-                p++;
-                p = skipwhite(p);
-                }
-            double y = 0.0;
-            p2 = getNumber(p, y);
-            if (p2<0)
-                return false;
-            if (p2<=p) //no y specified. use default
-                y = 0.0;
-            p = skipwhite(p2);
-            if (get(p++) != ')')
-                {
-                error("translate() needs closing ')'");
-                return false;
-                }
-            //printf("translate: %f %f\n", x, y);
-            SVGTransform transform;
-            transform.setTranslate(x, y);
-            transformList.appendItem(transform);
-            }
-
-        //######### SCALE
-        else if (name == "scale")
-            {
-            p = skipwhite(p);
-            if (get(p++) != '(')
-                {
-                error("scale transform needs opening '('");
-                return false;
-                }
-            p = skipwhite(p);
-            double x = 0.0;
-            p2 = getNumber(p, x);
-            if (p2<0)
-                return false;
-            if (p2<=p)
-                {
-                error("scale() expected 'x' value");
-                return false;
-                }
-            p = skipwhite(p2);
-            if (get(p) == ',')
-                {
-                p++;
-                p = skipwhite(p);
-                }
-            double y = 0.0;
-            p2 = getNumber(p, y);
-            if (p2<0)
-                return false;
-            if (p2<=p) //no y specified. use default
-                y = x; // y is same as x.  uniform scaling
-            p = skipwhite(p2);
-            if (get(p++) != ')')
-                {
-                error("scale() needs closing ')'");
-                return false;
-                }
-            //printf("scale: %f %f\n", x, y);
-            SVGTransform transform;
-            transform.setScale(x, y);
-            transformList.appendItem(transform);
-            }
-
-        //######### ROTATE
-        else if (name == "rotate")
-            {
-            p = skipwhite(p);
-            if (get(p++) != '(')
-                {
-                error("rotate transform needs opening '('");
-                return false;
-                }
-            p = skipwhite(p);
-            double angle = 0.0;
-            p2 = getNumber(p, angle);
-            if (p2<0)
-                return false;
-            if (p2<=p)
-                {
-                error("rotate() expected 'angle' value");
-                return false;
-                }
-            p = skipwhite(p2);
-            if (get(p) == ',')
-                {
-                p++;
-                p = skipwhite(p);
-                }
-            double cx = 0.0;
-            double cy = 0.0;
-            p2 = getNumber(p, cx);
-            if (p2>p)
-                {
-                p = skipwhite(p2);
-                if (get(p) == ',')
-                    {
-                    p++;
-                    p = skipwhite(p);
-                    }
-                p2 = getNumber(p, cy);
-                if (p2<0)
-                    return false;
-                if (p2<=p)
-                    {
-                    error("rotate() arguments should be either rotate(angle) or rotate(angle, cx, cy)");
-                    return false;
-                    }
-                p = skipwhite(p2);
-                }
-            if (get(p++) != ')')
-                {
-                error("rotate() needs closing ')'");
-                return false;
-                }
-            //printf("rotate: %f %f %f\n", angle, cx, cy);
-            SVGTransform transform;
-            transform.setRotate(angle, cx, cy);
-            transformList.appendItem(transform);
-            }
-
-        //######### SKEWX
-        else if (name == "skewX")
-            {
-            p = skipwhite(p);
-            if (get(p++) != '(')
-                {
-                error("skewX transform needs opening '('");
-                return false;
-                }
-            p = skipwhite(p);
-            double x = 0.0;
-            p2 = getNumber(p, x);
-            if (p2<0)
-                return false;
-            if (p2<=p)
-                {
-                error("skewX() expected 'x' value");
-                return false;
-                }
-            p = skipwhite(p2);
-            if (get(p++) != ')')
-                {
-                error("skewX() needs closing ')'");
-                return false;
-                }
-            //printf("skewX: %f\n", x);
-            SVGTransform transform;
-            transform.setSkewX(x);
-            transformList.appendItem(transform);
-            }
-
-        //######### SKEWY
-        else if (name == "skewY")
-            {
-            p = skipwhite(p);
-            if (get(p++) != '(')
-                {
-                error("skewY transform needs opening '('");
-                return false;
-                }
-            p = skipwhite(p);
-            double y = 0.0;
-            p2 = getNumber(p, y);
-            if (p2<0)
-                return false;
-            if (p2<=p)
-                {
-                error("skewY() expected 'y' value");
-                return false;
-                }
-            p = skipwhite(p2);
-            if (get(p++) != ')')
-                {
-                error("skewY() needs closing ')'");
-                return false;
-                }
-            //printf("skewY: %f\n", y);
-            SVGTransform transform;
-            transform.setSkewY(y);
-            transformList.appendItem(transform);
-            }
-
-        //### NONE OF THE ABOVE
-        else
-            {
-            error("unknown transform type:'%s'", name.c_str());
-            }
-
-        p = skipwhite(p);
-        XMLCh ch = get(p);
-        if (ch == ',')
-            {
-            p++;
-            p = skipwhite(p);
-            }
-
-        }//WHILE p<parselen
-
-    return true;
-}
-
-
-/**
- *
- */
-bool SvgReader::parseElement(SVGElementImplPtr parent,
-                             ElementImplPtr sourceElem)
-{
-    if (!parent || !sourceElem)
-        {
-        error("NULL source element");
-        return false;
-        }
-
-    DOMString namespaceURI = sourceElem->getNamespaceURI();
-    //printf("namespaceURI:%s\n", namespaceURI.c_str());
-    DOMString tagName      = sourceElem->getTagName();
-    printf("tag name:%s\n", tagName.c_str());
-
-    ElementImplPtr newElement = NULL;
-    if (namespaceURI != SVG_NAMESPACE)
-        {
-        newElement = new SVGSVGElementImpl();
-        newElement->assign(*sourceElem);
-        parent->appendChild(newElement);
-        }
-    else //## SVG!!
-        {
-
-        //####################################################
-        //## ATTRIBUTES
-        //####################################################
-        DOMString style = sourceElem->getAttribute("style");
-        if (style.size() > 0)
-            {
-            css::CssParser parser;
-            style.insert(0, "{");
-            style.append("}");
-            //printf("CSS:%s\n", style.c_str());
-            if (!parser.parse(style))
-                {
-                error("parsing style attribute");
-                }
-            else
-                {
-                //printf("##parsed!\n");
-                }
-            }
-
-        DOMString transform = sourceElem->getAttribute("transform");
-        if (transform.size() > 0)
-            {
-            if (!parseTransform(transform))
-                {
-                error("parsing transform attribute");
-                }
-            else
-                {
-                //printf("##parsed!\n");
-                }
-            }
-
-        //####################################################
-        //## ELEMENT - SPECIFIC
-        //####################################################
-        if (tagName == "svg")
-            {
-            newElement = new SVGSVGElementImpl();
-            newElement->assign(*sourceElem);
-            parent->appendChild(newElement);
-            }
-        else if (tagName == "title")
-            {
-            newElement = new SVGTitleElementImpl();
-            newElement->assign(*sourceElem);
-            parent->appendChild(newElement);
-            }
-        else if (tagName == "desc")
-            {
-            newElement = new SVGDescElementImpl();
-            newElement->assign(*sourceElem);
-            parent->appendChild(newElement);
-            }
-        else if (tagName == "defs")
-            {
-            newElement = new SVGDefsElementImpl();
-            newElement->assign(*sourceElem);
-            parent->appendChild(newElement);
-            }
-        else if (tagName == "style")
-            {
-            newElement = new SVGStyleElementImpl();
-            newElement->assign(*sourceElem);
-            parent->appendChild(newElement);
-            }
-        else if (tagName == "g")
-            {
-            newElement = new SVGGElementImpl();
-            newElement->assign(*sourceElem);
-            parent->appendChild(newElement);
-            }
-        else if (tagName == "path")
-            {
-            newElement = new SVGPathElementImpl();
-            newElement->assign(*sourceElem);
-            parent->appendChild(newElement);
-            }
-        }
-
-    NodeList children = sourceElem->getChildNodes();
-    int nodeCount = children.getLength();
-    for (int i=0 ; i<nodeCount ; i++)
-        {
-        NodePtr child = children.item(i);
-        int typ = child->getNodeType();
-        if (typ == Node::TEXT_NODE)
-            {
-            NodePtr newNode = doc->createTextNode(child->getNodeValue());
-            parent->appendChild(newNode);
-            }
-        else if (typ == Node::CDATA_SECTION_NODE)
-            {
-            NodePtr newNode = doc->createCDATASection(child->getNodeValue());
-            parent->appendChild(newNode);
-            }
-        else if (newElement.get() && typ == Node::ELEMENT_NODE)
-            {
-            //ElementImplPtr childElement = dynamic_cast<ElementImpl *>(child.get());
-            //parseElement(newElement, childElement);
-            }
-        }
-    return true;
-}
-
-
-/**
- *
- */
-SVGDocumentPtr SvgReader::parse(const DocumentPtr src)
-{
-    if (!src)
-        {
-        error("NULL source document");
-        return NULL;
-        }
-
-    DOMImplementationImpl impl;
-    doc = new SVGDocumentImpl(&impl, SVG_NAMESPACE, "svg" , NULL);
-
-    SVGElementImplPtr destElem = dynamic_cast<SVGElementImpl *>(doc->getRootElement().get());
-    ElementImplPtr    srcElem  = dynamic_cast<ElementImpl *>(src->getDocumentElement().get());
-    if (!parseElement(destElem, srcElem))
-        {
-        return NULL;
-        }
-
-    return doc;
-}
-
-
-
-/**
- *
- */
-SVGDocumentPtr SvgReader::parse(const DOMString &buf)
-{
-    /* remember, smartptrs are null-testable*/
-    SVGDocumentPtr svgdoc;
-    XmlReader parser;
-    DocumentPtr doc = parser.parse(buf);
-    if (!doc)
-        {
-        return svgdoc;
-        }
-    svgdoc = parse(doc);
-    return svgdoc;
-}
-
-
-
-/**
- *
- */
-SVGDocumentPtr SvgReader::parseFile(const DOMString &fileName)
-{
-    /* remember, smartptrs are null-testable*/
-    SVGDocumentPtr svgdoc;
-    XmlReader parser;
-    DocumentPtr doc = parser.parseFile(fileName);
-    if (!doc)
-        {
-        return svgdoc;
-        }
-    svgdoc = parse(doc);
-    return svgdoc;
-}
-
-
-
-
-}  //namespace svg
-}  //namespace dom
-}  //namespace w3c
-}  //namespace org
-
-/*#########################################################################
-## E N D    O F    F I L E
-#########################################################################*/
-
diff --git a/src/dom/svgparser.h b/src/dom/svgparser.h
deleted file mode 100644 (file)
index 8e53fe6..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-#ifndef __SVGPARSER_H__
-#define __SVGPARSER_H__
-
-/**
- * Phoebe DOM Implementation.
- *
- * This is a C++ approximation of the W3C DOM model, which follows
- * fairly closely the specifications in the various .idl files, copies of
- * which are provided for reference.  Most important is this one:
- *
- * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html
- *
- * Authors:
- *   Bob Jamison
- *
- * Copyright (C) 2005-2008 Bob Jamison
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *  
- * =======================================================================
- * NOTES
- * 
- * This parser takes an XML document, as a file, string, or DOM Document,
- * and attempts to parse it as an SVG-DOM  SVGDocument.
- * 
- * Look in svg.h and svgtypes.h for the classes which are the target of this
- * parser.
- * 
- * They loosely follow the specification:
- * http://www.w3.org/TR/SVG11/svgdom.html
- *              
- */
-
-
-#include "svgimpl.h"
-
-namespace org
-{
-namespace w3c
-{
-namespace dom
-{
-namespace svg
-{
-
-
-class SvgReader
-{
-public:
-
-    /**
-     *
-     */
-    SvgReader()
-        {
-        }
-
-    /**
-     *
-     */
-    SvgReader(const SvgReader &/*other*/)
-        {
-        }
-
-    /**
-     *
-     */
-    virtual ~SvgReader()
-        {
-        }
-
-    /**
-     *
-     */
-    SVGDocumentPtr parse(const DocumentPtr /*sourceDoc*/);
-
-    /**
-     *
-     */
-    SVGDocumentPtr parse(const DOMString &/*buffer*/);
-
-    /**
-     *
-     */
-    SVGDocumentPtr parseFile(const DOMString &/*fileName*/);
-
-
-
-
-private:
-
-    /**
-     *  Get the next character in the parse buf,  0 if out
-     *  of range
-     */
-    XMLCh get(int p);
-
-    /**
-     *  Test if the given substring exists at the given position
-     *  in parsebuf.  Use get() in case of out-of-bounds
-     */
-    bool match(int pos, char const *str);
-
-    /**
-     *
-     */
-    int skipwhite(int p);
-
-    /**
-     * get a word from the buffer
-     */
-    int getWord(int p, DOMString &result);
-
-    /**
-     * get a word from the buffer
-     */
-    int getNumber(int p0, double &result);
-
-
-    /**
-     *
-     */
-    bool parseTransform(const DOMString &str);
-
-
-    /**
-     *
-     */
-    bool parseElement(SVGElementImplPtr destElem,
-                      ElementImplPtr sourceElem);
-
-
-    /**
-     *
-     */
-    void error(char const *format, ...)
-    #ifdef G_GNUC_PRINTF
-    G_GNUC_PRINTF(2, 3)
-    #endif
-    ;
-
-
-
-    DOMString parsebuf;
-    int parselen;
-    int lastPosition;
-
-    SVGDocumentImplPtr doc;
-
-};
-
-
-
-
-
-}  //namespace svg
-}  //namespace dom
-}  //namespace w3c
-}  //namespace org
-
-#endif /* __SVGPARSER_H__ */
-/*#########################################################################
-## E N D    O F    F I L E
-#########################################################################*/
-
-
-
diff --git a/src/dom/svgreader.cpp b/src/dom/svgreader.cpp
new file mode 100644 (file)
index 0000000..7ebde97
--- /dev/null
@@ -0,0 +1,805 @@
+/**
+ * Phoebe DOM Implementation.
+ *
+ * This is a C++ approximation of the W3C DOM model, which follows
+ * fairly closely the specifications in the various .idl files, copies of
+ * which are provided for reference.  Most important is this one:
+ *
+ * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html
+ *
+ * Authors:
+ *   Bob Jamison
+ *
+ * Copyright (C) 2005-2008 Bob Jamison
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *  
+ * =======================================================================
+ * NOTES
+ * 
+ *      
+ */
+
+
+#include "svgreader.h"
+#include "dom/cssreader.h"
+#include "dom/ucd.h"
+#include "xmlreader.h"
+
+#include <stdarg.h>
+
+#define SVG_NAMESPACE "http://www.w3.org/2000/svg"
+
+namespace org
+{
+namespace w3c
+{
+namespace dom
+{
+namespace svg
+{
+
+
+//#########################################################################
+//# M E S S A G E S
+//#########################################################################
+
+
+/**
+ *
+ */
+void SvgReader::error(char const *fmt, ...)
+{
+    va_list args;
+    fprintf(stderr, "SvgReader:error:");
+    va_start(args, fmt);
+    vfprintf(stderr, fmt, args);
+    va_end(args) ;
+    fprintf(stderr, "\n");
+}
+
+
+
+//#########################################################################
+//# P A R S I N G
+//#########################################################################
+
+/**
+ *  Get the character at the position and record the fact
+ */
+XMLCh SvgReader::get(int p)
+{
+    if (p >= parselen)
+        return 0;
+    XMLCh ch = parsebuf[p];
+    //printf("%c", ch);
+    lastPosition = p;
+    return ch;
+}
+
+
+
+/**
+ *  Test if the given substring exists at the given position
+ *  in parsebuf.  Use get() in case of out-of-bounds
+ */
+bool SvgReader::match(int pos, char const *str)
+{
+    while (*str)
+       {
+       if (get(pos++) != (XMLCh) *str++)
+           return false;
+       }
+   return true;
+}
+
+/**
+ *
+ */
+int SvgReader::skipwhite(int p)
+{
+  while (p < parselen)
+    {
+    //# XML COMMENT
+    if (match(p, "<!--"))
+        {
+        p+=4;
+        bool done=false;
+        while (p<parselen)
+            {
+            if (match(p, "-->"))
+                {
+                p+=3;
+                done=true;
+                break;
+                }
+            p++;
+            }
+        lastPosition = p;
+        if (!done)
+            {
+            error("unterminated <!-- .. --> comment");
+            return -1;
+            }
+        }
+    //# C comment
+    else if (match(p, "/*"))
+        {
+        p+=2;
+        bool done=false;
+        while (p<parselen)
+            {
+            if (match(p, "*/"))
+                {
+                p+=2;
+                done=true;
+                break;
+                }
+            p++;
+            }
+        lastPosition = p;
+        if (!done)
+            {
+            error("unterminated /* .. */ comment");
+            return -1;
+            }
+        }
+    else if (!uni_is_space(get(p)))
+        break;
+    else
+        p++;
+    }
+  lastPosition = p;
+  return p;
+}
+
+/**
+ * get a word from the buffer
+ */
+int SvgReader::getWord(int p, DOMString &result)
+{
+    XMLCh ch = get(p);
+    if (!uni_is_letter(ch))
+        return p;
+    DOMString str;
+    str.push_back(ch);
+    p++;
+
+    while (p < parselen)
+        {
+        ch = get(p);
+        if (uni_is_letter_or_digit(ch) || ch=='-' || ch=='_')
+            {
+            str.push_back(ch);
+            p++;
+            }
+        else if (ch == '\\')
+            {
+            p+=2;
+            }
+        else
+            break;
+        }
+    result = str;
+    return p;
+}
+
+
+# if 0
+/**
+ * get a word from the buffer
+ */
+int SvgReader::getNumber(int p0, double &result)
+{
+    int p=p0;
+
+    DOMString str;
+
+    //allow sign
+    if (get(p) == '-')
+        {
+        p++;
+        }
+
+    while (p < parselen)
+        {
+        XMLCh ch = get(p);
+        if (ch<'0' || ch>'9')
+            break;
+        str.push_back(ch);
+        p++;
+        }
+    if (get(p) == '.' && get(p+1)>='0' && get(p+1)<='9')
+        {
+        p++;
+        str.push_back('.');
+        while (p < parselen)
+            {
+            XMLCh ch = get(p);
+            if (ch<'0' || ch>'9')
+                break;
+            str.push_back(ch);
+            p++;
+            }
+        }
+    if (p>p0)
+        {
+        char *start = (char *)str.c_str();
+        char *end   = NULL;
+        double val = strtod(start, &end);
+        if (end > start)
+            {
+            result = val;
+            return p;
+            }
+        }
+
+    //not a number
+    return p0;
+}
+#endif
+
+
+/**
+ * get a word from the buffer
+ */
+int SvgReader::getNumber(int p0, double &result)
+{
+    int p=p0;
+
+    char buf[64];
+
+    int i;
+    for (i=0 ; i<63 && p<parselen ; i++)
+        {
+        buf[i] = (char) get(p++);
+        }
+    buf[i] = '\0';
+
+    char *start = buf;
+    char *end   = NULL;
+    double val = strtod(start, &end);
+    if (end > start)
+        {
+        result = val;
+        int count = (int)(end - start);
+        p = p0 + count;
+        return p;
+        }
+
+    //not a number
+    return p0;
+}
+
+
+bool SvgReader::parseTransform(const DOMString &str)
+{
+    parsebuf = str;
+    parselen = str.size();
+
+    //printf("transform:%s\n", str.c_str());
+
+    SVGTransformList transformList;
+
+    int p = 0;
+
+    while (p < parselen)
+        {
+        p = skipwhite(p);
+        DOMString name;
+        int p2 = getWord(p, name);
+        if (p2<0)
+            return false;
+        if (p2<=p)
+            {
+            error("transform: need transform name");
+            //return false;
+            break;
+            }
+        p = p2;
+        //printf("transform name:%s\n", name.c_str());
+
+        //######### MATRIX
+        if (name == "matrix")
+            {
+            p = skipwhite(p);
+            if (get(p++) != '(')
+                {
+                error("matrix transform needs opening '('");
+                return false;
+                }
+            int nrVals = 0;
+            double vals[6];
+            bool seenBrace = false;
+            while (p < parselen && nrVals < 6)
+                {
+                p = skipwhite(p);
+                double val = 0.0;
+                p2 = getNumber(p, val);
+                if (p2<0)
+                    return false;
+                if (p2<=p)
+                    {
+                    error("matrix() expected number");
+                    return false;
+                    }
+                vals[nrVals++] = val;
+                p = skipwhite(p2);
+                XMLCh ch = get(p);
+                if (ch == ',')
+                    {
+                    p++;
+                    p = skipwhite(p);
+                    ch = get(p);
+                    }
+                if (ch == ')')
+                    {
+                    seenBrace = true;
+                    p++;
+                    break;
+                    }
+                }
+            if (!seenBrace)
+                {
+                error("matrix() needs closing brace");
+                return false;
+                }
+            if (nrVals != 6)
+                {
+                error("matrix() requires exactly 6 arguments");
+                return false;
+                }
+            //We got our arguments
+            //printf("translate: %f %f %f %f %f %f\n",
+            //      vals[0], vals[1], vals[2], vals[3], vals[4], vals[5]);
+            SVGMatrix matrix(vals[0], vals[1], vals[2],
+                             vals[3], vals[4], vals[5]);
+            SVGTransform transform;
+            transform.setMatrix(matrix);
+            transformList.appendItem(transform);
+            }
+
+        //######### TRANSLATE
+        else if (name == "translate")
+            {
+            p = skipwhite(p);
+            if (get(p++) != '(')
+                {
+                error("matrix transform needs opening '('");
+                return false;
+                }
+            p = skipwhite(p);
+            double x = 0.0;
+            p2 = getNumber(p, x);
+            if (p2<0)
+                return false;
+            if (p2<=p)
+                {
+                error("translate() expected 'x' value");
+                return false;
+                }
+            p = skipwhite(p2);
+            if (get(p) == ',')
+                {
+                p++;
+                p = skipwhite(p);
+                }
+            double y = 0.0;
+            p2 = getNumber(p, y);
+            if (p2<0)
+                return false;
+            if (p2<=p) //no y specified. use default
+                y = 0.0;
+            p = skipwhite(p2);
+            if (get(p++) != ')')
+                {
+                error("translate() needs closing ')'");
+                return false;
+                }
+            //printf("translate: %f %f\n", x, y);
+            SVGTransform transform;
+            transform.setTranslate(x, y);
+            transformList.appendItem(transform);
+            }
+
+        //######### SCALE
+        else if (name == "scale")
+            {
+            p = skipwhite(p);
+            if (get(p++) != '(')
+                {
+                error("scale transform needs opening '('");
+                return false;
+                }
+            p = skipwhite(p);
+            double x = 0.0;
+            p2 = getNumber(p, x);
+            if (p2<0)
+                return false;
+            if (p2<=p)
+                {
+                error("scale() expected 'x' value");
+                return false;
+                }
+            p = skipwhite(p2);
+            if (get(p) == ',')
+                {
+                p++;
+                p = skipwhite(p);
+                }
+            double y = 0.0;
+            p2 = getNumber(p, y);
+            if (p2<0)
+                return false;
+            if (p2<=p) //no y specified. use default
+                y = x; // y is same as x.  uniform scaling
+            p = skipwhite(p2);
+            if (get(p++) != ')')
+                {
+                error("scale() needs closing ')'");
+                return false;
+                }
+            //printf("scale: %f %f\n", x, y);
+            SVGTransform transform;
+            transform.setScale(x, y);
+            transformList.appendItem(transform);
+            }
+
+        //######### ROTATE
+        else if (name == "rotate")
+            {
+            p = skipwhite(p);
+            if (get(p++) != '(')
+                {
+                error("rotate transform needs opening '('");
+                return false;
+                }
+            p = skipwhite(p);
+            double angle = 0.0;
+            p2 = getNumber(p, angle);
+            if (p2<0)
+                return false;
+            if (p2<=p)
+                {
+                error("rotate() expected 'angle' value");
+                return false;
+                }
+            p = skipwhite(p2);
+            if (get(p) == ',')
+                {
+                p++;
+                p = skipwhite(p);
+                }
+            double cx = 0.0;
+            double cy = 0.0;
+            p2 = getNumber(p, cx);
+            if (p2>p)
+                {
+                p = skipwhite(p2);
+                if (get(p) == ',')
+                    {
+                    p++;
+                    p = skipwhite(p);
+                    }
+                p2 = getNumber(p, cy);
+                if (p2<0)
+                    return false;
+                if (p2<=p)
+                    {
+                    error("rotate() arguments should be either rotate(angle) or rotate(angle, cx, cy)");
+                    return false;
+                    }
+                p = skipwhite(p2);
+                }
+            if (get(p++) != ')')
+                {
+                error("rotate() needs closing ')'");
+                return false;
+                }
+            //printf("rotate: %f %f %f\n", angle, cx, cy);
+            SVGTransform transform;
+            transform.setRotate(angle, cx, cy);
+            transformList.appendItem(transform);
+            }
+
+        //######### SKEWX
+        else if (name == "skewX")
+            {
+            p = skipwhite(p);
+            if (get(p++) != '(')
+                {
+                error("skewX transform needs opening '('");
+                return false;
+                }
+            p = skipwhite(p);
+            double x = 0.0;
+            p2 = getNumber(p, x);
+            if (p2<0)
+                return false;
+            if (p2<=p)
+                {
+                error("skewX() expected 'x' value");
+                return false;
+                }
+            p = skipwhite(p2);
+            if (get(p++) != ')')
+                {
+                error("skewX() needs closing ')'");
+                return false;
+                }
+            //printf("skewX: %f\n", x);
+            SVGTransform transform;
+            transform.setSkewX(x);
+            transformList.appendItem(transform);
+            }
+
+        //######### SKEWY
+        else if (name == "skewY")
+            {
+            p = skipwhite(p);
+            if (get(p++) != '(')
+                {
+                error("skewY transform needs opening '('");
+                return false;
+                }
+            p = skipwhite(p);
+            double y = 0.0;
+            p2 = getNumber(p, y);
+            if (p2<0)
+                return false;
+            if (p2<=p)
+                {
+                error("skewY() expected 'y' value");
+                return false;
+                }
+            p = skipwhite(p2);
+            if (get(p++) != ')')
+                {
+                error("skewY() needs closing ')'");
+                return false;
+                }
+            //printf("skewY: %f\n", y);
+            SVGTransform transform;
+            transform.setSkewY(y);
+            transformList.appendItem(transform);
+            }
+
+        //### NONE OF THE ABOVE
+        else
+            {
+            error("unknown transform type:'%s'", name.c_str());
+            }
+
+        p = skipwhite(p);
+        XMLCh ch = get(p);
+        if (ch == ',')
+            {
+            p++;
+            p = skipwhite(p);
+            }
+
+        }//WHILE p<parselen
+
+    return true;
+}
+
+
+/**
+ *
+ */
+bool SvgReader::parseElement(SVGElementImplPtr parent,
+                             ElementImplPtr sourceElem)
+{
+    if (!parent || !sourceElem)
+        {
+        error("NULL source element");
+        return false;
+        }
+
+    DOMString namespaceURI = sourceElem->getNamespaceURI();
+    //printf("namespaceURI:%s\n", namespaceURI.c_str());
+    DOMString tagName      = sourceElem->getTagName();
+    printf("tag name:%s\n", tagName.c_str());
+
+    ElementImplPtr newElement = NULL;
+    if (namespaceURI != SVG_NAMESPACE)
+        {
+        newElement = new SVGSVGElementImpl();
+        newElement->assign(*sourceElem);
+        parent->appendChild(newElement);
+        }
+    else //## SVG!!
+        {
+
+        //####################################################
+        //## ATTRIBUTES
+        //####################################################
+        DOMString style = sourceElem->getAttribute("style");
+        if (style.size() > 0)
+            {
+            css::CssParser parser;
+            style.insert(0, "{");
+            style.append("}");
+            //printf("CSS:%s\n", style.c_str());
+            if (!parser.parse(style))
+                {
+                error("parsing style attribute");
+                }
+            else
+                {
+                //printf("##parsed!\n");
+                }
+            }
+
+        DOMString transform = sourceElem->getAttribute("transform");
+        if (transform.size() > 0)
+            {
+            if (!parseTransform(transform))
+                {
+                error("parsing transform attribute");
+                }
+            else
+                {
+                //printf("##parsed!\n");
+                }
+            }
+
+        //####################################################
+        //## ELEMENT - SPECIFIC
+        //####################################################
+        if (tagName == "svg")
+            {
+            newElement = new SVGSVGElementImpl();
+            newElement->assign(*sourceElem);
+            parent->appendChild(newElement);
+            }
+        else if (tagName == "title")
+            {
+            newElement = new SVGTitleElementImpl();
+            newElement->assign(*sourceElem);
+            parent->appendChild(newElement);
+            }
+        else if (tagName == "desc")
+            {
+            newElement = new SVGDescElementImpl();
+            newElement->assign(*sourceElem);
+            parent->appendChild(newElement);
+            }
+        else if (tagName == "defs")
+            {
+            newElement = new SVGDefsElementImpl();
+            newElement->assign(*sourceElem);
+            parent->appendChild(newElement);
+            }
+        else if (tagName == "style")
+            {
+            newElement = new SVGStyleElementImpl();
+            newElement->assign(*sourceElem);
+            parent->appendChild(newElement);
+            }
+        else if (tagName == "g")
+            {
+            newElement = new SVGGElementImpl();
+            newElement->assign(*sourceElem);
+            parent->appendChild(newElement);
+            }
+        else if (tagName == "path")
+            {
+            newElement = new SVGPathElementImpl();
+            newElement->assign(*sourceElem);
+            parent->appendChild(newElement);
+            }
+        }
+
+    NodeList children = sourceElem->getChildNodes();
+    int nodeCount = children.getLength();
+    for (int i=0 ; i<nodeCount ; i++)
+        {
+        NodePtr child = children.item(i);
+        int typ = child->getNodeType();
+        if (typ == Node::TEXT_NODE)
+            {
+            NodePtr newNode = doc->createTextNode(child->getNodeValue());
+            parent->appendChild(newNode);
+            }
+        else if (typ == Node::CDATA_SECTION_NODE)
+            {
+            NodePtr newNode = doc->createCDATASection(child->getNodeValue());
+            parent->appendChild(newNode);
+            }
+        else if (newElement.get() && typ == Node::ELEMENT_NODE)
+            {
+            //ElementImplPtr childElement = dynamic_cast<ElementImpl *>(child.get());
+            //parseElement(newElement, childElement);
+            }
+        }
+    return true;
+}
+
+
+/**
+ *
+ */
+SVGDocumentPtr SvgReader::parse(const DocumentPtr src)
+{
+    if (!src)
+        {
+        error("NULL source document");
+        return NULL;
+        }
+
+    DOMImplementationImpl impl;
+    doc = new SVGDocumentImpl(&impl, SVG_NAMESPACE, "svg" , NULL);
+
+    SVGElementImplPtr destElem = dynamic_cast<SVGElementImpl *>(doc->getRootElement().get());
+    ElementImplPtr    srcElem  = dynamic_cast<ElementImpl *>(src->getDocumentElement().get());
+    if (!parseElement(destElem, srcElem))
+        {
+        return NULL;
+        }
+
+    return doc;
+}
+
+
+
+/**
+ *
+ */
+SVGDocumentPtr SvgReader::parse(const DOMString &buf)
+{
+    /* remember, smartptrs are null-testable*/
+    SVGDocumentPtr svgdoc;
+    XmlReader parser;
+    DocumentPtr doc = parser.parse(buf);
+    if (!doc)
+        {
+        return svgdoc;
+        }
+    svgdoc = parse(doc);
+    return svgdoc;
+}
+
+
+
+/**
+ *
+ */
+SVGDocumentPtr SvgReader::parseFile(const DOMString &fileName)
+{
+    /* remember, smartptrs are null-testable*/
+    SVGDocumentPtr svgdoc;
+    XmlReader parser;
+    DocumentPtr doc = parser.parseFile(fileName);
+    if (!doc)
+        {
+        return svgdoc;
+        }
+    svgdoc = parse(doc);
+    return svgdoc;
+}
+
+
+
+
+}  //namespace svg
+}  //namespace dom
+}  //namespace w3c
+}  //namespace org
+
+/*#########################################################################
+## E N D    O F    F I L E
+#########################################################################*/
+
diff --git a/src/dom/svgreader.h b/src/dom/svgreader.h
new file mode 100644 (file)
index 0000000..cfc4128
--- /dev/null
@@ -0,0 +1,179 @@
+#ifndef __SVGREADER_H__
+#define __SVGREADER_H__
+
+/**
+ * Phoebe DOM Implementation.
+ *
+ * This is a C++ approximation of the W3C DOM model, which follows
+ * fairly closely the specifications in the various .idl files, copies of
+ * which are provided for reference.  Most important is this one:
+ *
+ * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html
+ *
+ * Authors:
+ *   Bob Jamison
+ *
+ * Copyright (C) 2005-2008 Bob Jamison
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *  
+ * =======================================================================
+ * NOTES
+ * 
+ * This parser takes an XML document, as a file, string, or DOM Document,
+ * and attempts to parse it as an SVG-DOM  SVGDocument.
+ * 
+ * Look in svg.h and svgtypes.h for the classes which are the target of this
+ * parser.
+ * 
+ * They loosely follow the specification:
+ * http://www.w3.org/TR/SVG11/svgdom.html
+ *              
+ */
+
+
+#include "svgimpl.h"
+
+namespace org
+{
+namespace w3c
+{
+namespace dom
+{
+namespace svg
+{
+
+
+class SvgReader
+{
+public:
+
+    /**
+     *
+     */
+    SvgReader()
+        {
+        }
+
+    /**
+     *
+     */
+    SvgReader(const SvgReader &/*other*/)
+        {
+        }
+
+    /**
+     *
+     */
+    virtual ~SvgReader()
+        {
+        }
+
+    /**
+     *
+     */
+    SVGDocumentPtr parse(const DocumentPtr /*sourceDoc*/);
+
+    /**
+     *
+     */
+    SVGDocumentPtr parse(const DOMString &/*buffer*/);
+
+    /**
+     *
+     */
+    SVGDocumentPtr parseFile(const DOMString &/*fileName*/);
+
+
+
+
+private:
+
+    /**
+     *  Get the next character in the parse buf,  0 if out
+     *  of range
+     */
+    XMLCh get(int p);
+
+    /**
+     *  Test if the given substring exists at the given position
+     *  in parsebuf.  Use get() in case of out-of-bounds
+     */
+    bool match(int pos, char const *str);
+
+    /**
+     *
+     */
+    int skipwhite(int p);
+
+    /**
+     * get a word from the buffer
+     */
+    int getWord(int p, DOMString &result);
+
+    /**
+     * get a word from the buffer
+     */
+    int getNumber(int p0, double &result);
+
+
+    /**
+     *
+     */
+    bool parseTransform(const DOMString &str);
+
+
+    /**
+     *
+     */
+    bool parseElement(SVGElementImplPtr destElem,
+                      ElementImplPtr sourceElem);
+
+
+    /**
+     *
+     */
+    void error(char const *format, ...)
+    #ifdef G_GNUC_PRINTF
+    G_GNUC_PRINTF(2, 3)
+    #endif
+    ;
+
+
+
+    DOMString parsebuf;
+    int parselen;
+    int lastPosition;
+
+    SVGDocumentImplPtr doc;
+
+};
+
+
+
+
+
+}  //namespace svg
+}  //namespace dom
+}  //namespace w3c
+}  //namespace org
+
+#endif /* __SVGREADER_H__ */
+/*#########################################################################
+## E N D    O F    F I L E
+#########################################################################*/
+
+
+