root/ext/standard/quot_print.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_hex2int
  2. php_quot_print_decode
  3. php_quot_print_encode
  4. PHP_FUNCTION
  5. PHP_FUNCTION

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Author: Kirill Maximov <kir@actimind.com>                            |
  16    +----------------------------------------------------------------------+
  17  */
  18 
  19 /* $Id$ */
  20 
  21 #include <stdlib.h>
  22 
  23 #ifdef HAVE_UNISTD_H
  24 #include <unistd.h>
  25 #endif
  26 #include <string.h>
  27 #include <errno.h>
  28 
  29 #include "php.h"
  30 #include "quot_print.h"
  31 
  32 #include <stdio.h>
  33 
  34 /*
  35 *  Converting HEX char to INT value
  36 */
  37 static char php_hex2int(int c) /* {{{ */
  38 {
  39         if (isdigit(c)) {
  40                 return c - '0';
  41         }
  42         else if (c >= 'A' && c <= 'F') {
  43                 return c - 'A' + 10;
  44         }
  45         else if (c >= 'a' && c <= 'f') {
  46                 return c - 'a' + 10;
  47         }
  48         else {
  49                 return -1;
  50         }
  51 }
  52 /* }}} */
  53 
  54 PHPAPI zend_string *php_quot_print_decode(const unsigned char *str, size_t length, int replace_us_by_ws) /* {{{ */
  55 {
  56         register size_t i;
  57         register unsigned const char *p1;
  58         register unsigned char *p2;
  59         register unsigned int h_nbl, l_nbl;
  60 
  61         size_t decoded_len, buf_size;
  62         zend_string *retval;
  63 
  64         static unsigned int hexval_tbl[256] = {
  65                 64, 64, 64, 64, 64, 64, 64, 64, 64, 32, 16, 64, 64, 16, 64, 64,
  66                 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  67                 32, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  68                  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 64, 64, 64, 64, 64, 64,
  69                 64, 10, 11, 12, 13, 14, 15, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  70                 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  71                 64, 10, 11, 12, 13, 14, 15, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  72                 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  73                 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  74                 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  75                 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  76                 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  77                 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  78                 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  79                 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  80                 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
  81         };
  82 
  83         if (replace_us_by_ws) {
  84                 replace_us_by_ws = '_';
  85         }
  86 
  87         i = length, p1 = str; buf_size = length;
  88 
  89         while (i > 1 && *p1 != '\0') {
  90                 if (*p1 == '=') {
  91                         buf_size -= 2;
  92                         p1++;
  93                         i--;
  94                 }
  95                 p1++;
  96                 i--;
  97         }
  98 
  99         retval = zend_string_alloc(buf_size, 0);
 100         i = length; p1 = str; p2 = (unsigned char*)ZSTR_VAL(retval);
 101         decoded_len = 0;
 102 
 103         while (i > 0 && *p1 != '\0') {
 104                 if (*p1 == '=') {
 105                         i--, p1++;
 106                         if (i == 0 || *p1 == '\0') {
 107                                 break;
 108                         }
 109                         h_nbl = hexval_tbl[*p1];
 110                         if (h_nbl < 16) {
 111                                 /* next char should be a hexadecimal digit */
 112                                 if ((--i) == 0 || (l_nbl = hexval_tbl[*(++p1)]) >= 16) {
 113                                         efree(retval);
 114                                         return NULL;
 115                                 }
 116                                 *(p2++) = (h_nbl << 4) | l_nbl, decoded_len++;
 117                                 i--, p1++;
 118                         } else if (h_nbl < 64) {
 119                                 /* soft line break */
 120                                 while (h_nbl == 32) {
 121                                         if (--i == 0 || (h_nbl = hexval_tbl[*(++p1)]) == 64) {
 122                                                 efree(retval);
 123                                                 return NULL;
 124                                         }
 125                                 }
 126                                 if (p1[0] == '\r' && i >= 2 && p1[1] == '\n') {
 127                                         i--, p1++;
 128                                 }
 129                                 i--, p1++;
 130                         } else {
 131                                 efree(retval);
 132                                 return NULL;
 133                         }
 134                 } else {
 135                         *(p2++) = (replace_us_by_ws == *p1 ? '\x20': *p1);
 136                         i--, p1++, decoded_len++;
 137                 }
 138         }
 139 
 140         *p2 = '\0';
 141         ZSTR_LEN(retval) = decoded_len;
 142         return retval;
 143 }
 144 /* }}} */
 145 
 146 #define PHP_QPRINT_MAXL 75
 147 
 148 PHPAPI zend_string *php_quot_print_encode(const unsigned char *str, size_t length) /* {{{ */
 149 {
 150         zend_ulong lp = 0;
 151         unsigned char c, *d;
 152         char *hex = "0123456789ABCDEF";
 153         zend_string *ret;
 154 
 155         ret = zend_string_safe_alloc(3, (length + (((3 * length)/(PHP_QPRINT_MAXL-9)) + 1)), 0, 0);
 156         d = (unsigned char*)ZSTR_VAL(ret);
 157 
 158         while (length--) {
 159                 if (((c = *str++) == '\015') && (*str == '\012') && length > 0) {
 160                         *d++ = '\015';
 161                         *d++ = *str++;
 162                         length--;
 163                         lp = 0;
 164                 } else {
 165                         if (iscntrl (c) || (c == 0x7f) || (c & 0x80) || (c == '=') || ((c == ' ') && (*str == '\015'))) {
 166                                 if ((((lp+= 3) > PHP_QPRINT_MAXL) && (c <= 0x7f))
 167             || ((c > 0x7f) && (c <= 0xdf) && ((lp + 3) > PHP_QPRINT_MAXL))
 168             || ((c > 0xdf) && (c <= 0xef) && ((lp + 6) > PHP_QPRINT_MAXL))
 169             || ((c > 0xef) && (c <= 0xf4) && ((lp + 9) > PHP_QPRINT_MAXL))) {
 170                                         *d++ = '=';
 171                                         *d++ = '\015';
 172                                         *d++ = '\012';
 173                                         lp = 3;
 174                                 }
 175                                 *d++ = '=';
 176                                 *d++ = hex[c >> 4];
 177                                 *d++ = hex[c & 0xf];
 178                         } else {
 179                                 if ((++lp) > PHP_QPRINT_MAXL) {
 180                                         *d++ = '=';
 181                                         *d++ = '\015';
 182                                         *d++ = '\012';
 183                                         lp = 1;
 184                                 }
 185                                 *d++ = c;
 186                         }
 187                 }
 188         }
 189         *d = '\0';
 190         ret = zend_string_truncate(ret, d - (unsigned char*)ZSTR_VAL(ret), 0);
 191         return ret;
 192 }
 193 /* }}} */
 194 
 195 /*
 196 *
 197 * Decoding  Quoted-printable string.
 198 *
 199 */
 200 /* {{{ proto string quoted_printable_decode(string str)
 201    Convert a quoted-printable string to an 8 bit string */
 202 PHP_FUNCTION(quoted_printable_decode)
 203 {
 204         zend_string *arg1;
 205         char *str_in;
 206         zend_string *str_out;
 207         size_t i = 0, j = 0, k;
 208 
 209         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &arg1) == FAILURE) {
 210                 return;
 211         }
 212 
 213         if (ZSTR_LEN(arg1) == 0) {
 214                 /* shortcut */
 215                 RETURN_EMPTY_STRING();
 216         }
 217 
 218         str_in = ZSTR_VAL(arg1);
 219         str_out = zend_string_alloc(ZSTR_LEN(arg1), 0);
 220         while (str_in[i]) {
 221                 switch (str_in[i]) {
 222                 case '=':
 223                         if (str_in[i + 1] && str_in[i + 2] &&
 224                                 isxdigit((int) str_in[i + 1]) &&
 225                                 isxdigit((int) str_in[i + 2]))
 226                         {
 227                                 ZSTR_VAL(str_out)[j++] = (php_hex2int((int) str_in[i + 1]) << 4)
 228                                                 + php_hex2int((int) str_in[i + 2]);
 229                                 i += 3;
 230                         } else  /* check for soft line break according to RFC 2045*/ {
 231                                 k = 1;
 232                                 while (str_in[i + k] && ((str_in[i + k] == 32) || (str_in[i + k] == 9))) {
 233                                         /* Possibly, skip spaces/tabs at the end of line */
 234                                         k++;
 235                                 }
 236                                 if (!str_in[i + k]) {
 237                                         /* End of line reached */
 238                                         i += k;
 239                                 }
 240                                 else if ((str_in[i + k] == 13) && (str_in[i + k + 1] == 10)) {
 241                                         /* CRLF */
 242                                         i += k + 2;
 243                                 }
 244                                 else if ((str_in[i + k] == 13) || (str_in[i + k] == 10)) {
 245                                         /* CR or LF */
 246                                         i += k + 1;
 247                                 }
 248                                 else {
 249                                         ZSTR_VAL(str_out)[j++] = str_in[i++];
 250                                 }
 251                         }
 252                         break;
 253                 default:
 254                         ZSTR_VAL(str_out)[j++] = str_in[i++];
 255                 }
 256         }
 257         ZSTR_VAL(str_out)[j] = '\0';
 258         ZSTR_LEN(str_out) = j;
 259 
 260         RETVAL_NEW_STR(str_out);
 261 }
 262 /* }}} */
 263 
 264 /* {{{ proto string quoted_printable_encode(string str) */
 265 PHP_FUNCTION(quoted_printable_encode)
 266 {
 267         zend_string *str;
 268         zend_string *new_str;
 269 
 270         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) != SUCCESS) {
 271                 return;
 272         }
 273 
 274         if (!ZSTR_LEN(str)) {
 275                 RETURN_EMPTY_STRING();
 276         }
 277 
 278         new_str = php_quot_print_encode((unsigned char *)ZSTR_VAL(str), (size_t)ZSTR_LEN(str));
 279         RETURN_STR(new_str);
 280 }
 281 /* }}} */
 282 
 283 /*
 284  * Local variables:
 285  * tab-width: 4
 286  * c-basic-offset: 4
 287  * End:
 288  * vim600: sw=4 ts=4 fdm=marker
 289  * vim<600: sw=4 ts=4
 290  */

/* [<][>][^][v][top][bottom][index][help] */