1 /*
2   +----------------------------------------------------------------------+
3   | zend_string compatibility layer for PHP 5 & 7                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 2005-2007 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: Francois Laupretre <francois@tekwire.net>                    |
16   +----------------------------------------------------------------------+
17 */
18 
19 #ifndef _COMPAT_ZEND_STRING_H
20 #define _COMPAT_ZEND_STRING_H
21 
22 #ifdef PHP_7
23 /*============================================================================*/
24 #include "zend_string.h"
25 
26 #ifndef ZSTR_IS_PERSISTENT
27 #	define ZSTR_IS_PERSISTENT(s) (GC_FLAGS(s) & IS_STR_PERSISTENT)
28 #endif
29 
30 #else
31 /*============================================================================*/
32 /*---- zend_string for PHP 5 ----*/
33 
34 struct _zend_string {
35 		int			persistent;
36 		int			hash_is_set; /* needed because computed hash may be null */
37         zend_ulong	h; /* hash value */
38 		uint32_t	refcount;
39         size_t		len;
40         char		val[1];
41 };
42 
43 typedef struct _zend_string zend_string;
44 
45 /* Shortcuts */
46 
47 #define ZSTR_VAL(zstr)  (zstr)->val
48 #define ZSTR_LEN(zstr)  (zstr)->len
49 #define ZSTR_H(zstr)    (zstr)->h
50 #define ZSTR_HASH(zstr) zend_string_hash_val(zstr)
51 
52 #define _ZSTR_HEADER_SIZE XtOffsetOf(zend_string, val)
53 #define _ZSTR_STRUCT_SIZE(len) (_ZSTR_HEADER_SIZE + len + 1)
54 
55 #define ZSTR_IS_PERSISTENT(s) (s->persistent)
56 
57 /*---------*/
58 
zend_string_refcount(zend_string * s)59 static zend_always_inline uint32_t zend_string_refcount(zend_string *s)
60 {
61 	return (s->refcount);
62 }
63 
64 /*---------*/
65 
zend_string_addref(zend_string * s)66 static zend_always_inline uint32_t zend_string_addref(zend_string *s)
67 {
68 	return ++(s->refcount);
69 }
70 
71 /*---------*/
72 
zend_string_delref(zend_string * s)73 static zend_always_inline uint32_t zend_string_delref(zend_string *s)
74 {
75 	return --(s->refcount);
76 }
77 
78 /*---------*/
79 
zend_string_hash_val(zend_string * s)80 static zend_always_inline zend_ulong zend_string_hash_val(zend_string *s)
81 {
82 	char c, *p;
83 
84 	if (! s->hash_is_set) {
85 		/* Compute with terminating null but preserve string */
86 		p = &(ZSTR_VAL(s)[ZSTR_LEN(s)]);
87 		c = (*p);
88 		(*p) = '\0';
89 		ZSTR_H(s) = zend_get_hash_value(ZSTR_VAL(s), ZSTR_LEN(s)+1);
90 		(*p) = c;
91 		s->hash_is_set = 1;
92 	}
93 	return ZSTR_H(s);
94 }
95 
96 /*---------*/
97 
zend_string_forget_hash_val(zend_string * s)98 static zend_always_inline void zend_string_forget_hash_val(zend_string *s)
99 {
100 	s->hash_is_set = 0;
101 	ZSTR_H(s) = 0; /* Security */
102 }
103 
104 /*---------*/
105 
zend_string_alloc(size_t len,int persistent)106 static zend_always_inline zend_string *zend_string_alloc(size_t len, int persistent)
107 {
108 	zend_string *ret = (zend_string *)pemalloc(ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);
109 	ret->persistent = persistent;
110 	zend_string_forget_hash_val(ret);
111 	ret->refcount = 1;
112 	ZSTR_LEN(ret) = len;
113 	return ret;
114 }
115 
116 /*---------*/
117 
zend_string_safe_alloc(size_t n,size_t m,size_t l,int persistent)118 static zend_always_inline zend_string *zend_string_safe_alloc(size_t n
119 	, size_t m, size_t l, int persistent)
120 {
121 	zend_string *ret = (zend_string *)safe_pemalloc(n, m, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(l)), persistent);
122 	ret->persistent = persistent;
123 	zend_string_forget_hash_val(ret);
124 	ret->refcount = 1;
125 	ZSTR_LEN(ret) = l;
126 	return ret;
127 }
128 
129 /*---------*/
130 
zend_string_init(const char * str,size_t len,int persistent)131 static zend_always_inline zend_string *zend_string_init(const char *str, size_t len, int persistent)
132 {
133 	zend_string *ret = zend_string_alloc(len, persistent);
134 
135 	memcpy(ZSTR_VAL(ret), str, len);
136 	ZSTR_VAL(ret)[len] = '\0';
137 	return ret;
138 }
139 
140 /*---------*/
141 
zend_string_dup(zend_string * s,int persistent)142 static zend_always_inline zend_string *zend_string_dup(zend_string *s, int persistent)
143 {
144 	zend_string *target;
145 
146 	target = zend_string_init(ZSTR_VAL(s), ZSTR_LEN(s), persistent);
147 	if (s->hash_is_set) {
148 		ZSTR_H(target) = ZSTR_H(s);
149 		target->hash_is_set = 1;
150 	}
151 
152 	return target;
153 }
154 
155 /*---------*/
156 
zend_string_realloc(zend_string * s,size_t len,int persistent)157 static zend_always_inline zend_string *zend_string_realloc(zend_string *s
158 	, size_t len, int persistent)
159 {
160 	zend_string *ret;
161 
162 	if (EXPECTED(s->refcount == 1)) {
163 		ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);
164 		ZSTR_LEN(ret) = len;
165 		zend_string_forget_hash_val(ret);
166 		return ret;
167 	}
168 
169 	zend_string_delref(s);
170     ret = zend_string_alloc(len, persistent);
171     memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), MIN(len, ZSTR_LEN(s)) + 1);
172 
173 	return ret;
174 }
175 
176 /*---------*/
177 
zend_string_extend(zend_string * s,size_t len,int persistent)178 static zend_always_inline zend_string *zend_string_extend(zend_string *s
179 	, size_t len, int persistent)
180 {
181     zend_string *ret;
182 
183     ZEND_ASSERT(len >= ZSTR_LEN(s));
184 
185 	if (EXPECTED(s->refcount == 1)) {
186 		ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);
187 		ZSTR_LEN(ret) = len;
188 		zend_string_forget_hash_val(ret);
189 		return ret;
190 	}
191 
192 	zend_string_delref(s);
193     ret = zend_string_alloc(len, persistent);
194     memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), ZSTR_LEN(s) + 1);
195 
196     return ret;
197 }
198 
199 /*---------*/
200 
zend_string_truncate(zend_string * s,size_t len,int persistent)201 static zend_always_inline zend_string *zend_string_truncate(zend_string *s
202 	, size_t len, int persistent)
203 {
204     zend_string *ret;
205 
206     ZEND_ASSERT(len <= ZSTR_LEN(s));
207 
208 	if (EXPECTED(s->refcount == 1)) {
209 		ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);
210 		ZSTR_LEN(ret) = len;
211 		zend_string_forget_hash_val(ret);
212 		return ret;
213 	}
214 
215 	zend_string_delref(s);
216     ret = zend_string_alloc(len, persistent);
217     memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), len + 1);
218 
219     return ret;
220 }
221 
222 /*---------*/
223 
zend_string_safe_realloc(zend_string * s,size_t n,size_t m,size_t l,int persistent)224 static zend_always_inline zend_string *zend_string_safe_realloc(zend_string *s
225 	, size_t n, size_t m, size_t l, int persistent)
226 {
227     zend_string *ret;
228 
229 	if (EXPECTED(s->refcount == 1)) {
230 		ret = (zend_string *)safe_perealloc(s, n, m, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(l)), persistent);
231 		ZSTR_LEN(ret) = (n * m) + l;
232 		zend_string_forget_hash_val(ret);
233 		return ret;
234 	}
235 
236 	zend_string_delref(s);
237 	ret = zend_string_safe_alloc(n, m, l, persistent);
238     memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), MIN((n * m) + l, ZSTR_LEN(s)) + 1);
239     return ret;
240 }
241 
242 /*---------*/
243 
zend_string_free(zend_string * s)244 static zend_always_inline void zend_string_free(zend_string *s)
245 {
246 	if (s) {
247 		pefree(s, s->persistent);
248 	}
249 }
250 
251 
252 /*---------*/
253 
zend_string_release(zend_string * s)254 static zend_always_inline void zend_string_release(zend_string *s)
255 {
256 	if (s) {
257 		s->refcount--;
258 		if (s->refcount == 0) {
259 			zend_string_free(s);
260 		}
261 	}
262 }
263 
264 /*---------*/
265 
zend_string_copy(zend_string * s)266 static zend_always_inline zend_string *zend_string_copy(zend_string *s)
267 {
268 	zend_string_addref(s);
269 	return (s);
270 }
271 
272 /*---------*/
273 
zend_string_equals(zend_string * s1,zend_string * s2)274 static zend_always_inline zend_bool zend_string_equals(zend_string *s1, zend_string *s2)
275 {
276 	return s1 == s2 || (s1->len == s2->len && !memcmp(s1->val, s2->val, s1->len));
277 }
278 
279 #define zend_string_equals_literal(str, literal) \
280 	((str)->len == sizeof(literal)-1 && !memcmp((str)->val, literal, sizeof(literal) - 1))
281 
282 #endif /* PHP_7 */
283 #endif /* _COMPAT_ZEND_STRING_H */
284