1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 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: Dmitry Stogov <dmitry@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 #include <zend.h>
20 #include "zend_smart_str.h"
21 #include "zend_smart_string.h"
22
23 #define SMART_STR_OVERHEAD (ZEND_MM_OVERHEAD + _ZSTR_HEADER_SIZE + 1)
24 #define SMART_STR_START_SIZE 256
25 #define SMART_STR_START_LEN (SMART_STR_START_SIZE - SMART_STR_OVERHEAD)
26 #define SMART_STR_PAGE 4096
27
28 #define SMART_STR_NEW_LEN(len) \
29 (ZEND_MM_ALIGNED_SIZE_EX(len + SMART_STR_OVERHEAD, SMART_STR_PAGE) - SMART_STR_OVERHEAD)
30
smart_str_erealloc(smart_str * str,size_t len)31 ZEND_API void ZEND_FASTCALL smart_str_erealloc(smart_str *str, size_t len)
32 {
33 if (UNEXPECTED(!str->s)) {
34 str->a = len <= SMART_STR_START_LEN
35 ? SMART_STR_START_LEN
36 : SMART_STR_NEW_LEN(len);
37 str->s = zend_string_alloc(str->a, 0);
38 ZSTR_LEN(str->s) = 0;
39 } else {
40 str->a = SMART_STR_NEW_LEN(len);
41 str->s = (zend_string *) erealloc2(str->s, str->a + _ZSTR_HEADER_SIZE + 1, _ZSTR_HEADER_SIZE + ZSTR_LEN(str->s));
42 }
43 }
44
smart_str_realloc(smart_str * str,size_t len)45 ZEND_API void ZEND_FASTCALL smart_str_realloc(smart_str *str, size_t len)
46 {
47 if (UNEXPECTED(!str->s)) {
48 str->a = len <= SMART_STR_START_LEN
49 ? SMART_STR_START_LEN
50 : SMART_STR_NEW_LEN(len);
51 str->s = zend_string_alloc(str->a, 1);
52 ZSTR_LEN(str->s) = 0;
53 } else {
54 str->a = SMART_STR_NEW_LEN(len);
55 str->s = (zend_string *) perealloc(str->s, str->a + _ZSTR_HEADER_SIZE + 1, 1);
56 }
57 }
58
59 /* Windows uses VK_ESCAPE instead of \e */
60 #ifndef VK_ESCAPE
61 #define VK_ESCAPE '\e'
62 #endif
63
zend_compute_escaped_string_len(const char * s,size_t l)64 static size_t zend_compute_escaped_string_len(const char *s, size_t l) {
65 size_t i, len = l;
66 for (i = 0; i < l; ++i) {
67 char c = s[i];
68 if (c == '\n' || c == '\r' || c == '\t' ||
69 c == '\f' || c == '\v' || c == '\\' || c == VK_ESCAPE) {
70 len += 1;
71 } else if (c < 32 || c > 126) {
72 len += 3;
73 }
74 }
75 return len;
76 }
77
smart_str_append_escaped(smart_str * str,const char * s,size_t l)78 ZEND_API void ZEND_FASTCALL smart_str_append_escaped(smart_str *str, const char *s, size_t l) {
79 char *res;
80 size_t i, len = zend_compute_escaped_string_len(s, l);
81
82 smart_str_alloc(str, len, 0);
83 res = &ZSTR_VAL(str->s)[ZSTR_LEN(str->s)];
84 ZSTR_LEN(str->s) += len;
85
86 for (i = 0; i < l; ++i) {
87 unsigned char c = s[i];
88 if (c < 32 || c == '\\' || c > 126) {
89 *res++ = '\\';
90 switch (c) {
91 case '\n': *res++ = 'n'; break;
92 case '\r': *res++ = 'r'; break;
93 case '\t': *res++ = 't'; break;
94 case '\f': *res++ = 'f'; break;
95 case '\v': *res++ = 'v'; break;
96 case '\\': *res++ = '\\'; break;
97 case VK_ESCAPE: *res++ = 'e'; break;
98 default:
99 *res++ = 'x';
100 if ((c >> 4) < 10) {
101 *res++ = (c >> 4) + '0';
102 } else {
103 *res++ = (c >> 4) + 'A' - 10;
104 }
105 if ((c & 0xf) < 10) {
106 *res++ = (c & 0xf) + '0';
107 } else {
108 *res++ = (c & 0xf) + 'A' - 10;
109 }
110 }
111 } else {
112 *res++ = c;
113 }
114 }
115 }
116
smart_str_append_printf(smart_str * dest,const char * format,...)117 ZEND_API void smart_str_append_printf(smart_str *dest, const char *format, ...) {
118 va_list arg;
119 va_start(arg, format);
120 zend_printf_to_smart_str(dest, format, arg);
121 va_end(arg);
122 }
123
124 #define SMART_STRING_OVERHEAD (ZEND_MM_OVERHEAD + 1)
125 #define SMART_STRING_START_SIZE 256
126 #define SMART_STRING_START_LEN (SMART_STRING_START_SIZE - SMART_STRING_OVERHEAD)
127 #define SMART_STRING_PAGE 4096
128
_smart_string_alloc_persistent(smart_string * str,size_t len)129 ZEND_API void ZEND_FASTCALL _smart_string_alloc_persistent(smart_string *str, size_t len)
130 {
131 if (!str->c) {
132 str->len = 0;
133 if (len <= SMART_STRING_START_LEN) {
134 str->a = SMART_STRING_START_LEN;
135 } else {
136 str->a = ZEND_MM_ALIGNED_SIZE_EX(len + SMART_STRING_OVERHEAD, SMART_STRING_PAGE) - SMART_STRING_OVERHEAD;
137 }
138 str->c = pemalloc(str->a + 1, 1);
139 } else {
140 if (UNEXPECTED((size_t) len > SIZE_MAX - str->len)) {
141 zend_error(E_ERROR, "String size overflow");
142 }
143 len += str->len;
144 str->a = ZEND_MM_ALIGNED_SIZE_EX(len + SMART_STRING_OVERHEAD, SMART_STRING_PAGE) - SMART_STRING_OVERHEAD;
145 str->c = perealloc(str->c, str->a + 1, 1);
146 }
147 }
148
_smart_string_alloc(smart_string * str,size_t len)149 ZEND_API void ZEND_FASTCALL _smart_string_alloc(smart_string *str, size_t len)
150 {
151 if (!str->c) {
152 str->len = 0;
153 if (len <= SMART_STRING_START_LEN) {
154 str->a = SMART_STRING_START_LEN;
155 str->c = emalloc(SMART_STRING_START_LEN + 1);
156 } else {
157 str->a = ZEND_MM_ALIGNED_SIZE_EX(len + SMART_STRING_OVERHEAD, SMART_STRING_PAGE) - SMART_STRING_OVERHEAD;
158 if (EXPECTED(str->a < (ZEND_MM_CHUNK_SIZE - SMART_STRING_OVERHEAD))) {
159 str->c = emalloc_large(str->a + 1);
160 } else {
161 /* allocate a huge chunk */
162 str->c = emalloc(str->a + 1);
163 }
164 }
165 } else {
166 if (UNEXPECTED((size_t) len > SIZE_MAX - str->len)) {
167 zend_error(E_ERROR, "String size overflow");
168 }
169 len += str->len;
170 str->a = ZEND_MM_ALIGNED_SIZE_EX(len + SMART_STRING_OVERHEAD, SMART_STRING_PAGE) - SMART_STRING_OVERHEAD;
171 str->c = erealloc2(str->c, str->a + 1, str->len);
172 }
173 }
174
175 /*
176 * Local variables:
177 * tab-width: 4
178 * c-basic-offset: 4
179 * indent-tabs-mode: t
180 * End:
181 * vim600: sw=4 ts=4 fdm=marker
182 * vim<600: sw=4 ts=4
183 */
184