token.cc 4.69 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

#include <eval/token.h>
16
#include <eval/eval_log.h>
17
#include <util/encode/hex.h>
18
#include <boost/lexical_cast.hpp>
19
20
21
22
23
24
25
26
27
28
29
#include <string>

using namespace isc::dhcp;
using namespace std;

void
TokenString::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
    // Literals only push, nothing to pop
    values.push(value_);
}

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
void
TokenString::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
    // Transform string of hexadecimal digits into binary format
    std::vector<uint8_t> binary;
    try {
        // The decodeHex function expects that the string contains an
        // even number of digits. If we don't meet this requirement,
        // we have to insert a leading 0.
        if (!repr_.empty() && repr_.length() % 2) {
            repr_ = repr_.insert(0, "0");
        }
        util::encode::decodeHex(repr_, binary);
    } catch (...) {
        values.push("");
        return;
    }
    // Convert to a string
    std::string chars(binary.size(), '\0');
    std::memmove(&chars[0], &binary[0], binary.size());
    // Literals only push, nothing to pop
    values.push(chars_);
}

53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
void
TokenOption::evaluate(const Pkt& pkt, ValueStack& values) {
    OptionPtr opt = pkt.getOption(option_code_);
    if (opt) {
        values.push(opt->toString());
    } else {
        // Option not found, push empty string
        values.push("");
    }
}

void
TokenEqual::evaluate(const Pkt& /*pkt*/, ValueStack& values) {

    if (values.size() < 2) {
        isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
Tomek Mrugalski's avatar
Tomek Mrugalski committed
69
                  "2 values for == operator, got " << values.size());
70
71
72
73
74
75
76
77
78
79
80
81
    }

    string op1 = values.top();
    values.pop();
    string op2 = values.top();
    values.pop(); // Dammit, std::stack interface is awkward.

    if (op1 == op2)
        values.push("true");
    else
        values.push("false");
}
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103

void
TokenSubstring::evaluate(const Pkt& /*pkt*/, ValueStack& values) {

    if (values.size() < 3) {
        isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
                  "3 values for substring operator, got " << values.size());
    }

    string len_str = values.top();
    values.pop();
    string start_str = values.top();
    values.pop();
    string string_str = values.top();
    values.pop();

    // If we have no string to start with we push an empty string and leave
    if (string_str.empty()) {
        values.push("");
        return;
    }

104
    // Convert the starting position and length from strings to numbers
105
    // the length may also be "all" in which case simply make it the
106
    // length of the string.
107
    // If we have a problem push an empty string and leave
108
109
    int start_pos;
    int length;
110
111
    try {
        start_pos = boost::lexical_cast<int>(start_str);
112
        if (len_str == "all") {
113
114
115
116
117
118
119
120
121
            length = string_str.length();
        } else {
            length = boost::lexical_cast<int>(len_str);
        }
    } catch (const boost::bad_lexical_cast&) {
        LOG_DEBUG(eval_logger, EVAL_DBG_TRACE,
                  EVAL_SUBSTRING_BAD_PARAM_CONVERSION)
            .arg(start_str)
            .arg(len_str);
122

123
124
125
126
        values.push("");
        return;
    }

127
    const int string_length = string_str.length();
128
129
    // If the starting postion is outside of the string push an
    // empty string and leave
130
    if ((start_pos < -string_length) || (start_pos >= string_length)) {
131
132
133
134
135
        values.push("");
        return;
    }

    // Adjust the values to be something for substr.  We first figure out
136
137
    // the starting postion, then update it and the length to get the
    // characters before or after it depending on the sign of length
138
    if (start_pos < 0) {
139
        start_pos = string_length + start_pos;
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
    }

    if (length < 0) {
        length = -length;
        if (length <=  start_pos){
            start_pos -= length;
        } else {
            length = start_pos;
            start_pos = 0;
        }
    }

    // and finally get the substring
    values.push(string_str.substr(start_pos, length));
}