/**************************************************************************** * apps/netutils/codecs/urldecode.c * * This file is part of the NuttX RTOS: * * Copyright (C) 2012 Gregory Nutt. All rights reserved. * Author: Darcy Gong * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include "netutils/urldecode.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ #ifdef CONFIG_CODECS_URLCODE # define IS_HEX_CHAR(ch) \ ((ch >= '0' && ch <= '9') || \ (ch >= 'a' && ch <= 'f') || \ (ch >= 'A' && ch <= 'F')) # define HEX_VALUE(ch, value) \ if (ch >= '0' && ch <= '9') \ { \ value = ch - '0'; \ } \ else if (ch >= 'a' && ch <= 'f') \ { \ value = ch - 'a' + 10; \ } \ else \ { \ value = ch - 'A' + 10; \ } #endif /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: from_hex * * Description: * Converts a hex character to its integer value, * ****************************************************************************/ #ifdef CONFIG_CODECS_URLCODE_NEWMEMORY static char from_hex(char ch) { return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10; } #endif /**************************************************************************** * Name: * * Description: * Converts an integer value to its hex character, * ****************************************************************************/ #ifdef CONFIG_CODECS_URLCODE_NEWMEMORY static char to_hex(char code) { static const char hex[] = "0123456789abcdef"; return hex[code & 15]; } #endif /**************************************************************************** * Name: int2h * * Description: * Convert a single character to a 2 digit hex str a terminating '\0' is * added * ****************************************************************************/ #ifdef CONFIG_CODECS_AVR_URLCODE static void int2h(char c, char *hstr) { hstr[1] = (c & 0xf) + '0'; if ((c & 0xf) > 9) { hstr[1] = (c & 0xf) - 10 + 'a'; } c = (c >> 4) & 0xf; hstr[0] = c + '0'; if (c > 9) { hstr[0] = c - 10 + 'a'; } hstr[2] = '\0'; } #endif /**************************************************************************** * Name: h2int * * Description: * Convert a single hex digit character to its integer value. * ****************************************************************************/ #ifdef CONFIG_CODECS_AVR_URLCODE static unsigned char h2int(char c) { if (c >= '0' && c <= '9') { return ((unsigned char)c - '0'); } if (c >= 'a' && c <= 'f') { return ((unsigned char)c - 'a' + 10); } if (c >= 'A' && c <= 'F') { return ((unsigned char)c - 'A' + 10); } return 0; } #endif /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: * * Description: * Returns a url-encoded version of str. * * IMPORTANT: be sure to free() the returned string after use. * ****************************************************************************/ #ifdef CONFIG_CODECS_URLCODE_NEWMEMORY char *url_encode(char *str) { char *pstr = str; char *buf = malloc(strlen(str) * 3 + 1); char *pbuf = buf; while (*pstr) { if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') { *pbuf++ = *pstr; } else if (*pstr == ' ') { *pbuf++ = '+'; } else { *pbuf++ = '%'; *pbuf++ = to_hex(*pstr >> 4); *pbuf++ = to_hex(*pstr & 15); } pstr++; } *pbuf = '\0'; return buf; } #endif /**************************************************************************** * Name: url_decode * * Description: * Returns a url-decoded version of str. * * IMPORTANT: be sure to free() the returned string after use. * ****************************************************************************/ #ifdef CONFIG_CODECS_URLCODE_NEWMEMORY char *url_decode(char *str) { char *pstr = str; char *buf = malloc(strlen(str) + 1); char *pbuf = buf; while (*pstr) { if (*pstr == '%') { if (pstr[1] && pstr[2]) { *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]); pstr += 2; } } else if (*pstr == '+') { *pbuf++ = ' '; } else { *pbuf++ = *pstr; } pstr++; } *pbuf = '\0'; return buf; } #endif /**************************************************************************** * Name: urlencode ****************************************************************************/ #ifdef CONFIG_CODECS_URLCODE char *urlencode(const char *src, const int src_len, char *dest, int *dest_len) { static const unsigned char hex_chars[] = "0123456789ABCDEF"; const unsigned char *pSrc; const unsigned char *pEnd; char *pDest; pDest = dest; pEnd = (unsigned char *)src + src_len; for (pSrc = (unsigned char *)src; pSrc < pEnd; pSrc++) { if ((*pSrc >= '0' && *pSrc <= '9') || (*pSrc >= 'a' && *pSrc <= 'z') || (*pSrc >= 'A' && *pSrc <= 'Z') || (*pSrc == '_' || *pSrc == '-' || *pSrc == '.' || *pSrc == '~')) { *pDest++ = *pSrc; } else if (*pSrc == ' ') { *pDest++ = '+'; } else { *pDest++ = '%'; *pDest++ = hex_chars[(*pSrc) >> 4]; *pDest++ = hex_chars[(*pSrc) & 0x0F]; } } *pDest = '\0'; *dest_len = pDest - dest; return dest; } #endif /**************************************************************************** * Name: urldecode ****************************************************************************/ #ifdef CONFIG_CODECS_URLCODE char *urldecode(const char *src, const int src_len, char *dest, int *dest_len) { const unsigned char *pSrc; const unsigned char *pEnd; char *pDest; unsigned char cHigh; unsigned char cLow; int valHigh; int valLow; pDest = dest; pSrc = (unsigned char *)src; pEnd = (unsigned char *)src + src_len; while (pSrc < pEnd) { if (*pSrc == '%' && pSrc + 2 < pEnd) { cHigh = *(pSrc + 1); cLow = *(pSrc + 2); if (IS_HEX_CHAR(cHigh) && IS_HEX_CHAR(cLow)) { HEX_VALUE(cHigh, valHigh) HEX_VALUE(cLow, valLow) *pDest++ = (valHigh << 4) | valLow; pSrc += 3; } else { *pDest++ = *pSrc; pSrc++; } } else if (*pSrc == '+') { *pDest++ = ' '; pSrc++; } else { *pDest++ = *pSrc; pSrc++; } } *pDest = '\0'; *dest_len = pDest - dest; return dest; } #endif /**************************************************************************** * Name: urlencode_len ****************************************************************************/ #ifdef CONFIG_CODECS_URLCODE int urlencode_len(const char *src, const int src_len) { const unsigned char *pSrc; const unsigned char *pEnd; int len = 0; pEnd = (unsigned char *)src + src_len; for (pSrc = (unsigned char *)src; pSrc < pEnd; pSrc++) { if ((*pSrc >= '0' && *pSrc <= '9') || (*pSrc >= 'a' && *pSrc <= 'z') || (*pSrc >= 'A' && *pSrc <= 'Z') || (*pSrc == '_' || *pSrc == '-' || *pSrc == '.' || *pSrc == '~' || *pSrc == ' ')) { len++; } else { len+=3; } } return len; } #endif /**************************************************************************** * Name: urldecode_len ****************************************************************************/ #ifdef CONFIG_CODECS_URLCODE int urldecode_len(const char *src, const int src_len) { const unsigned char *pSrc; const unsigned char *pEnd; int len = 0; unsigned char cHigh; unsigned char cLow; pSrc = (unsigned char *)src; pEnd = (unsigned char *)src + src_len; while (pSrc < pEnd) { if (*pSrc == '%' && pSrc + 2 < pEnd) { cHigh = *(pSrc + 1); cLow = *(pSrc + 2); if (IS_HEX_CHAR(cHigh) && IS_HEX_CHAR(cLow)) { pSrc += 2; } } len++; pSrc++; } return len; } #endif /**************************************************************************** * Name: urlrawdecode * * Description: * decode a url string e.g "hello%20joe" or "hello+joe" becomes "hello joe" * ****************************************************************************/ #ifdef CONFIG_CODECS_AVR_URLCODE void urlrawdecode(char *urlbuf) { char c; char *dst; dst = urlbuf; while ((c = *urlbuf)) { if (c == '+') { c = ' '; } if (c == '%') { urlbuf++; c = *urlbuf; urlbuf++; c = (h2int(c) << 4) | h2int(*urlbuf); } *dst = c; dst++; urlbuf++; } *dst = '\0'; } #endif /**************************************************************************** * Name: urlrawencode * * Description: * There must be enoug space in urlbuf. In the worst case that is 3 times * the length of str * ****************************************************************************/ #ifdef CONFIG_CODECS_AVR_URLCODE void urlrawencode(char *str, char *urlbuf) { char c; while ((c = *str)) { if (c == ' ' || isalnum(c) || c == '_' || c == '-' || c == '.' || c == '~') { if (c == ' ') { c = '+'; } *urlbuf = c; str++; urlbuf++; continue; } *urlbuf = '%'; urlbuf++; int2h(c, urlbuf); urlbuf++; urlbuf++; str++; } *urlbuf = '\0'; } #endif