qLibc
qencode.c
Go to the documentation of this file.
1/******************************************************************************
2 * qLibc
3 *
4 * Copyright (c) 2010-2015 Seungyoung Kim.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *****************************************************************************/
28
29/**
30 * @file qencode.c Encoding/decoding APIs.
31 */
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <stdbool.h>
36#include <string.h>
37#include "qinternal.h"
38#include "utilities/qstring.h"
39#include "utilities/qencode.h"
40
41/**
42 * Parse URL encoded query string
43 *
44 * @param tbl a pointer of qlisttbl_t container. NULL can be used to
45 * create new table.
46 * @param query URL encoded string.
47 * @param equalchar separater of key, value pair.
48 * @param sepchar separater of line.
49 * @param count if count is not NULL, a number of parsed entries are stored.
50 *
51 * @return qlisttbl container pointer, otherwise returns NULL.
52 *
53 * @code
54 * cont char query = "category=love&str=%C5%A5%B5%F0%C4%DA%B4%F5&sort=asc";
55 * qlisttbl_t *tbl = qparse_queries(NULL, req->pszQueryString, '=', '&', NULL);
56 * printf("category = %s\n", tbl->get_str(tbl, "category", false));
57 * printf("str = %s\n", tbl->get_str(tbl, "str", false));
58 * printf("sort = %s\n", tbl->get_str(tbl, "sort", false));
59 * tbl->free(tbl);
60 * @endcode
61 */
62qlisttbl_t *qparse_queries(qlisttbl_t *tbl, const char *query, char equalchar,
63 char sepchar, int *count) {
64 if (tbl == NULL && (tbl = qlisttbl(0)) == NULL) {
65 return NULL;
66 }
67
68 if (query == NULL) {
69 return tbl;
70 }
71
72 int cnt = 0;
73 char *newquery = strdup(query);
74 while (newquery && *newquery) {
75 char *value = _q_makeword(newquery, sepchar);
76 char *name = qstrtrim(_q_makeword(value, equalchar));
77 qurl_decode(name);
78 qurl_decode(value);
79
80 if (tbl->putstr(tbl, name, value) == true) {
81 cnt++;
82 }
83
84 free(name);
85 free(value);
86 }
87
88 if (count != NULL) {
89 *count = cnt;
90 }
91 free(newquery);
92
93 return tbl;
94}
95
96/**
97 * Encode data using URL encoding(Percent encoding) algorithm.
98 *
99 * @param bin a pointer of input data.
100 * @param size the length of input data.
101 *
102 * @return a malloced string pointer of URL encoded string in case of
103 * successful, otherwise returns NULL
104 *
105 * @code
106 * const char *text = "hello 'qLibc' world";
107 *
108 * char *encstr = qurl_encode(text, strlen(text));
109 * if(encstr == NULL) return -1;
110 *
111 * printf("Original: %s\n", text);
112 * printf("Encoded : %s\n", encstr);
113 *
114 * size_t decsize = qurl_decode(encstr);
115 *
116 * printf("Decoded : %s (%zu bytes)\n", encstr, decsize);
117 * free(encstr);
118 *
119 * --[output]--
120 * Original: hello 'qLibc' world
121 * Encoded: hello%20%27qLibc%27%20world
122 * Decoded: hello 'qLibc' world (19 bytes)
123 * @endcode
124 */
125char *qurl_encode(const void *bin, size_t size) {
126 const char URLCHARTBL[16*16] = {
127 00 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 00-0F
128 00 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 10-1F
129 00 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,'-','.','/', // 20-2F
130 '0','1','2','3','4','5','6','7','8','9',':', 0 , 0 , 0 , 0 , 0 , // 30-3F
131 '@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O', // 40-4F
132 'P','Q','R','S','T','U','V','W','X','Y','Z', 0 ,'\\',0 , 0 ,'_', // 50-5F
133 00 ,'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o', // 60-6f
134 'p','q','r','s','t','u','v','w','x','y','z', 0 , 0 , 0 , 0 , 0 , // 70-7F
135 00 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 80-8F
136 00 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 90-9F
137 00 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // A0-AF
138 00 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // B0-BF
139 00 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // C0-CF
140 00 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // D0-DF
141 00 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // E0-EF
142 00 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // F0-FF
143 }; // 0 means must be encoded.
144
145 if (bin == NULL)
146 return NULL;
147 if (size == 0)
148 return strdup("");
149
150 // malloc buffer
151 char *pszEncStr = (char *) malloc((size * 3) + 1);
152 if (pszEncStr == NULL)
153 return NULL;
154
155 char *pszEncPt = pszEncStr;
156 char *pBinPt = (char *) bin;
157 const char *pBinEnd = (bin + size - 1);
158 for (; pBinPt <= pBinEnd; pBinPt++) {
159 unsigned char c = *pBinPt;
160 if (URLCHARTBL[c] != 0) {
161 *pszEncPt++ = *pBinPt;
162 } else {
163 unsigned char cUpper4 = (c >> 4);
164 unsigned char cLower4 = (c & 0x0F);
165
166 *pszEncPt++ = '%';
167 *pszEncPt++ =
168 (cUpper4 < 0x0A) ?
169 (cUpper4 + '0') : ((cUpper4 - 0x0A) + 'a');
170 *pszEncPt++ =
171 (cLower4 < 0x0A) ?
172 (cLower4 + '0') : ((cLower4 - 0x0A) + 'a');
173 }
174 }
175 *pszEncPt = '\0';
176
177 return pszEncStr;
178}
179
180/**
181 * Decode URL encoded string.
182 *
183 * @param str a pointer of URL encoded string.
184 *
185 * @return the length of bytes stored in the str memory in case of successful,
186 * otherwise returns NULL
187 *
188 * @note
189 * This modify str directly. And the 'str' is always terminated by NULL
190 * character.
191 */
192size_t qurl_decode(char *str) {
193 if (str == NULL) {
194 return 0;
195 }
196
197 char *pEncPt, *pBinPt = str;
198 for (pEncPt = str; *pEncPt != '\0'; pEncPt++) {
199 switch (*pEncPt) {
200 case '+': {
201 *pBinPt++ = ' ';
202 break;
203 }
204 case '%': {
205 *pBinPt++ = _q_x2c(*(pEncPt + 1), *(pEncPt + 2));
206 pEncPt += 2;
207 break;
208 }
209 default: {
210 *pBinPt++ = *pEncPt;
211 break;
212 }
213 }
214 }
215 *pBinPt = '\0';
216
217 return (pBinPt - str);
218}
219
220/**
221 * Encode data using BASE64 algorithm.
222 *
223 * @param bin a pointer of input data.
224 * @param size the length of input data.
225 *
226 * @return a malloced string pointer of BASE64 encoded string in case of
227 * successful, otherwise returns NULL
228 *
229 * @code
230 * const char *text = "hello world";
231 *
232 * char *encstr = qbase64_encode(text, strlen(text));
233 * if(encstr == NULL) return -1;
234 *
235 * printf("Original: %s\n", text);
236 * printf("Encoded : %s\n", encstr);
237 *
238 * size_t decsize = qbase64_decode(encstr);
239 *
240 * printf("Decoded : %s (%zu bytes)\n", encstr, decsize);
241 * free(encstr);
242 *
243 * --[output]--
244 * Original: hello world
245 * Encoded: aGVsbG8gd29ybGQ=
246 * Decoded: hello world (11 bytes)
247 * @endcode
248 */
249char *qbase64_encode(const void *bin, size_t size) {
250 const char B64CHARTBL[64] = {
251 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', // 00-0F
252 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', // 10-1F
253 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', // 20-2F
254 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' // 30-3F
255 };
256
257 if (size == 0) {
258 return strdup("");
259 }
260
261 // malloc for encoded string
262 char *pszB64 = (char *) malloc(
263 4 * ((size / 3) + ((size % 3 == 0) ? 0 : 1)) + 1);
264 if (pszB64 == NULL) {
265 return NULL;
266 }
267
268 char *pszB64Pt = pszB64;
269 unsigned char *pBinPt, *pBinEnd = (unsigned char *) (bin + size - 1);
270 unsigned char szIn[3] = { 0, 0, 0 };
271 int nOffset;
272 for (pBinPt = (unsigned char *) bin, nOffset = 0; pBinPt <= pBinEnd;
273 pBinPt++, nOffset++) {
274 int nIdxOfThree = nOffset % 3;
275 szIn[nIdxOfThree] = *pBinPt;
276 if (nIdxOfThree < 2 && pBinPt < pBinEnd)
277 continue;
278
279 *pszB64Pt++ = B64CHARTBL[((szIn[0] & 0xFC) >> 2)];
280 *pszB64Pt++ = B64CHARTBL[(((szIn[0] & 0x03) << 4)
281 | ((szIn[1] & 0xF0) >> 4))];
282 *pszB64Pt++ =
283 (nIdxOfThree >= 1) ?
284 B64CHARTBL[(((szIn[1] & 0x0F) << 2)
285 | ((szIn[2] & 0xC0) >> 6))] :
286 '=';
287 *pszB64Pt++ = (nIdxOfThree >= 2) ? B64CHARTBL[(szIn[2] & 0x3F)] : '=';
288
289 memset((void *) szIn, 0, sizeof(szIn));
290 }
291 *pszB64Pt = '\0';
292
293 return pszB64;
294}
295
296/**
297 * Decode BASE64 encoded string.
298 *
299 * @param str a pointer of Base64 encoded string.
300 *
301 * @return the length of bytes stored in the str memory in case of successful,
302 * otherwise returns NULL
303 *
304 * @note
305 * This modify str directly. And the 'str' is always terminated by NULL
306 * character.
307 */
308size_t qbase64_decode(char *str) {
309 const char B64MAPTBL[16 * 16] = {
310 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 00-0F
311 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 10-1F
312 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, // 20-2F
313 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, // 30-3F
314 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 40-4F
315 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, // 50-5F
316 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 60-6F
317 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, // 70-7F
318 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 80-8F
319 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 90-9F
320 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // A0-AF
321 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // B0-BF
322 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // C0-CF
323 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // D0-DF
324 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // E0-EF
325 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 // F0-FF
326 };
327
328 char *pEncPt, *pBinPt = str;
329 int nIdxOfFour = 0;
330 char cLastByte = 0;
331 for (pEncPt = str; *pEncPt != '\0'; pEncPt++) {
332 char cByte = B64MAPTBL[(unsigned char) (*pEncPt)];
333 if (cByte == 64)
334 continue;
335
336 if (nIdxOfFour == 0) {
337 nIdxOfFour++;
338 } else if (nIdxOfFour == 1) {
339 // 00876543 0021????
340 //*pBinPt++ = ( ((cLastByte << 2) & 0xFC) | ((cByte >> 4) & 0x03) );
341 *pBinPt++ = ((cLastByte << 2) | (cByte >> 4));
342 nIdxOfFour++;
343 } else if (nIdxOfFour == 2) {
344 // 00??8765 004321??
345 //*pBinPt++ = ( ((cLastByte << 4) & 0xF0) | ((cByte >> 2) & 0x0F) );
346 *pBinPt++ = ((cLastByte << 4) | (cByte >> 2));
347 nIdxOfFour++;
348 } else {
349 // 00????87 00654321
350 //*pBinPt++ = ( ((cLastByte << 6) & 0xC0) | (cByte & 0x3F) );
351 *pBinPt++ = ((cLastByte << 6) | cByte);
352 nIdxOfFour = 0;
353 }
354
355 cLastByte = cByte;
356 }
357 *pBinPt = '\0';
358
359 return (pBinPt - str);
360}
361
362/**
363 * Encode data to Hexadecimal digit format.
364 *
365 * @param bin a pointer of input data.
366 * @param size the length of input data.
367 *
368 * @return a malloced string pointer of Hexadecimal encoded string in case of
369 * successful, otherwise returns NULL
370 *
371 * @code
372 * const char *text = "hello world";
373 *
374 * char *encstr = qhex_encode(text, strlen(text));
375 * if(encstr == NULL) return -1;
376 *
377 * printf("Original: %s\n", text);
378 * printf("Encoded : %s\n", encstr);
379 *
380 * size_t decsize = qhex_decode(encstr);
381 *
382 * printf("Decoded : %s (%zu bytes)\n", encstr, decsize);
383 * free(encstr);
384 *
385 * return 0;
386 *
387 * --[output]--
388 * Original: hello world
389 * Encoded : 68656c6c6f20776f726c64
390 * Decoded : hello world (11 bytes)
391 * @endcode
392 */
393char *qhex_encode(const void *bin, size_t size) {
394 const char HEXCHARTBL[16] = {
395 '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
396 };
397
398 char *pHexStr = (char *) malloc(sizeof(char) * ((size * 2) + 1));
399 if (pHexStr == NULL)
400 return NULL;
401
402 unsigned char *pSrc = (unsigned char *) bin;
403 char *pHexPt = pHexStr;
404 int i;
405 for (i = 0; i < size; i++) {
406 *pHexPt++ = HEXCHARTBL[(pSrc[i] >> 4)];
407 *pHexPt++ = HEXCHARTBL[(pSrc[i] & 0x0F)];
408 }
409 *pHexPt = '\0';
410
411 return pHexStr;
412}
413
414/**
415 * Decode Hexadecimal encoded data.
416 *
417 * @param str a pointer of Hexadecimal encoded string.
418 *
419 * @return the length of bytes stored in the str memory in case of successful,
420 * otherwise returns NULL
421 *
422 * @note
423 * This modify str directly. And the 'str' is always terminated by NULL
424 * character.
425 */
426size_t qhex_decode(char *str) {
427 const char HEXMAPTBL[16*16] = {
428 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00-0F
429 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10-1F
430 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20-2F
431 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // 30-3F
432 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40-4F
433 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 50-5F
434 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60-6f
435 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 70-7F
436 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80-8F
437 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 90-9F
438 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A0-AF
439 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B0-BF
440 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C0-CF
441 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D0-DF
442 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E0-EF
443 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F0-FF
444 };
445
446 char *pEncPt, *pBinPt = str;
447 for (pEncPt = str; *pEncPt != '\0'; pEncPt += 2) {
448 *pBinPt++ = (HEXMAPTBL[(unsigned char) (*pEncPt)] << 4)
449 + HEXMAPTBL[(unsigned char) (*(pEncPt + 1))];
450 }
451 *pBinPt = '\0';
452
453 return (pBinPt - str);
454}
size_t qbase64_decode(char *str)
Decode BASE64 encoded string.
Definition qencode.c:308
char * qurl_encode(const void *bin, size_t size)
Encode data using URL encoding(Percent encoding) algorithm.
Definition qencode.c:125
char * qbase64_encode(const void *bin, size_t size)
Encode data using BASE64 algorithm.
Definition qencode.c:249
qlisttbl_t * qparse_queries(qlisttbl_t *tbl, const char *query, char equalchar, char sepchar, int *count)
Parse URL encoded query string.
Definition qencode.c:62
size_t qhex_decode(char *str)
Decode Hexadecimal encoded data.
Definition qencode.c:426
size_t qurl_decode(char *str)
Decode URL encoded string.
Definition qencode.c:192
char * qhex_encode(const void *bin, size_t size)
Encode data to Hexadecimal digit format.
Definition qencode.c:393
qlisttbl_t * qlisttbl(int options)
Create a new Q_LIST linked-list container.
Definition qlisttbl.c:150
char * qstrtrim(char *str)
Remove white spaces(including CR, LF) from head and tail of the string.
Definition qstring.c:55