1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "trigger_checker.h"
17
18#include <ctype.h>
19#include "init_param.h"
20#include "trigger_manager.h"
21#include "securec.h"
22
23#define MAX_CALC_PARAM 100
24// 申请整块能存作为计算的节点
25int CalculatorInit(LogicCalculator *calculator, int dataNumber, int dataUnit, int needCondition)
26{
27    PARAM_CHECK(calculator != NULL, return -1, "Invalid param");
28    PARAM_CHECK(dataUnit <= (int)sizeof(LogicData), return -1, "Invalid param");
29    PARAM_CHECK(dataNumber <= MAX_CALC_PARAM, return -1, "Invalid param");
30    int dataSize = dataUnit * dataNumber;
31    if (needCondition) {
32        dataSize += MAX_DATA_BUFFER_MAX;
33    }
34    calculator->data = (char *)calloc(1, dataSize);
35    PARAM_CHECK(calculator->data != NULL, return -1, "Failed to malloc for calculator");
36    calculator->dataNumber = dataNumber;
37    calculator->endIndex = 0;
38    calculator->dataUnit = dataUnit;
39
40    dataSize = dataUnit * dataNumber;
41    calculator->conditionName = calculator->data + dataSize;
42    dataSize += SUPPORT_DATA_BUFFER_MAX;
43    calculator->conditionContent = calculator->data + dataSize;
44    dataSize += SUPPORT_DATA_BUFFER_MAX;
45    calculator->inputName = calculator->data + dataSize;
46    dataSize += SUPPORT_DATA_BUFFER_MAX;
47    calculator->inputContent = calculator->data + dataSize;
48    dataSize += SUPPORT_DATA_BUFFER_MAX;
49    calculator->readContent = calculator->data + dataSize;
50    return memset_s(calculator->triggerContent,
51        sizeof(calculator->triggerContent), 0, sizeof(calculator->triggerContent));
52}
53
54void CalculatorFree(LogicCalculator *calculator)
55{
56    PARAM_CHECK(calculator != NULL, return, "Invalid param");
57    if (calculator->data != NULL) {
58        free(calculator->data);
59    }
60    calculator->data = NULL;
61}
62
63static void CalculatorClear(LogicCalculator *calculator)
64{
65    PARAM_CHECK(calculator != NULL, return, "Invalid param");
66    calculator->endIndex = 0;
67}
68
69static int CalculatorPushChar(LogicCalculator *calculator, char data)
70{
71    PARAM_CHECK(calculator != NULL, return -1, "Invalid param");
72    PARAM_CHECK(calculator->endIndex < calculator->dataNumber, return -1, "More data for calculator support");
73    PARAM_CHECK(sizeof(char) == calculator->dataUnit, return -1, "More data for calculator support");
74    calculator->data[calculator->endIndex++] = data;
75    return 0;
76}
77
78static int CalculatorPopChar(LogicCalculator *calculator, char *data)
79{
80    PARAM_CHECK(calculator != NULL, return -1, "Invalid param");
81    PARAM_CHECK(calculator->endIndex < calculator->dataNumber, return -1, "More data for calculator support");
82    if (calculator->endIndex == 0) {
83        return -1;
84    }
85    *data = calculator->data[--calculator->endIndex];
86    return 0;
87}
88
89static int CalculatorPush(LogicCalculator *calculator, const void *data)
90{
91    PARAM_CHECK(calculator != NULL, return -1, "Invalid param");
92    PARAM_CHECK(calculator->endIndex < calculator->dataNumber, return -1, "More data for calculator support");
93    char *tmpData = (char *)calculator->data + calculator->dataUnit * calculator->endIndex;
94    int ret = memcpy_s(tmpData, calculator->dataUnit, data, calculator->dataUnit);
95    PARAM_CHECK(ret == EOK, return -1, "Failed to copy logic data");
96    calculator->endIndex++;
97    return 0;
98}
99
100static int CalculatorPop(LogicCalculator *calculator, void *data)
101{
102    PARAM_CHECK(calculator != NULL && data != NULL, return -1, "Invalid param");
103    PARAM_CHECK(calculator->endIndex < calculator->dataNumber, return -1, "More data for calculator support");
104    if (calculator->endIndex == 0) {
105        return -1;
106    }
107    char *tmpData = (char *)calculator->data + calculator->dataUnit * (calculator->endIndex - 1);
108    int ret = memcpy_s(data, calculator->dataUnit, tmpData, calculator->dataUnit);
109    PARAM_CHECK(ret == EOK, return -1, "Failed to copy logic data");
110    calculator->endIndex--;
111    return 0;
112}
113
114static int CalculatorLength(const LogicCalculator *calculator)
115{
116    PARAM_CHECK(calculator != NULL, return 0, "Invalid param");
117    return calculator->endIndex;
118}
119
120static int PrefixAdd(char *prefix, uint32_t *prefixIndex, uint32_t prefixLen, char op)
121{
122    if ((*prefixIndex + 1 + 1 + 1) >= prefixLen) {
123        return -1;
124    }
125    prefix[(*prefixIndex)++] = ' ';
126    prefix[(*prefixIndex)++] = op;
127    prefix[(*prefixIndex)++] = ' ';
128    return 0;
129}
130
131static int HandleOperationOr(LogicCalculator *calculator, char *prefix, uint32_t *prefixIndex, uint32_t prefixLen)
132{
133    char e = 0;
134    prefix[(*prefixIndex)++] = ' ';
135    if (CalculatorLength(calculator) == 0) {
136        CalculatorPushChar(calculator, '|');
137    } else {
138        do {
139            CalculatorPopChar(calculator, &e);
140            if (e == '(') {
141                CalculatorPushChar(calculator, e);
142            } else {
143                int ret = PrefixAdd(prefix, prefixIndex, prefixLen, e);
144                PARAM_CHECK(ret == 0, return -1, "Invalid prefix");
145            }
146        } while (CalculatorLength(calculator) > 0 && e != '(');
147        CalculatorPushChar(calculator, '|');
148    }
149    return 0;
150}
151
152static int CompareValue(const char *condition, const char *value)
153{
154    if (strcmp(condition, "*") == 0) {
155        return 1;
156    }
157    if (strcmp(condition, value) == 0) {
158        return 1;
159    }
160    char *tmp = strstr(condition, "*");
161    if (tmp != NULL && (strncmp(value, condition, tmp - condition) == 0)) {
162        return 1;
163    }
164    return 0;
165}
166
167static int ComputeSubCondition(const LogicCalculator *calculator, LogicData *data, const char *condition)
168{
169    if (!LOGIC_DATA_TEST_FLAG(data, LOGIC_DATA_FLAGS_ORIGINAL)) {
170        return LOGIC_DATA_TEST_FLAG(data, LOGIC_DATA_FLAGS_TRUE);
171    }
172    uint32_t triggerContentSize = strlen(calculator->triggerContent);
173    // 解析条件, aaaa && bbb=1 && ccc=1的场景
174    char *subStr = strstr(condition + data->startIndex, "=");
175    if (subStr != NULL && ((uint32_t)(subStr - condition) > data->endIndex)) {
176        if (strncmp(condition + data->startIndex, calculator->triggerContent, triggerContentSize) == 0) {
177            return 1;
178        }
179        return 0;
180    }
181    int ret = GetValueFromContent(condition + data->startIndex,
182        data->endIndex - data->startIndex, 0, calculator->conditionName, SUPPORT_DATA_BUFFER_MAX);
183    PARAM_CHECK(ret == 0, return -1, "Failed parse content name");
184    ret = GetValueFromContent(condition + data->startIndex, data->endIndex - data->startIndex,
185        strlen(calculator->conditionName) + 1, calculator->conditionContent, SUPPORT_DATA_BUFFER_MAX);
186    PARAM_CHECK(ret == 0, return -1, "Failed parse content value");
187    // check name
188    if ((calculator->inputName != NULL) && (strcmp(calculator->conditionName, calculator->inputName) == 0)) {
189        return CompareValue(calculator->conditionContent, calculator->inputContent);
190    } else if (strlen(calculator->conditionName) > 0) {
191        uint32_t len = SUPPORT_DATA_BUFFER_MAX;
192        ret = SystemReadParam(calculator->conditionName, calculator->readContent, &len);
193        if (ret != 0) {
194            return 0;
195        }
196        return CompareValue(calculator->conditionContent, calculator->readContent);
197    }
198    return 0;
199}
200
201int GetValueFromContent(const char *content, uint32_t contentSize, uint32_t start, char *value, uint32_t valueSize)
202{
203    uint32_t contentIndex = start;
204    uint32_t currIndex = 0;
205    while (contentIndex < contentSize && currIndex < valueSize) {
206        if (content[contentIndex] == '=') {
207            value[currIndex++] = '\0';
208            return 0;
209        }
210        value[currIndex++] = content[contentIndex++];
211    }
212    if (currIndex < valueSize) {
213        value[currIndex] = '\0';
214        return 0;
215    }
216    return -1;
217}
218
219int ComputeCondition(LogicCalculator *calculator, const char *condition)
220{
221    PARAM_CHECK(calculator != NULL && condition != NULL, return -1, "Invalid calculator");
222    uint32_t currIndex = 0;
223    uint32_t start = 0;
224    size_t conditionLen = strlen(condition);
225    int noneOper = 1;
226    CalculatorClear(calculator);
227    LogicData data1 = {};
228    LogicData data2 = {};
229    while (currIndex < conditionLen) {
230        if (condition[currIndex] == '|' || condition[currIndex] == '&') {
231            noneOper = 0;
232            int ret = CalculatorPop(calculator, (void*)&data2);
233            int ret1 = CalculatorPop(calculator, (void*)&data1);
234            PARAM_CHECK((ret == 0 && ret1 == 0), return -1, "Failed to pop data");
235
236            ret = ComputeSubCondition(calculator, &data1, condition);
237            data1.flags = 0;
238            if (condition[currIndex] == '|' && ret == 1) {
239                LOGIC_DATA_SET_FLAG(&data1, LOGIC_DATA_FLAGS_TRUE);
240            } else if ((condition[currIndex] == '|' || ret == 1) &&
241                (ComputeSubCondition(calculator, &data2, condition) == 1)) {
242                LOGIC_DATA_SET_FLAG(&data1, LOGIC_DATA_FLAGS_TRUE);
243            }
244            ret = CalculatorPush(calculator, (void *)&data1);
245            PARAM_CHECK(ret == 0, return -1, "Failed to push data");
246            start = currIndex + 1; // 跳过符号
247        } else if (isspace(condition[currIndex])) {
248            if (start == currIndex) {
249                start = ++currIndex;
250                continue;
251            }
252            data1.flags = LOGIC_DATA_FLAGS_ORIGINAL;
253            data1.startIndex = start;
254            data1.endIndex = currIndex;
255            int ret = CalculatorPush(calculator, (void *)&data1);
256            PARAM_CHECK(ret == 0, return -1, "Failed to push data");
257            start = currIndex + 1;
258        }
259        currIndex++;
260    }
261    if (noneOper) {
262        data1.flags = LOGIC_DATA_FLAGS_ORIGINAL;
263        data1.startIndex = start;
264        data1.endIndex = strlen(condition);
265    } else {
266        int ret = CalculatorPop(calculator, &data1);
267        PARAM_CHECK(ret == 0, return -1, "Invalid calculator");
268    }
269    return ComputeSubCondition(calculator, &data1, condition);
270}
271
272int ConvertInfixToPrefix(const char *condition, char *prefix, uint32_t prefixLen)
273{
274    PARAM_CHECK(condition != NULL && prefix != NULL, return -1, "Invalid condition");
275    char e = 0;
276    int ret;
277    uint32_t curr = 0;
278    uint32_t prefixIndex = 0;
279    size_t conditionLen = strlen(condition);
280    LogicCalculator calculator;
281    PARAM_CHECK(CalculatorInit(&calculator, MAX_CALC_PARAM, 1, 0) == 0, return -1, "Failed to init calculator");
282
283    while (curr < conditionLen) {
284        if (condition[curr] == ')') {
285            CalculatorPopChar(&calculator, &e);
286            while (e != '(') {
287                ret = PrefixAdd(prefix, &prefixIndex, prefixLen, e);
288                PARAM_CHECK(ret == 0,
289                    CalculatorFree(&calculator); return -1, "Invalid prefix");
290                CalculatorPopChar(&calculator, &e);
291            }
292        } else if (condition[curr] == '|') {
293            PARAM_CHECK(condition[curr + 1] == '|',
294                CalculatorFree(&calculator); return -1, "Invalid condition");
295            ret = HandleOperationOr(&calculator, prefix, &prefixIndex, prefixLen);
296            PARAM_CHECK(ret == 0,
297                CalculatorFree(&calculator); return -1, "Invalid prefix");
298            curr++;
299        } else if (condition[curr] == '&') {
300            PARAM_CHECK(condition[curr + 1] == '&',
301                CalculatorFree(&calculator); return -1, "Invalid condition");
302            prefix[prefixIndex++] = ' ';
303            CalculatorPushChar(&calculator, condition[curr]);
304            curr++;
305        } else if (condition[curr] == '(') {
306            CalculatorPushChar(&calculator, condition[curr]);
307        } else {
308            prefix[prefixIndex++] = condition[curr];
309        }
310        curr++;
311        PARAM_CHECK(prefixIndex < prefixLen,
312            CalculatorFree(&calculator); return -1, "Invalid prefixIndex");
313    }
314
315    while (CalculatorLength(&calculator) > 0) {
316        CalculatorPopChar(&calculator, &e);
317        ret = PrefixAdd(prefix, &prefixIndex, prefixLen, e);
318        PARAM_CHECK(ret == 0,
319            CalculatorFree(&calculator);
320            return -1, "Invalid prefix %u %u", prefixIndex, prefixLen);
321    }
322    prefix[prefixIndex] = '\0';
323    CalculatorFree(&calculator);
324    return 0;
325}
326
327int CheckMatchSubCondition(const char *condition, const char *input, int length)
328{
329    PARAM_CHECK(condition != NULL, return 0, "Invalid condition");
330    PARAM_CHECK(input != NULL, return 0, "Invalid input");
331    const char *tmp = strstr(condition, input);
332    while (tmp != NULL) {
333        PARAM_LOGV("CheckMatchSubCondition Condition: '%s' content: '%s' length %d", condition, input, length);
334        if (((int)strlen(tmp) <= length) || (tmp[length] != '=')) {
335            return 0;
336        }
337        // for condition: parameter = 1
338        if (tmp == condition) {
339            return 1;
340        }
341        // for condition: parameter1 = 1 && parameter2 = 1
342        if (*(tmp - 1) == ' ') {
343            return 1;
344        }
345        tmp = strstr(tmp + 1, input);
346    }
347    return 0;
348}