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  */
62 qlisttbl_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  */
125 char *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  */
192 size_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  */
249 char *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  */
308 size_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  */
393 char *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  */
426 size_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 }
char * qhex_encode(const void *bin, size_t size)
Encode data to Hexadecimal digit format.
Definition: qencode.c:393
size_t qhex_decode(char *str)
Decode Hexadecimal encoded data.
Definition: qencode.c:426
size_t qbase64_decode(char *str)
Decode BASE64 encoded string.
Definition: qencode.c:308
size_t qurl_decode(char *str)
Decode URL encoded string.
Definition: qencode.c:192
qlisttbl_t * qlisttbl(int options)
Create a new Q_LIST linked-list container.
Definition: qlisttbl.c:150
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
char * qstrtrim(char *str)
Remove white spaces(including CR, LF) from head and tail of the string.
Definition: qstring.c:55
char * qurl_encode(const void *bin, size_t size)
Encode data using URL encoding(Percent encoding) algorithm.
Definition: qencode.c:125