aboutsummaryrefslogtreecommitdiff
path: root/src/XpathParser.c
blob: 24e1d6e2fe09278c1f90ace0203a7c74a7e0edf8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include "../include/quickmedia/XpathParser.h"
#include "../include/quickmedia/XpathTokenizer.h"
#include <stdlib.h>

typedef struct {
    QuickMediaXpathTokenizer tokenizer;
} QuickMediaXpathParser;

static void quickmedia_xpath_parser_init(QuickMediaXpathParser *self, const char *xpath) {
    quickmedia_xpath_tokenizer_init(&self->tokenizer, xpath);
}

/*   ('[' IDENTIFIER '=' '"' STRING '"' ']')?   */
static int xpath_parse_param(QuickMediaXpathParser *self, QuickMediaNodeSearchParam *result) {
    if(quickmedia_xpath_tokenizer_next_if(&self->tokenizer, QUICKMEDIA_XPATH_TOKEN_OPEN_BRACKET) != 0)
        return 1;

    QuickMediaXpathToken token = quickmedia_xpath_tokenizer_next(&self->tokenizer);
    if(token != QUICKMEDIA_XPATH_TOKEN_IDENTIFIER)
        return -1;
    
    result->name = quickmedia_xpath_tokenizer_copy_identifier(&self->tokenizer);

    token = quickmedia_xpath_tokenizer_next(&self->tokenizer);
    if(token != QUICKMEDIA_XPATH_TOKEN_EQUAL)
        return -2;

    token = quickmedia_xpath_tokenizer_next(&self->tokenizer);
    if(token != QUICKMEDIA_XPATH_TOKEN_STRING)
        return -3;
    
    result->value = quickmedia_xpath_tokenizer_copy_string(&self->tokenizer);

    token = quickmedia_xpath_tokenizer_next(&self->tokenizer);
    if(token != QUICKMEDIA_XPATH_TOKEN_CLOSING_BRACKET)
        return -4;

    return 0;
}

static int xpath_parse_node(QuickMediaXpathParser *self, QuickMediaNodeSearch *result) {
    quickmedia_node_search_init(result);
    QuickMediaXpathToken token = quickmedia_xpath_tokenizer_next(&self->tokenizer);
    /*    // or /    */
    if(token == QUICKMEDIA_XPATH_TOKEN_CHILD || token == QUICKMEDIA_XPATH_TOKEN_CHILD_RECURSIVE) {
        result->recursive = (token == QUICKMEDIA_XPATH_TOKEN_CHILD_RECURSIVE);

        token = quickmedia_xpath_tokenizer_next(&self->tokenizer);
        if(token != QUICKMEDIA_XPATH_TOKEN_IDENTIFIER)
            return -1;

        result->name = quickmedia_xpath_tokenizer_copy_identifier(&self->tokenizer);

        int param_result = xpath_parse_param(self, &result->param);
        if(param_result < 0) {
            quickmedia_node_search_deinit(result);
            return param_result;
        } else if(param_result == 0) {
            result->param_defined = 1;
        }

        result->child = malloc(sizeof(QuickMediaNodeSearch));
        int node_result = xpath_parse_node(self, result->child);
        if(node_result > 0) {
            node_result = 0;
            /* Didn't have child, remove child */
            free(result->child);
            result->child = NULL;
        } else if(node_result < 0) {
            quickmedia_node_search_deinit(result);
        }

        return node_result;
    } else if(token == QUICKMEDIA_XPATH_TOKEN_END_OF_FILE) {
        return 1;
    } else {
        return -2;
    }
}

int quickmedia_parse_xpath(const char *xpath, QuickMediaNodeSearch *result) {
    QuickMediaXpathParser parser;
    quickmedia_xpath_parser_init(&parser, xpath);
    int parse_result = xpath_parse_node(&parser, result);
    if(parse_result > 0)
        parse_result = -1;
    return parse_result;
}