Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 :
9 : #include "hexcode.h"
10 :
11 : #ifndef HAVE_KDBCONFIG
12 : #include "kdbconfig.h"
13 : #endif
14 :
15 : #include <kdbhelper.h>
16 :
17 : #include <stdlib.h>
18 : #include <string.h>
19 :
20 : /**
21 : * Gives the integer number 0-15 to a corresponding
22 : * hex character '0'-'9', 'a'-'f' or 'A'-'F'.
23 : */
24 120 : static inline int elektraHexcodeConvFromHex (char c)
25 : {
26 120 : if (c == '0')
27 : return 0;
28 92 : else if (c == '1')
29 : return 1;
30 92 : else if (c == '2')
31 : return 2;
32 62 : else if (c == '3')
33 : return 3;
34 38 : else if (c == '4')
35 : return 4;
36 38 : else if (c == '5')
37 : return 5;
38 30 : else if (c == '6')
39 : return 6;
40 30 : else if (c == '7')
41 : return 7;
42 30 : else if (c == '8')
43 : return 8;
44 30 : else if (c == '9')
45 : return 9;
46 30 : else if (c == 'a' || c == 'A')
47 : return 10;
48 24 : else if (c == 'b' || c == 'B')
49 : return 11;
50 16 : else if (c == 'c' || c == 'C')
51 : return 12;
52 8 : else if (c == 'd' || c == 'D')
53 : return 13;
54 0 : else if (c == 'e' || c == 'E')
55 : return 14;
56 0 : else if (c == 'f' || c == 'F')
57 : return 15;
58 : else
59 0 : return 0; /* Unknown escape char */
60 : }
61 :
62 : /** Reads the value of the key and decodes all escaping
63 : * codes into the buffer.
64 : * @pre the buffer needs to be as large as value's size.
65 : * @param cur the key holding the value to decode
66 : * @param buf the buffer to write to
67 : */
68 24 : void elektraHexcodeDecode (Key * cur, CHexData * hd)
69 : {
70 24 : size_t valsize = keyGetValueSize (cur);
71 24 : const char * val = keyValue (cur);
72 :
73 24 : if (!val) return;
74 :
75 : size_t out = 0;
76 144 : for (size_t in = 0; in < valsize - 1; ++in)
77 : {
78 144 : char c = val[in];
79 144 : char * n = hd->buf + out;
80 :
81 144 : if (c == hd->escape)
82 : {
83 50 : in += 2; /* Advance twice (2 hex numbers) */
84 50 : char first = val[in - 1];
85 50 : char second = val[in];
86 : int res;
87 :
88 50 : res = elektraHexcodeConvFromHex (second);
89 50 : res += elektraHexcodeConvFromHex (first) * 16;
90 50 : *n = res & 255;
91 : }
92 : else
93 : {
94 94 : *n = c;
95 : }
96 144 : ++out; /* Only one char is written */
97 : }
98 :
99 24 : hd->buf[out] = 0; // null termination for keyString()
100 :
101 24 : keySetRaw (cur, hd->buf, out + 1);
102 : }
103 :
104 :
105 20 : int elektraHexcodeGet (Plugin * handle, KeySet * returned, Key * parentKey)
106 : {
107 : /* get all keys */
108 :
109 20 : if (!strcmp (keyName (parentKey), "system/elektra/modules/hexcode"))
110 : {
111 20 : KeySet * pluginConfig =
112 20 : ksNew (30, keyNew ("system/elektra/modules/hexcode", KEY_VALUE, "hexcode plugin waits for your orders", KEY_END),
113 : keyNew ("system/elektra/modules/hexcode/exports", KEY_END),
114 : keyNew ("system/elektra/modules/hexcode/exports/get", KEY_FUNC, elektraHexcodeGet, KEY_END),
115 : keyNew ("system/elektra/modules/hexcode/exports/set", KEY_FUNC, elektraHexcodeSet, KEY_END),
116 : keyNew ("system/elektra/modules/hexcode/exports/open", KEY_FUNC, elektraHexcodeOpen, KEY_END),
117 : keyNew ("system/elektra/modules/hexcode/exports/close", KEY_FUNC, elektraHexcodeClose, KEY_END),
118 : #include "readme_hexcode.c"
119 : keyNew ("system/elektra/modules/hexcode/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
120 20 : ksAppend (returned, pluginConfig);
121 20 : ksDel (pluginConfig);
122 20 : return 1;
123 : }
124 :
125 0 : CHexData * hd = elektraPluginGetData (handle);
126 0 : if (!hd->buf)
127 : {
128 0 : hd->buf = elektraMalloc (1000);
129 0 : hd->bufalloc = 1000;
130 : }
131 :
132 : Key * cur;
133 0 : ksRewind (returned);
134 0 : while ((cur = ksNext (returned)) != 0)
135 : {
136 0 : size_t valsize = keyGetValueSize (cur);
137 0 : if (valsize > hd->bufalloc)
138 : {
139 0 : hd->bufalloc = valsize;
140 0 : hd->buf = realloc (hd->buf, hd->bufalloc);
141 : }
142 :
143 0 : elektraHexcodeDecode (cur, hd);
144 : }
145 :
146 : return 1; /* success */
147 : }
148 :
149 :
150 : /**
151 : * Gives the integer number 0-15 to a corresponding
152 : * hex character '0'-'9', 'a'-'f' or 'A'-'F'.
153 : */
154 : static inline char elektraHexcodeConvToHex (int c)
155 : {
156 136 : switch (c)
157 : {
158 : case 0:
159 : return '0';
160 : case 1:
161 : return '1';
162 : case 2:
163 : return '2';
164 : case 3:
165 : return '3';
166 : case 4:
167 : return '4';
168 : case 5:
169 : return '5';
170 : case 6:
171 : return '6';
172 : case 7:
173 : return '7';
174 : case 8:
175 : return '8';
176 : case 9:
177 : return '9';
178 : case 10:
179 : return 'A';
180 : case 11:
181 : return 'B';
182 : case 12:
183 : return 'C';
184 : case 13:
185 : return 'D';
186 : case 14:
187 : return 'E';
188 : case 15:
189 : return 'F';
190 : default:
191 : return '0';
192 : }
193 : }
194 :
195 :
196 : /** Reads the value of the key and encodes it in
197 : * c-style in the buffer.
198 : *
199 : * @param cur the key which value is to encode
200 : * @param buf the buffer
201 : * @pre the buffer needs to have thrice as much space as the value's size
202 : */
203 26 : void elektraHexcodeEncode (Key * cur, CHexData * hd)
204 : {
205 26 : size_t valsize = keyGetValueSize (cur);
206 26 : const char * val = keyValue (cur);
207 :
208 26 : if (!val) return;
209 :
210 : size_t out = 0;
211 200 : for (size_t in = 0; in < valsize - 1; ++in)
212 : {
213 200 : unsigned char c = val[in];
214 :
215 : // need to encode char?
216 200 : if (hd->hd[c & 255])
217 : {
218 68 : hd->buf[out] = hd->escape;
219 68 : out++;
220 136 : hd->buf[out] = elektraHexcodeConvToHex (c / 16);
221 68 : out++;
222 136 : hd->buf[out] = elektraHexcodeConvToHex (c % 16);
223 68 : out++;
224 : }
225 : else
226 : {
227 : // just copy one character
228 132 : hd->buf[out] = val[in];
229 : // advance out cursor
230 132 : out++;
231 : }
232 : }
233 :
234 26 : hd->buf[out] = 0; // null termination for keyString()
235 :
236 26 : keySetRaw (cur, hd->buf, out + 1);
237 : }
238 :
239 :
240 2 : int elektraHexcodeSet (Plugin * handle, KeySet * returned, Key * parentKey ELEKTRA_UNUSED)
241 : {
242 : /* set all keys */
243 2 : CHexData * hd = elektraPluginGetData (handle);
244 2 : if (!hd->buf)
245 : {
246 2 : hd->buf = elektraMalloc (1000);
247 2 : hd->bufalloc = 1000;
248 : }
249 :
250 : Key * cur;
251 2 : ksRewind (returned);
252 6 : while ((cur = ksNext (returned)) != 0)
253 : {
254 2 : size_t valsize = keyGetValueSize (cur);
255 2 : if (valsize * 3 > hd->bufalloc)
256 : {
257 0 : hd->bufalloc = valsize * 3;
258 0 : hd->buf = realloc (hd->buf, hd->bufalloc);
259 : }
260 :
261 2 : elektraHexcodeEncode (cur, hd);
262 : }
263 :
264 2 : return 1; /* success */
265 : }
266 :
267 22 : int elektraHexcodeOpen (Plugin * handle, Key * key ELEKTRA_UNUSED)
268 : {
269 22 : CHexData * hd = calloc (1, sizeof (CHexData));
270 :
271 : /* Store for later use...*/
272 22 : elektraPluginSetData (handle, hd);
273 :
274 22 : KeySet * config = elektraPluginGetConfig (handle);
275 :
276 22 : Key * escape = ksLookupByName (config, "/escape", 0);
277 22 : hd->escape = '\\';
278 22 : if (escape && keyGetBaseNameSize (escape) && keyGetValueSize (escape) == 3)
279 : {
280 : int res;
281 0 : res = elektraHexcodeConvFromHex (keyString (escape)[1]);
282 0 : res += elektraHexcodeConvFromHex (keyString (escape)[0]) * 16;
283 :
284 0 : hd->escape = res & 255;
285 : }
286 :
287 22 : Key * root = ksLookupByName (config, "/chars", 0);
288 22 : if (!root)
289 : {
290 : /* Some default config */
291 20 : hd->hd['\0'] = 1;
292 20 : hd->hd['\n'] = 1;
293 20 : hd->hd['\\'] = 1;
294 20 : hd->hd[' '] = 1;
295 : }
296 : else
297 : {
298 : Key * cur = 0;
299 12 : while ((cur = ksNext (config)) != 0)
300 : {
301 : /* ignore all keys not direct below */
302 10 : if (keyRel (root, cur) == 1)
303 : {
304 : /* ignore invalid size */
305 10 : if (keyGetBaseNameSize (cur) != 3) continue;
306 :
307 : int res;
308 10 : res = elektraHexcodeConvFromHex (keyBaseName (cur)[1]);
309 10 : res += elektraHexcodeConvFromHex (keyBaseName (cur)[0]) * 16;
310 :
311 : /* Hexencode this character! */
312 10 : hd->hd[res & 255] = 1;
313 : }
314 : }
315 : }
316 :
317 22 : return 0;
318 : }
319 :
320 22 : int elektraHexcodeClose (Plugin * handle, Key * key ELEKTRA_UNUSED)
321 : {
322 22 : CHexData * hd = elektraPluginGetData (handle);
323 :
324 22 : elektraFree (hd->buf);
325 22 : elektraFree (hd);
326 :
327 22 : return 0;
328 : }
329 :
330 20 : Plugin * ELEKTRA_PLUGIN_EXPORT
331 : {
332 : // clang-format off
333 20 : return elektraPluginExport("hexcode",
334 : ELEKTRA_PLUGIN_GET, &elektraHexcodeGet,
335 : ELEKTRA_PLUGIN_SET, &elektraHexcodeSet,
336 : ELEKTRA_PLUGIN_OPEN, &elektraHexcodeOpen,
337 : ELEKTRA_PLUGIN_CLOSE, &elektraHexcodeClose,
338 : ELEKTRA_PLUGIN_END);
339 : }
340 :
|