file: fix segfault in uci_parse_option
[project/uci.git] / parse.c
1 /*
2 * libuci - Library for the Unified Configuration Interface
3 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License version 2.1
7 * as published by the Free Software Foundation
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 */
14
15 #include <string.h>
16 #include <stdint.h>
17
18 #include "uci.h"
19
20 void uci_parse_section(struct uci_section *s, const struct uci_parse_option *opts,
21 int n_opts, struct uci_option **tb)
22 {
23 struct uci_element *e;
24
25 memset(tb, 0, n_opts * sizeof(*tb));
26
27 uci_foreach_element(&s->options, e) {
28 struct uci_option *o = uci_to_option(e);
29 int i;
30
31 for (i = 0; i < n_opts; i++) {
32 if (tb[i])
33 continue;
34
35 if (strcmp(opts[i].name, o->e.name) != 0)
36 continue;
37
38 if (opts[i].type != o->type)
39 continue;
40
41 /* match found */
42 tb[i] = o;
43 break;
44 }
45 }
46 }
47
48 //-----------------------------------------------------------------------------
49 // MurmurHashNeutral2, by Austin Appleby
50
51 // Same as MurmurHash2, but endian- and alignment-neutral.
52 static uint32_t hash_murmur2(uint32_t h, const void * key, int len)
53 {
54 const unsigned char * data = key;
55 const uint32_t m = 0x5bd1e995;
56 const int r = 24;
57
58 while(len >= 4)
59 {
60 unsigned int k;
61
62 k = data[0];
63 k |= data[1] << 8;
64 k |= data[2] << 16;
65 k |= data[3] << 24;
66
67 k *= m;
68 k ^= k >> r;
69 k *= m;
70
71 h *= m;
72 h ^= k;
73
74 data += 4;
75 len -= 4;
76 }
77
78 switch(len)
79 {
80 case 3: h ^= data[2] << 16;
81 /* fall through */
82 case 2: h ^= data[1] << 8;
83 /* fall through */
84 case 1: h ^= data[0];
85 h *= m;
86 }
87
88 h ^= h >> 13;
89 h *= m;
90 h ^= h >> 15;
91
92 return h;
93 }
94
95 static uint32_t uci_hash_list(uint32_t h, const struct uci_list *list)
96 {
97 const struct uci_element *e;
98
99 uci_foreach_element(list, e) {
100 h = hash_murmur2(h, e->name, strlen(e->name) + 1);
101 }
102 return h;
103 }
104
105 uint32_t uci_hash_options(struct uci_option **tb, int n_opts)
106 {
107 uint32_t h = 0xdeadc0de;
108 int i;
109
110 for (i = 0; i < n_opts; i++) {
111 const struct uci_option *o = tb[i];
112
113 if (!tb[i])
114 continue;
115
116 h = hash_murmur2(h, o->e.name, strlen(o->e.name) + 1);
117 h = hash_murmur2(h, &o->type, sizeof(o->type));
118
119 switch (tb[i]->type) {
120 case UCI_TYPE_STRING:
121 h = hash_murmur2(h, o->v.string, strlen(o->v.string) + 1);
122 break;
123 case UCI_TYPE_LIST:
124 h = uci_hash_list(h, &o->v.list);
125 break;
126 }
127 }
128
129 return h;
130 }
131
132