1 /*
2  *  Utilities
3  */
4 
5 #ifndef DUK_UTIL_H_INCLUDED
6 #define DUK_UTIL_H_INCLUDED
7 
8 #define DUK_UTIL_MIN_HASH_PRIME  17  /* must match genhashsizes.py */
9 
10 #define DUK_UTIL_GET_HASH_PROBE_STEP(hash)  (duk_util_probe_steps[(hash) & 0x1f])
11 
12 /*
13  *  Endian conversion
14  */
15 
16 #if defined(DUK_USE_INTEGER_LE)
17 #define DUK_HTON32(x) DUK_BSWAP32((x))
18 #define DUK_NTOH32(x) DUK_BSWAP32((x))
19 #define DUK_HTON16(x) DUK_BSWAP16((x))
20 #define DUK_NTOH16(x) DUK_BSWAP16((x))
21 #elif defined(DUK_USE_INTEGER_BE)
22 #define DUK_HTON32(x) (x)
23 #define DUK_NTOH32(x) (x)
24 #define DUK_HTON16(x) (x)
25 #define DUK_NTOH16(x) (x)
26 #else
27 #error internal error, endianness defines broken
28 #endif
29 
30 /*
31  *  Bitstream decoder
32  */
33 
34 struct duk_bitdecoder_ctx {
35 	const duk_uint8_t *data;
36 	duk_size_t offset;
37 	duk_size_t length;
38 	duk_uint32_t currval;
39 	duk_small_int_t currbits;
40 };
41 
42 /*
43  *  Bitstream encoder
44  */
45 
46 struct duk_bitencoder_ctx {
47 	duk_uint8_t *data;
48 	duk_size_t offset;
49 	duk_size_t length;
50 	duk_uint32_t currval;
51 	duk_small_int_t currbits;
52 	duk_small_int_t truncated;
53 };
54 
55 /*
56  *  Raw write/read macros for big endian, unaligned basic values.
57  *  Caller ensures there's enough space.  The macros update the pointer
58  *  argument automatically on resizes.  The idiom seems a bit odd, but
59  *  leads to compact code.
60  */
61 
62 #define DUK_RAW_WRITE_U8(ptr,val)  do { \
63 		*(ptr)++ = (duk_uint8_t) (val); \
64 	} while (0)
65 #define DUK_RAW_WRITE_U16_BE(ptr,val) duk_raw_write_u16_be(&(ptr), (duk_uint16_t) (val))
66 #define DUK_RAW_WRITE_U32_BE(ptr,val) duk_raw_write_u32_be(&(ptr), (duk_uint32_t) (val))
67 #define DUK_RAW_WRITE_DOUBLE_BE(ptr,val) duk_raw_write_double_be(&(ptr), (duk_double_t) (val))
68 #define DUK_RAW_WRITE_XUTF8(ptr,val)  do { \
69 		/* 'ptr' is evaluated both as LHS and RHS. */ \
70 		duk_uint8_t *duk__ptr; \
71 		duk_small_int_t duk__len; \
72 		duk__ptr = (duk_uint8_t *) (ptr); \
73 		duk__len = duk_unicode_encode_xutf8((duk_ucodepoint_t) (val), duk__ptr); \
74 		duk__ptr += duk__len; \
75 		(ptr) = duk__ptr; \
76 	} while (0)
77 #define DUK_RAW_WRITE_CESU8(ptr,val)  do { \
78 		/* 'ptr' is evaluated both as LHS and RHS. */ \
79 		duk_uint8_t *duk__ptr; \
80 		duk_small_int_t duk__len; \
81 		duk__ptr = (duk_uint8_t *) (ptr); \
82 		duk__len = duk_unicode_encode_cesu8((duk_ucodepoint_t) (val), duk__ptr); \
83 		duk__ptr += duk__len; \
84 		(ptr) = duk__ptr; \
85 	} while (0)
86 
87 #define DUK_RAW_READ_U8(ptr) ((duk_uint8_t) (*(ptr)++))
88 #define DUK_RAW_READ_U16_BE(ptr) duk_raw_read_u16_be(&(ptr));
89 #define DUK_RAW_READ_U32_BE(ptr) duk_raw_read_u32_be(&(ptr));
90 #define DUK_RAW_READ_DOUBLE_BE(ptr) duk_raw_read_double_be(&(ptr));
91 
92 /*
93  *  Buffer writer (dynamic buffer only)
94  *
95  *  Helper for writing to a dynamic buffer with a concept of a "spare" area
96  *  to reduce resizes.  You can ensure there is enough space beforehand and
97  *  then write for a while without further checks, relying on a stable data
98  *  pointer.  Spare handling is automatic so call sites only indicate how
99  *  much data they need right now.
100  *
101  *  There are several ways to write using bufwriter.  The best approach
102  *  depends mainly on how much performance matters over code footprint.
103  *  The key issues are (1) ensuring there is space and (2) keeping the
104  *  pointers consistent.  Fast code should ensure space for multiple writes
105  *  with one ensure call.  Fastest inner loop code can temporarily borrow
106  *  the 'p' pointer but must write it back eventually.
107  *
108  *  Be careful to ensure all macro arguments (other than static pointers like
109  *  'thr' and 'bw_ctx') are evaluated exactly once, using temporaries if
110  *  necessary (if that's not possible, there should be a note near the macro).
111  *  Buffer write arguments often contain arithmetic etc so this is
112  *  particularly important here.
113  */
114 
115 /* XXX: Migrate bufwriter and other read/write helpers to its own header? */
116 
117 struct duk_bufwriter_ctx {
118 	duk_uint8_t *p;
119 	duk_uint8_t *p_base;
120 	duk_uint8_t *p_limit;
121 	duk_hbuffer_dynamic *buf;
122 };
123 
124 #define DUK_BW_SPARE_ADD           64
125 #define DUK_BW_SPARE_SHIFT         4    /* 2^4 -> 1/16 = 6.25% spare */
126 
127 /* Initialization and finalization (compaction), converting to other types. */
128 
129 #define DUK_BW_INIT_PUSHBUF(thr,bw_ctx,sz) do { \
130 		duk_bw_init_pushbuf((thr), (bw_ctx), (sz)); \
131 	} while (0)
132 #define DUK_BW_INIT_WITHBUF(thr,bw_ctx,buf) do { \
133 		duk_bw_init((thr), (bw_ctx), (buf)); \
134 	} while (0)
135 #define DUK_BW_COMPACT(thr,bw_ctx) do { \
136 		/* Make underlying buffer compact to match DUK_BW_GET_SIZE(). */ \
137 		duk_bw_compact((thr), (bw_ctx)); \
138 	} while (0)
139 #define DUK_BW_PUSH_AS_STRING(thr,bw_ctx) do { \
140 		duk_push_lstring((duk_context *) (thr), \
141 		                 (const char *) (bw_ctx)->p_base, \
142 		                 (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \
143 	} while (0)
144 /* Pointers may be NULL for a while when 'buf' size is zero and before any
145  * ENSURE calls have been made.  Once an ENSURE has been made, the pointers
146  * are required to be non-NULL so that it's always valid to use memcpy() and
147  * memmove(), even for zero size.
148  */
149 #define DUK_BW_ASSERT_VALID_EXPR(thr,bw_ctx) \
150 	DUK_ASSERT_EXPR((bw_ctx) != NULL && \
151 	                (bw_ctx)->buf != NULL && \
152 			((DUK_HBUFFER_DYNAMIC_GET_SIZE((bw_ctx)->buf) == 0) || \
153 				((bw_ctx)->p != NULL && \
154 		                 (bw_ctx)->p_base != NULL && \
155 		                 (bw_ctx)->p_limit != NULL && \
156 		                 (bw_ctx)->p_limit >= (bw_ctx)->p_base && \
157 		                 (bw_ctx)->p >= (bw_ctx)->p_base && \
158 		                 (bw_ctx)->p <= (bw_ctx)->p_limit)))
159 #define DUK_BW_ASSERT_VALID(thr,bw_ctx) do { \
160 		DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)); \
161 	} while (0)
162 
163 /* Working with the pointer and current size. */
164 
165 #define DUK_BW_GET_PTR(thr,bw_ctx) \
166 	((bw_ctx)->p)
167 #define DUK_BW_SET_PTR(thr,bw_ctx,ptr) do { \
168 		(bw_ctx)->p = (ptr); \
169 	} while (0)
170 #define DUK_BW_ADD_PTR(thr,bw_ctx,delta) do { \
171 		(bw_ctx)->p += (delta); \
172 	} while (0)
173 #define DUK_BW_GET_BASEPTR(thr,bw_ctx) \
174 	((bw_ctx)->p_base)
175 #define DUK_BW_GET_LIMITPTR(thr,bw_ctx) \
176 	((bw_ctx)->p_limit)
177 #define DUK_BW_GET_SIZE(thr,bw_ctx) \
178 	((duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base))
179 #define DUK_BW_SET_SIZE(thr,bw_ctx,sz) do { \
180 		DUK_ASSERT((duk_size_t) (sz) <= (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \
181 		(bw_ctx)->p = (bw_ctx)->p_base + (sz); \
182 	} while (0)
183 #define DUK_BW_RESET_SIZE(thr,bw_ctx) do { \
184 		/* Reset to zero size, keep current limit. */ \
185 		(bw_ctx)->p = (bw_ctx)->p_base; \
186 	} while (0)
187 #define DUK_BW_GET_BUFFER(thr,bw_ctx) \
188 	((bw_ctx)->buf)
189 
190 /* Ensuring (reserving) space. */
191 
192 #define DUK_BW_ENSURE(thr,bw_ctx,sz) do { \
193 		duk_size_t duk__sz, duk__space; \
194 		DUK_BW_ASSERT_VALID((thr), (bw_ctx)); \
195 		duk__sz = (sz); \
196 		duk__space = (duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p); \
197 		if (duk__space < duk__sz) { \
198 			(void) duk_bw_resize((thr), (bw_ctx), duk__sz); \
199 		} \
200 	} while (0)
201 /* NOTE: Multiple evaluation of 'ptr' in this macro. */
202 /* XXX: Rework to use an always-inline function? */
203 #define DUK_BW_ENSURE_RAW(thr,bw_ctx,sz,ptr) \
204 	(((duk_size_t) ((bw_ctx)->p_limit - (ptr)) >= (sz)) ? \
205 	 (ptr) : \
206 	 ((bw_ctx)->p = (ptr), duk_bw_resize((thr),(bw_ctx),(sz))))
207 #define DUK_BW_ENSURE_GETPTR(thr,bw_ctx,sz) \
208 	DUK_BW_ENSURE_RAW((thr), (bw_ctx), (sz), (bw_ctx)->p)
209 #define DUK_BW_ASSERT_SPACE_EXPR(thr,bw_ctx,sz) \
210 	(DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)), \
211 	 DUK_ASSERT_EXPR((duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p) >= (duk_size_t) (sz)))
212 #define DUK_BW_ASSERT_SPACE(thr,bw_ctx,sz) do { \
213 		DUK_BW_ASSERT_SPACE_EXPR((thr), (bw_ctx), (sz)); \
214 	} while (0)
215 
216 /* Miscellaneous. */
217 
218 #define DUK_BW_SETPTR_AND_COMPACT(thr,bw_ctx,ptr) do { \
219 		(bw_ctx)->p = (ptr); \
220 		duk_bw_compact((thr), (bw_ctx)); \
221 	} while (0)
222 
223 /* Fast write calls which assume you control the spare beforehand.
224  * Multibyte write variants exist and use a temporary write pointer
225  * because byte writes alias with anything: with a stored pointer
226  * explicit pointer load/stores get generated (e.g. gcc -Os).
227  */
228 
229 #define DUK_BW_WRITE_RAW_U8(thr,bw_ctx,val) do { \
230 		DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 1); \
231 		*(bw_ctx)->p++ = (duk_uint8_t) (val); \
232 	} while (0)
233 #define DUK_BW_WRITE_RAW_U8_2(thr,bw_ctx,val1,val2) do { \
234 		duk_uint8_t *duk__p; \
235 		DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 2); \
236 		duk__p = (bw_ctx)->p; \
237 		*duk__p++ = (duk_uint8_t) (val1); \
238 		*duk__p++ = (duk_uint8_t) (val2); \
239 		(bw_ctx)->p = duk__p; \
240 	} while (0)
241 #define DUK_BW_WRITE_RAW_U8_3(thr,bw_ctx,val1,val2,val3) do { \
242 		duk_uint8_t *duk__p; \
243 		DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 3); \
244 		duk__p = (bw_ctx)->p; \
245 		*duk__p++ = (duk_uint8_t) (val1); \
246 		*duk__p++ = (duk_uint8_t) (val2); \
247 		*duk__p++ = (duk_uint8_t) (val3); \
248 		(bw_ctx)->p = duk__p; \
249 	} while (0)
250 #define DUK_BW_WRITE_RAW_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \
251 		duk_uint8_t *duk__p; \
252 		DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 4); \
253 		duk__p = (bw_ctx)->p; \
254 		*duk__p++ = (duk_uint8_t) (val1); \
255 		*duk__p++ = (duk_uint8_t) (val2); \
256 		*duk__p++ = (duk_uint8_t) (val3); \
257 		*duk__p++ = (duk_uint8_t) (val4); \
258 		(bw_ctx)->p = duk__p; \
259 	} while (0)
260 #define DUK_BW_WRITE_RAW_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \
261 		duk_uint8_t *duk__p; \
262 		DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 5); \
263 		duk__p = (bw_ctx)->p; \
264 		*duk__p++ = (duk_uint8_t) (val1); \
265 		*duk__p++ = (duk_uint8_t) (val2); \
266 		*duk__p++ = (duk_uint8_t) (val3); \
267 		*duk__p++ = (duk_uint8_t) (val4); \
268 		*duk__p++ = (duk_uint8_t) (val5); \
269 		(bw_ctx)->p = duk__p; \
270 	} while (0)
271 #define DUK_BW_WRITE_RAW_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \
272 		duk_uint8_t *duk__p; \
273 		DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 6); \
274 		duk__p = (bw_ctx)->p; \
275 		*duk__p++ = (duk_uint8_t) (val1); \
276 		*duk__p++ = (duk_uint8_t) (val2); \
277 		*duk__p++ = (duk_uint8_t) (val3); \
278 		*duk__p++ = (duk_uint8_t) (val4); \
279 		*duk__p++ = (duk_uint8_t) (val5); \
280 		*duk__p++ = (duk_uint8_t) (val6); \
281 		(bw_ctx)->p = duk__p; \
282 	} while (0)
283 #define DUK_BW_WRITE_RAW_XUTF8(thr,bw_ctx,cp) do { \
284 		duk_ucodepoint_t duk__cp; \
285 		duk_small_int_t duk__enc_len; \
286 		duk__cp = (cp); \
287 		DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_xutf8_length(duk__cp)); \
288 		duk__enc_len = duk_unicode_encode_xutf8(duk__cp, (bw_ctx)->p); \
289 		(bw_ctx)->p += duk__enc_len; \
290 	} while (0)
291 #define DUK_BW_WRITE_RAW_CESU8(thr,bw_ctx,cp) do { \
292 		duk_ucodepoint_t duk__cp; \
293 		duk_small_int_t duk__enc_len; \
294 		duk__cp = (duk_ucodepoint_t) (cp); \
295 		DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_cesu8_length(duk__cp)); \
296 		duk__enc_len = duk_unicode_encode_cesu8(duk__cp, (bw_ctx)->p); \
297 		(bw_ctx)->p += duk__enc_len; \
298 	} while (0)
299 /* XXX: add temporary duk__p pointer here too; sharing */
300 #define DUK_BW_WRITE_RAW_BYTES(thr,bw_ctx,valptr,valsz) do { \
301 		const void *duk__valptr; \
302 		duk_size_t duk__valsz; \
303 		duk__valptr = (const void *) (valptr); \
304 		duk__valsz = (duk_size_t) (valsz); \
305 		DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
306 		(bw_ctx)->p += duk__valsz; \
307 	} while (0)
308 #define DUK_BW_WRITE_RAW_CSTRING(thr,bw_ctx,val) do { \
309 		const duk_uint8_t *duk__val; \
310 		duk_size_t duk__val_len; \
311 		duk__val = (const duk_uint8_t *) (val); \
312 		duk__val_len = DUK_STRLEN((const char *) duk__val); \
313 		DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
314 		(bw_ctx)->p += duk__val_len; \
315 	} while (0)
316 #define DUK_BW_WRITE_RAW_HSTRING(thr,bw_ctx,val) do { \
317 		duk_size_t duk__val_len; \
318 		duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \
319 		DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
320 		(bw_ctx)->p += duk__val_len; \
321 	} while (0)
322 #define DUK_BW_WRITE_RAW_HBUFFER(thr,bw_ctx,val) do { \
323 		duk_size_t duk__val_len; \
324 		duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \
325 		DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
326 		(bw_ctx)->p += duk__val_len; \
327 	} while (0)
328 #define DUK_BW_WRITE_RAW_HBUFFER_FIXED(thr,bw_ctx,val) do { \
329 		duk_size_t duk__val_len; \
330 		duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \
331 		DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
332 		(bw_ctx)->p += duk__val_len; \
333 	} while (0)
334 #define DUK_BW_WRITE_RAW_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \
335 		duk_size_t duk__val_len; \
336 		duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \
337 		DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
338 		(bw_ctx)->p += duk__val_len; \
339 	} while (0)
340 
341 /* Append bytes from a slice already in the buffer. */
342 #define DUK_BW_WRITE_RAW_SLICE(thr,bw,dst_off,dst_len) \
343 	duk_bw_write_raw_slice((thr), (bw), (dst_off), (dst_len))
344 
345 /* Insert bytes in the middle of the buffer from an external buffer. */
346 #define DUK_BW_INSERT_RAW_BYTES(thr,bw,dst_off,buf,len) \
347 	duk_bw_insert_raw_bytes((thr), (bw), (dst_off), (buf), (len))
348 
349 /* Insert bytes in the middle of the buffer from a slice already
350  * in the buffer.  Source offset is interpreted "before" the operation.
351  */
352 #define DUK_BW_INSERT_RAW_SLICE(thr,bw,dst_off,src_off,len) \
353 	duk_bw_insert_raw_slice((thr), (bw), (dst_off), (src_off), (len))
354 
355 /* Insert a reserved area somewhere in the buffer; caller fills it.
356  * Evaluates to a (duk_uint_t *) pointing to the start of the reserved
357  * area for convenience.
358  */
359 #define DUK_BW_INSERT_RAW_AREA(thr,bw,off,len) \
360 	duk_bw_insert_raw_area((thr), (bw), (off), (len))
361 
362 /* Remove a slice from inside buffer. */
363 #define DUK_BW_REMOVE_RAW_SLICE(thr,bw,off,len) \
364 	duk_bw_remove_raw_slice((thr), (bw), (off), (len))
365 
366 /* Safe write calls which will ensure space first. */
367 
368 #define DUK_BW_WRITE_ENSURE_U8(thr,bw_ctx,val) do { \
369 		DUK_BW_ENSURE((thr), (bw_ctx), 1); \
370 		DUK_BW_WRITE_RAW_U8((thr), (bw_ctx), (val)); \
371 	} while (0)
372 #define DUK_BW_WRITE_ENSURE_U8_2(thr,bw_ctx,val1,val2) do { \
373 		DUK_BW_ENSURE((thr), (bw_ctx), 2); \
374 		DUK_BW_WRITE_RAW_U8_2((thr), (bw_ctx), (val1), (val2)); \
375 	} while (0)
376 #define DUK_BW_WRITE_ENSURE_U8_3(thr,bw_ctx,val1,val2,val3) do { \
377 		DUK_BW_ENSURE((thr), (bw_ctx), 3); \
378 		DUK_BW_WRITE_RAW_U8_3((thr), (bw_ctx), (val1), (val2), (val3)); \
379 	} while (0)
380 #define DUK_BW_WRITE_ENSURE_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \
381 		DUK_BW_ENSURE((thr), (bw_ctx), 4); \
382 		DUK_BW_WRITE_RAW_U8_4((thr), (bw_ctx), (val1), (val2), (val3), (val4)); \
383 	} while (0)
384 #define DUK_BW_WRITE_ENSURE_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \
385 		DUK_BW_ENSURE((thr), (bw_ctx), 5); \
386 		DUK_BW_WRITE_RAW_U8_5((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5)); \
387 	} while (0)
388 #define DUK_BW_WRITE_ENSURE_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \
389 		DUK_BW_ENSURE((thr), (bw_ctx), 6); \
390 		DUK_BW_WRITE_RAW_U8_6((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5), (val6)); \
391 	} while (0)
392 #define DUK_BW_WRITE_ENSURE_XUTF8(thr,bw_ctx,cp) do { \
393 		DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_XUTF8_LENGTH); \
394 		DUK_BW_WRITE_RAW_XUTF8((thr), (bw_ctx), (cp)); \
395 	} while (0)
396 #define DUK_BW_WRITE_ENSURE_CESU8(thr,bw_ctx,cp) do { \
397 		DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_CESU8_LENGTH); \
398 		DUK_BW_WRITE_RAW_CESU8((thr), (bw_ctx), (cp)); \
399 	} while (0)
400 /* XXX: add temporary duk__p pointer here too; sharing */
401 #define DUK_BW_WRITE_ENSURE_BYTES(thr,bw_ctx,valptr,valsz) do { \
402 		const void *duk__valptr; \
403 		duk_size_t duk__valsz; \
404 		duk__valptr = (const void *) (valptr); \
405 		duk__valsz = (duk_size_t) (valsz); \
406 		DUK_BW_ENSURE((thr), (bw_ctx), duk__valsz); \
407 		DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
408 		(bw_ctx)->p += duk__valsz; \
409 	} while (0)
410 #define DUK_BW_WRITE_ENSURE_CSTRING(thr,bw_ctx,val) do { \
411 		const duk_uint8_t *duk__val; \
412 		duk_size_t duk__val_len; \
413 		duk__val = (const duk_uint8_t *) (val); \
414 		duk__val_len = DUK_STRLEN((const char *) duk__val); \
415 		DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
416 		DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
417 		(bw_ctx)->p += duk__val_len; \
418 	} while (0)
419 #define DUK_BW_WRITE_ENSURE_HSTRING(thr,bw_ctx,val) do { \
420 		duk_size_t duk__val_len; \
421 		duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \
422 		DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
423 		DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
424 		(bw_ctx)->p += duk__val_len; \
425 	} while (0)
426 #define DUK_BW_WRITE_ENSURE_HBUFFER(thr,bw_ctx,val) do { \
427 		duk_size_t duk__val_len; \
428 		duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \
429 		DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
430 		DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
431 		(bw_ctx)->p += duk__val_len; \
432 	} while (0)
433 #define DUK_BW_WRITE_ENSURE_HBUFFER_FIXED(thr,bw_ctx,val) do { \
434 		duk_size_t duk__val_len; \
435 		duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \
436 		DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
437 		DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
438 		(bw_ctx)->p += duk__val_len; \
439 	} while (0)
440 #define DUK_BW_WRITE_ENSURE_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \
441 		duk_size_t duk__val_len; \
442 		duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \
443 		DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
444 		DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
445 		(bw_ctx)->p += duk__val_len; \
446 	} while (0)
447 
448 #define DUK_BW_WRITE_ENSURE_SLICE(thr,bw,dst_off,dst_len) \
449 	duk_bw_write_ensure_slice((thr), (bw), (dst_off), (dst_len))
450 #define DUK_BW_INSERT_ENSURE_BYTES(thr,bw,dst_off,buf,len) \
451 	duk_bw_insert_ensure_bytes((thr), (bw), (dst_off), (buf), (len))
452 #define DUK_BW_INSERT_ENSURE_SLICE(thr,bw,dst_off,src_off,len) \
453 	duk_bw_insert_ensure_slice((thr), (bw), (dst_off), (src_off), (len))
454 #define DUK_BW_INSERT_ENSURE_AREA(thr,bw,off,len) \
455 	/* Evaluates to (duk_uint8_t *) pointing to start of area. */ \
456 	duk_bw_insert_ensure_area((thr), (bw), (off), (len))
457 #define DUK_BW_REMOVE_ENSURE_SLICE(thr,bw,off,len) \
458 	/* No difference between raw/ensure because the buffer shrinks. */ \
459 	DUK_BW_REMOVE_RAW_SLICE((thr), (bw), (off), (len))
460 
461 /*
462  *  Externs and prototypes
463  */
464 
465 #if !defined(DUK_SINGLE_FILE)
466 DUK_INTERNAL_DECL const duk_uint8_t duk_lc_digits[36];
467 DUK_INTERNAL_DECL const duk_uint8_t duk_uc_nybbles[16];
468 DUK_INTERNAL_DECL const duk_int8_t duk_hex_dectab[256];
469 #if defined(DUK_USE_HEX_FASTPATH)
470 DUK_INTERNAL_DECL const duk_int16_t duk_hex_dectab_shift4[256];
471 DUK_INTERNAL_DECL const duk_uint16_t duk_hex_enctab[256];
472 #endif
473 #if defined(DUK_USE_BASE64_FASTPATH)
474 DUK_INTERNAL_DECL const duk_uint8_t duk_base64_enctab[64];
475 DUK_INTERNAL_DECL const duk_int8_t duk_base64_dectab[256];
476 #endif
477 #endif  /* !DUK_SINGLE_FILE */
478 
479 /* Note: assumes that duk_util_probe_steps size is 32 */
480 #if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
481 #if !defined(DUK_SINGLE_FILE)
482 DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32];
483 #endif  /* !DUK_SINGLE_FILE */
484 #endif
485 
486 #if defined(DUK_USE_STRHASH_DENSE)
487 DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed);
488 #endif
489 
490 #if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
491 DUK_INTERNAL_DECL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size);
492 #endif
493 
494 DUK_INTERNAL_DECL duk_int32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits);
495 DUK_INTERNAL_DECL duk_small_int_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx);
496 DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value);
497 
498 DUK_INTERNAL_DECL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits);
499 DUK_INTERNAL_DECL void duk_be_finish(duk_bitencoder_ctx *ctx);
500 
501 DUK_INTERNAL_DECL duk_uint32_t duk_util_tinyrandom_get_bits(duk_hthread *thr, duk_small_int_t n);
502 DUK_INTERNAL_DECL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr);
503 
504 DUK_INTERNAL_DECL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf);
505 DUK_INTERNAL_DECL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size);
506 DUK_INTERNAL_DECL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz);
507 DUK_INTERNAL_DECL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx);
508 DUK_INTERNAL_DECL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len);
509 DUK_INTERNAL_DECL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len);
510 DUK_INTERNAL_DECL void duk_bw_insert_raw_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len);
511 DUK_INTERNAL_DECL void duk_bw_insert_ensure_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len);
512 DUK_INTERNAL_DECL void duk_bw_insert_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len);
513 DUK_INTERNAL_DECL void duk_bw_insert_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len);
514 DUK_INTERNAL_DECL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len);
515 DUK_INTERNAL_DECL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len);
516 DUK_INTERNAL_DECL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len);
517 /* No duk_bw_remove_ensure_slice(), functionality would be identical. */
518 
519 DUK_INTERNAL_DECL duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p);
520 DUK_INTERNAL_DECL duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p);
521 DUK_INTERNAL_DECL duk_double_t duk_raw_read_double_be(duk_uint8_t **p);
522 DUK_INTERNAL_DECL void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val);
523 DUK_INTERNAL_DECL void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val);
524 DUK_INTERNAL_DECL void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val);
525 
526 #if defined(DUK_USE_DEBUGGER_SUPPORT)  /* For now only needed by the debugger. */
527 DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len);
528 #endif
529 
530 #endif  /* DUK_UTIL_H_INCLUDED */
531