示例#1
0
const CssSelector *CssPullParser::NextSelector()
{
    if (!currSel)
        return nullptr;
    SkipWsAndComments(currSel, selEnd);
    if (currSel == selEnd)
        return nullptr;

    sel.s = currSel;
    // skip single selector
    const char *sEnd = currSel;
    while (currSel < selEnd && *currSel != ',') {
        if (*currSel == '"' || *currSel == '\'') {
            bool ok = SkipQuotedString(currSel, selEnd);
            CrashIf(!ok);
            sEnd = currSel;
        }
        else if (*currSel == '\\' && currSel < selEnd - 1) {
            currSel += 2;
            sEnd = currSel;
        }
        else if (!SkipWsAndComments(currSel, selEnd)) {
            sEnd = ++currSel;
        }
    }
    if (currSel < selEnd)
        currSel++;

    sel.sLen = sEnd - sel.s;
    sel.tag = Tag_NotFound;
    sel.clazz = nullptr;
    sel.clazzLen = 0;

    // parse "*", "el", ".class" and "el.class"
    const char *c = sEnd;
    for (; c > sel.s && (isalnum((unsigned char)*(c - 1)) || *(c - 1) == '-'); c--);
    if (c > sel.s && *(c - 1) == '.') {
        sel.clazz = c;
        sel.clazzLen = sEnd - c;
        c--;
    }
    for (; c > sel.s && (isalnum((unsigned char)*(c - 1)) || *(c - 1) == '-'); c--);
    if (sel.clazz - 1 == sel.s) {
        sel.tag = Tag_Any;
    }
    else if (c == (sel.clazz ? sel.clazz - 1 : sEnd) && c == sel.s + 1 && *sel.s == '*') {
        sel.tag = Tag_Any;
    }
    else if (c == sel.s) {
        sel.tag = FindHtmlTag(sel.s, sel.clazz ? sel.clazz - sel.s - 1 : sel.sLen);
    }

    return &sel;
}
示例#2
0
bool CssPullParser::NextRule()
{
    if (inProps)
        while (NextProperty());
    CrashIf(inProps && currPos < end);
    if (inlineStyle || currPos == end)
        return false;

    if (currPos == s) {
        SkipWsAndComments(currPos, end);
        if (currPos + 4 < end && str::StartsWith(currPos, "<!--"))
            currPos += 4;
    }

    SkipWsAndComments(currPos, end);
    currSel = currPos;
    // skip selectors
    while (currPos < end && *currPos != '{') {
        if (*currPos == '"' || *currPos == '\'') {
            if (!SkipQuotedString(currPos, end))
                break;
        }
        else if (*currPos == ';') {
            currPos++;
            SkipWsAndComments(currPos, end);
            currSel = currPos;
        }
        else if (!SkipWsAndComments(currPos, end)) {
            currPos++;
        }
    }

    if (currPos == end) {
        currSel = nullptr;
        return false;
    }
    selEnd = currPos++;
    inProps = true;
    return true;
}
示例#3
0
static bool SkipBlock(const char*& s, const char *end)
{
    CrashIf(s >= end || *s != '{');
    s++;
    while (s < end && *s != '}') {
        if (*s == '"' || *s == '\'') {
            if (!SkipQuotedString(s, end))
                return false;
        }
        else if (*s == '{') {
            if (!SkipBlock(s, end))
                return false;
        }
        else if (*s == '\\' && s < end - 1)
            s += 2;
        else if (!SkipWsAndComments(s, end))
            s++;
    }
    if (s == end)
        return false;
    s++;
    return true;
}
static SquareTreeNode *ParseSquareTreeRec(char *& data, bool isTopLevel=false)
{
    SquareTreeNode *node = new SquareTreeNode();

    while (*(data = SkipWsAndComments(data))) {
        // all non-empty non-comment lines contain a key-value pair
        // where the value is either a string (separated by '=' or ':')
        // or a list of child nodes (if the key is followed by '[' alone)
        char *key = data;
        for (data = key; *data && *data != '=' && *data != ':' && *data != '[' && *data != ']' && *data != '\n'; data++);
        if (!*data || '\n' == *data) {
            // use first whitespace as a fallback separator
            for (data = key; *data && !str::IsWs(*data); data++);
        }
        char *separator = data;
        if (*data && *data != '\n') {
            // skip to the first non-whitespace character on the same line (value)
            data = SkipWs(data + 1, true);
        }
        char *value = data;
        // skip to the end of the line
        for (; *data && *data != '\n'; data++);
        if (IsBracketLine(separator) ||
            // also tolerate "key \n [ \n ... \n ]" (else the key
            // gets an empty value and the child node an empty key)
            str::IsWs(*separator) && '\n' == *value && IsBracketLine(SkipWsAndComments(data))) {
            // parse child node(s)
            data = SkipWsAndComments(separator) + 1;
            *SkipWsRev(key, separator) = '\0';
            node->data.Append(SquareTreeNode::DataItem(key, ParseSquareTreeRec(data)));
            // arrays are created by either reusing the same key for a different child
            // or by concatenating multiple children ("[ \n ] [ \n ] [ \n ]")
            while (IsBracketLine((data = SkipWsAndComments(data)))) {
                data++;
                node->data.Append(SquareTreeNode::DataItem(key, ParseSquareTreeRec(data)));
            }
        }
        else if (']' == *key) {
            // finish parsing child node
            data = key + 1;
            if (!isTopLevel)
                return node;
            // ignore superfluous closing square brackets instead of
            // ignoring all content following them
        }
        else if ('[' == *key && ']' == SkipWsRev(value, data)[-1]) {
            // treat INI section headers as top-level node names
            // (else "[Section]" would be ignored)
            if (!isTopLevel) {
                data = key;
                return node;
            }
            // trim whitespace around section name (for consistency with GetPrivateProfileString)
            key = SkipWs(key + 1);
            *SkipWsRev(key, SkipWsRev(value, data) - 1) = '\0';
            node->data.Append(SquareTreeNode::DataItem(key, ParseSquareTreeRec(data)));
        }
        else if ('[' == *separator || ']' == *separator) {
            // invalid line (ignored)
        }
        else {
            // string value (decoding is left to the consumer)
            bool hasMoreLines = '\n' == *data;
            *SkipWsRev(key, separator) = '\0';
            *SkipWsRev(value, data) = '\0';
            node->data.Append(SquareTreeNode::DataItem(key, value));
            if (hasMoreLines)
                data++;
        }
    }

    // assume that all square brackets have been properly balanced
    return node;
}
示例#5
0
const CssProperty *CssPullParser::NextProperty()
{
    if (currPos == s)
        inlineStyle = inProps = true;
    else if (!inProps)
        return nullptr;

GetNextProperty:
    SkipWsAndComments(currPos, end);
    if (currPos == end)
        return nullptr;
    if (*currPos == '}') {
        currPos++;
        inProps = false;
        return nullptr;
    }
    if (*currPos == '{') {
        if (!SkipBlock(currPos, end))
            return nullptr;
        goto GetNextProperty;
    }
    if (*currPos == ';') {
        currPos++;
        goto GetNextProperty;
    }
    const char *name = currPos;
    // skip identifier
    while (currPos < end && !str::IsWs(*currPos) && *currPos != ':' &&
        *currPos != ';' && *currPos != '{' && *currPos != '}') {
        currPos++;
    }
    SkipWsAndComments(currPos, end);
    if (currPos == end || *currPos != ':')
        goto GetNextProperty;
    prop.type = FindCssProp(name, currPos - name);
    currPos++;
    SkipWsAndComments(currPos, end);

    prop.s = currPos;
    // skip value
    const char *valEnd = currPos;
    while (currPos < end && *currPos != ';' && *currPos != '}') {
        if (*currPos == '"' || *currPos == '\'') {
            if (!SkipQuotedString(currPos, end))
                return nullptr;
            valEnd = currPos;
        }
        else if (*currPos == '{') {
            if (!SkipBlock(currPos, end))
                return nullptr;
            valEnd = currPos;
        }
        else if (*currPos == '\\' && currPos < end - 1) {
            currPos += 2;
            valEnd = currPos;
        }
        else if (!SkipWsAndComments(currPos, end)) {
            valEnd = ++currPos;
        }
    }
    prop.sLen = valEnd - prop.s;

    return &prop;
}