1 /* ====================================================================
2 * The Kannel Software License, Version 1.0
3 *
4 * Copyright (c) 2001-2014 Kannel Group
5 * Copyright (c) 1998-2001 WapIT Ltd.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution,
21 * if any, must include the following acknowledgment:
22 * "This product includes software developed by the
23 * Kannel Group (http://www.kannel.org/)."
24 * Alternately, this acknowledgment may appear in the software itself,
25 * if and wherever such third-party acknowledgments normally appear.
26 *
27 * 4. The names "Kannel" and "Kannel Group" must not be used to
28 * endorse or promote products derived from this software without
29 * prior written permission. For written permission, please
30 * contact org@kannel.org.
31 *
32 * 5. Products derived from this software may not be called "Kannel",
33 * nor may "Kannel" appear in their name, without prior written
34 * permission of the Kannel Group.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Kannel Group. For more information on
51 * the Kannel Group, please see <http://www.kannel.org/>.
52 *
53 * Portions of this software are based upon software originally written at
54 * WapIT Ltd., Helsinki, Finland for the Kannel project.
55 */
56
57 /*
58 *
59 * wsbc.c
60 *
61 * Author: Markku Rossi <mtr@iki.fi>
62 *
63 * Copyright (c) 1999-2000 WAPIT OY LTD.
64 * All rights reserved.
65 *
66 * Byte-code handling functions.
67 *
68 */
69
70 #include "wsint.h"
71 #include "wsbc.h"
72
73 /********************* Prototypes for static functions ******************/
74
75 /* Add a new pragma of type `type' to the byte-code `bc'. The
76 * function returns a pointer to an internal pragma structure that
77 * must not be freed by the caller. It is freed when the byte-code
78 * `bc' is freed. The function returns NULL if the pragma structure
79 * could not be allocated. */
80 static WsBcPragma *add_pragma(WsBc *bc, WsBcPragmaType type);
81
82 /********************* Manipulating byte-code structure *****************/
83
ws_bc_alloc(WsBcStringEncoding string_encoding)84 WsBc *ws_bc_alloc(WsBcStringEncoding string_encoding)
85 {
86 WsBc *bc = ws_calloc(1, sizeof(WsBc));
87
88 if (bc == NULL)
89 return NULL;
90
91 bc->string_encoding = string_encoding;
92
93 return bc;
94 }
95
96
ws_bc_free(WsBc * bc)97 void ws_bc_free(WsBc *bc)
98 {
99 WsUInt16 i;
100 WsUInt8 j;
101
102 if (bc == NULL)
103 return;
104
105 /* Free constants. */
106 for (i = 0; i < bc->num_constants; i++) {
107 WsBcConstant *c = &bc->constants[i];
108
109 if (c->type == WS_BC_CONST_TYPE_UTF8_STRING)
110 ws_free(c->u.v_string.data);
111 }
112 ws_free(bc->constants);
113
114 /* Free pragmas. */
115 ws_free(bc->pragmas);
116
117 /* Free function names. */
118 for (j = 0; j < bc->num_function_names; j++)
119 ws_free(bc->function_names[j].name);
120 ws_free(bc->function_names);
121
122 /* Free functions. */
123 for (j = 0; j < bc->num_functions; j++)
124 ws_free(bc->functions[j].code);
125 ws_free(bc->functions);
126
127 /* Free the byte-code structure. */
128 ws_free(bc);
129 }
130
131
ws_bc_encode(WsBc * bc,unsigned char ** data_return,size_t * data_len_return)132 WsBool ws_bc_encode(WsBc *bc, unsigned char **data_return,
133 size_t *data_len_return)
134 {
135 WsBuffer buffer;
136 WsUInt32 ui;
137 unsigned char data[64];
138 unsigned char *p, *mb;
139 size_t len;
140
141 ws_buffer_init(&buffer);
142
143 /* Append space for the header. We do not know yet the size of the
144 resulting byte-code. */
145 if (!ws_buffer_append_space(&buffer, NULL, WS_BC_MAX_HEADER_LEN))
146 goto error;
147
148
149 /* Constants. */
150
151 if (!ws_encode_buffer(&buffer,
152 WS_ENC_MB_UINT16, bc->num_constants,
153 WS_ENC_MB_UINT16, (WsUInt16) bc->string_encoding,
154 WS_ENC_END))
155 goto error;
156
157 for (ui = 0 ; ui < bc->num_constants; ui++) {
158 switch (bc->constants[ui].type) {
159 case WS_BC_CONST_TYPE_INT:
160 if (WS_INT8_MIN <= bc->constants[ui].u.v_int
161 && bc->constants[ui].u.v_int <= WS_INT8_MAX) {
162 if (!ws_encode_buffer(&buffer,
163 WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_INT8,
164 WS_ENC_INT8,
165 (WsInt8) bc->constants[ui].u.v_int,
166 WS_ENC_END))
167 goto error;
168 } else if (WS_INT16_MIN <= bc->constants[ui].u.v_int
169 && bc->constants[ui].u.v_int <= WS_INT16_MAX) {
170 if (!ws_encode_buffer(&buffer,
171 WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_INT16,
172 WS_ENC_INT16,
173 (WsInt16) bc->constants[ui].u.v_int,
174 WS_ENC_END))
175 goto error;
176 } else {
177 if (!ws_encode_buffer(&buffer,
178 WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_INT32,
179 WS_ENC_INT32, bc->constants[ui].u.v_int,
180 WS_ENC_END))
181 goto error;
182 }
183 break;
184
185 case WS_BC_CONST_TYPE_FLOAT32:
186 case WS_BC_CONST_TYPE_FLOAT32_NAN:
187 case WS_BC_CONST_TYPE_FLOAT32_POSITIVE_INF:
188 case WS_BC_CONST_TYPE_FLOAT32_NEGATIVE_INF:
189 switch (bc->constants[ui].type) {
190 case WS_BC_CONST_TYPE_FLOAT32:
191 ws_ieee754_encode_single(bc->constants[ui].u.v_float, data);
192 p = data;
193 break;
194
195 case WS_BC_CONST_TYPE_FLOAT32_NAN:
196 p = ws_ieee754_nan;
197 break;
198
199 case WS_BC_CONST_TYPE_FLOAT32_POSITIVE_INF:
200 p = ws_ieee754_positive_inf;
201 break;
202
203 case WS_BC_CONST_TYPE_FLOAT32_NEGATIVE_INF:
204 p = ws_ieee754_negative_inf;
205 break;
206
207 default:
208 ws_fatal("ws_bc_encode(): internal inconsistency");
209 /* NOTREACHED */
210 p = NULL; /* Initialized to keep compiler quiet. */
211 break;
212 }
213
214 if (!ws_encode_buffer(&buffer,
215 WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_FLOAT32,
216 WS_ENC_DATA, p, 4,
217 WS_ENC_END))
218 goto error;
219 break;
220
221 break;
222
223 case WS_BC_CONST_TYPE_UTF8_STRING:
224 /* Encode the strings as requested. */
225 switch (bc->string_encoding) {
226 case WS_BC_STRING_ENC_ISO_8859_1:
227 {
228 WsUtf8String *string = ws_utf8_alloc();
229 unsigned char *latin1;
230 size_t latin1_len;
231 WsBool success;
232
233 if (string == NULL)
234 goto error;
235
236 /* Create an UTF-8 string. */
237 if (!ws_utf8_set_data(string,
238 bc->constants[ui].u.v_string.data,
239 bc->constants[ui].u.v_string.len)) {
240 ws_utf8_free(string);
241 goto error;
242 }
243
244 /* Convert it to latin1. */
245 latin1 = ws_utf8_to_latin1(string, '?', &latin1_len);
246
247 /* We'r done with the UTF-8 string. */
248 ws_utf8_free(string);
249
250 if (latin1 == NULL)
251 goto error;
252
253 /* Encode it. */
254 success = ws_encode_buffer(
255 &buffer,
256 WS_ENC_UINT8,
257 (WsUInt8) WS_BC_CONST_EXT_ENC_STRING,
258
259 WS_ENC_MB_UINT32, (WsUInt32) latin1_len,
260 WS_ENC_DATA, latin1, latin1_len,
261
262 WS_ENC_END);
263 ws_utf8_free_data(latin1);
264
265 if (!success)
266 goto error;
267 }
268 break;
269
270 case WS_BC_STRING_ENC_UTF8:
271 if (!ws_encode_buffer(
272 &buffer,
273 WS_ENC_UINT8,
274 (WsUInt8) WS_BC_CONST_UTF8_STRING,
275
276 WS_ENC_MB_UINT32,
277 (WsUInt32) bc->constants[ui].u.v_string.len,
278
279 WS_ENC_DATA,
280 bc->constants[ui].u.v_string.data,
281 bc->constants[ui].u.v_string.len,
282
283 WS_ENC_END))
284 goto error;
285 break;
286 }
287 break;
288
289 case WS_BC_CONST_TYPE_EMPTY_STRING:
290 if (!ws_encode_buffer(&buffer,
291 WS_ENC_UINT8,
292 (WsUInt8) WS_BC_CONST_EMPTY_STRING,
293 WS_ENC_END))
294 goto error;
295 break;
296 }
297 }
298
299
300 /* Pragmas. */
301
302 if (!ws_encode_buffer(&buffer,
303 WS_ENC_MB_UINT16, bc->num_pragmas,
304 WS_ENC_END))
305 goto error;
306
307 for (ui = 0; ui < bc->num_pragmas; ui++) {
308 switch (bc->pragmas[ui].type) {
309 case WS_BC_PRAGMA_TYPE_ACCESS_DOMAIN:
310 if (!ws_encode_buffer(&buffer,
311 WS_ENC_UINT8,
312 (WsUInt8) WS_BC_PRAGMA_ACCESS_DOMAIN,
313
314 WS_ENC_MB_UINT16, bc->pragmas[ui].index_1,
315 WS_ENC_END))
316 goto error;
317 break;
318
319 case WS_BC_PRAGMA_TYPE_ACCESS_PATH:
320 if (!ws_encode_buffer(&buffer,
321 WS_ENC_UINT8,
322 (WsUInt8) WS_BC_PRAGMA_ACCESS_PATH,
323 WS_ENC_MB_UINT16, bc->pragmas[ui].index_1,
324 WS_ENC_END))
325 goto error;
326 break;
327
328 case WS_BC_PRAGMA_TYPE_USER_AGENT_PROPERTY:
329 if (!ws_encode_buffer(&buffer,
330 WS_ENC_UINT8,
331 (WsUInt8) WS_BC_PRAGMA_USER_AGENT_PROPERTY,
332 WS_ENC_MB_UINT16, bc->pragmas[ui].index_1,
333 WS_ENC_MB_UINT16, bc->pragmas[ui].index_2,
334 WS_ENC_END))
335 goto error;
336 break;
337
338 case WS_BC_PRAGMA_TYPE_USER_AGENT_PROPERTY_AND_SCHEME:
339 if (!ws_encode_buffer(
340 &buffer,
341 WS_ENC_UINT8,
342 (WsUInt8) WS_BC_PRAGMA_USER_AGENT_PROPERTY_AND_SCHEME,
343 WS_ENC_MB_UINT16, bc->pragmas[ui].index_1,
344 WS_ENC_MB_UINT16, bc->pragmas[ui].index_2,
345 WS_ENC_MB_UINT16, bc->pragmas[ui].index_3,
346 WS_ENC_END))
347 goto error;
348 break;
349 }
350 }
351
352
353 /* Function pool. */
354
355 if (!ws_encode_buffer(&buffer,
356 WS_ENC_UINT8, bc->num_functions,
357 WS_ENC_END))
358 goto error;
359
360 /* Function names. */
361
362 if (!ws_encode_buffer(&buffer,
363 WS_ENC_UINT8, bc->num_function_names,
364 WS_ENC_END))
365 goto error;
366
367 for (ui = 0; ui < bc->num_function_names; ui++) {
368 size_t name_len = strlen(bc->function_names[ui].name);
369
370 if (!ws_encode_buffer(&buffer,
371 WS_ENC_UINT8, bc->function_names[ui].index,
372 WS_ENC_UINT8, (WsUInt8) name_len,
373 WS_ENC_DATA, bc->function_names[ui].name, name_len,
374 WS_ENC_END))
375 goto error;
376 }
377
378 /* Functions. */
379
380 for (ui = 0; ui < bc->num_functions; ui++) {
381 if (!ws_encode_buffer(&buffer,
382 WS_ENC_UINT8, bc->functions[ui].num_arguments,
383 WS_ENC_UINT8, bc->functions[ui].num_locals,
384 WS_ENC_MB_UINT32, bc->functions[ui].code_size,
385 WS_ENC_DATA, bc->functions[ui].code,
386 (size_t) bc->functions[ui].code_size,
387 WS_ENC_END))
388 goto error;
389 }
390
391
392 /* Fix the byte-code header. */
393
394 p = ws_buffer_ptr(&buffer);
395
396 /* Encode the size of the byte-code excluding the byte-code header. */
397 mb = ws_encode_mb_uint32(ws_buffer_len(&buffer) - WS_BC_MAX_HEADER_LEN,
398 data, &len);
399 memcpy(p + WS_BC_MAX_HEADER_LEN - len, mb, len);
400
401 /* Set the byte-code file version information. */
402 WS_PUT_UINT8(p + WS_BC_MAX_HEADER_LEN - len - 1, WS_BC_VERSION);
403
404 /* Calculate the beginning of the bc-array and its size. */
405 *data_return = p + WS_BC_MAX_HEADER_LEN - len - 1;
406 *data_len_return = ws_buffer_len(&buffer) - WS_BC_MAX_HEADER_LEN + len + 1;
407
408 /* All done. */
409 return WS_TRUE;
410
411
412 /*
413 * Error handling.
414 */
415
416 error:
417
418 ws_buffer_uninit(&buffer);
419 *data_return = NULL;
420 *data_len_return = 0;
421
422 return WS_FALSE;
423 }
424
425
ws_bc_data_free(unsigned char * data)426 void ws_bc_data_free(unsigned char *data)
427 {
428 size_t len = WS_MB_UINT32_MAX_ENCODED_LEN;
429
430 if (data == NULL)
431 return;
432
433 /* Decode the mb-encoded length so we know how much space it uses. */
434 (void) ws_decode_mb_uint32(data + 1, &len);
435
436 /* Now we can compute the beginning of the array `data'. */
437 ws_free(data - (WS_MB_UINT32_MAX_ENCODED_LEN - len));
438 }
439
440
441 /* A helper macro to update the data pointers during the decoding of
442 byte-code data. */
443 #define WS_UPDATE_DATA \
444 data += decoded; \
445 data_len -= decoded
446
447 /* A helper macro to check the validity of the constant string index
448 `idx'. */
449 #define WS_CHECK_STRING(idx) \
450 if ((idx) >= bc->num_constants \
451 || ((bc->constants[(idx)].type \
452 != WS_BC_CONST_TYPE_UTF8_STRING) \
453 && (bc->constants[(idx)].type \
454 != WS_BC_CONST_TYPE_EMPTY_STRING))) \
455 goto error;
456
ws_bc_decode(const unsigned char * data,size_t data_len)457 WsBc *ws_bc_decode(const unsigned char *data, size_t data_len)
458 {
459 WsBc *bc = ws_bc_alloc(WS_BC_STRING_ENC_ISO_8859_1);
460 WsByte b;
461 WsUInt32 ui32;
462 WsUInt16 ui16, j;
463 WsUInt16 ui16b;
464 WsUInt8 ui8, num_functions, k, l;
465 WsInt8 i8;
466 WsInt16 i16;
467 WsInt32 i32;
468 WsIeee754Result ieee754;
469 unsigned char *ucp;
470 size_t decoded;
471
472 /* Decode the byte-code header. */
473 decoded = ws_decode_buffer(data, data_len,
474 WS_ENC_BYTE, &b,
475 WS_ENC_MB_UINT32, &ui32,
476 WS_ENC_END);
477
478 if (!decoded
479 || b != WS_BC_VERSION
480 || ui32 != data_len - decoded)
481 /* This is not a valid (or supported) byte-code header. */
482 goto error;
483
484 WS_UPDATE_DATA;
485
486 /* Constant pool. */
487
488 decoded = ws_decode_buffer(data, data_len,
489 WS_ENC_MB_UINT16, &ui16,
490 WS_ENC_MB_UINT16, &ui16b,
491 WS_ENC_END);
492 if (!decoded)
493 goto error;
494
495 bc->string_encoding = ui16b;
496
497 bc->constants = ws_calloc(ui16, sizeof(WsBcConstant));
498 if (bc->constants == NULL)
499 goto error;
500 bc->num_constants = ui16;
501
502 WS_UPDATE_DATA;
503
504 for (j = 0; j < bc->num_constants; j++) {
505 WsBcConstant *c = &bc->constants[j];
506
507 decoded = ws_decode_buffer(data, data_len,
508 WS_ENC_UINT8, &ui8,
509 WS_ENC_END);
510 if (decoded != 1)
511 goto error;
512
513 WS_UPDATE_DATA;
514
515 switch (ui8) {
516 case WS_BC_CONST_INT8:
517 decoded = ws_decode_buffer(data, data_len,
518 WS_ENC_INT8, &i8,
519 WS_ENC_END);
520 if (decoded != 1)
521 goto error;
522
523 WS_UPDATE_DATA;
524
525 c->type = WS_BC_CONST_TYPE_INT;
526 c->u.v_int = i8;
527 break;
528
529 case WS_BC_CONST_INT16:
530 decoded = ws_decode_buffer(data, data_len,
531 WS_ENC_INT16, &i16,
532 WS_ENC_END);
533 if (decoded != 2)
534 goto error;
535
536 WS_UPDATE_DATA;
537
538 c->type = WS_BC_CONST_TYPE_INT;
539 c->u.v_int = i16;
540 break;
541
542 case WS_BC_CONST_INT32:
543 decoded = ws_decode_buffer(data, data_len,
544 WS_ENC_INT32, &i32,
545 WS_ENC_END);
546 if (decoded != 4)
547 goto error;
548
549 WS_UPDATE_DATA;
550
551 c->type = WS_BC_CONST_TYPE_INT;
552 c->u.v_int = i32;
553 break;
554
555 case WS_BC_CONST_FLOAT32:
556 decoded = ws_decode_buffer(data, data_len,
557 WS_ENC_DATA, &ucp, (size_t) 4,
558 WS_ENC_END);
559 if (decoded != 4)
560 goto error;
561
562 WS_UPDATE_DATA;
563
564 ieee754 = ws_ieee754_decode_single(ucp, &c->u.v_float);
565
566 switch (ieee754) {
567 case WS_IEEE754_OK:
568 c->type = WS_BC_CONST_TYPE_FLOAT32;
569 break;
570
571 case WS_IEEE754_NAN:
572 c->type = WS_BC_CONST_TYPE_FLOAT32_NAN;
573 break;
574
575 case WS_IEEE754_POSITIVE_INF:
576 c->type = WS_BC_CONST_TYPE_FLOAT32_POSITIVE_INF;
577 break;
578
579 case WS_IEEE754_NEGATIVE_INF:
580 c->type = WS_BC_CONST_TYPE_FLOAT32_NEGATIVE_INF;
581 break;
582 }
583
584 break;
585
586 case WS_BC_CONST_UTF8_STRING:
587 decoded = ws_decode_buffer(data, data_len,
588 WS_ENC_MB_UINT32, &ui32,
589 WS_ENC_END);
590 if (decoded == 0)
591 goto error;
592
593 WS_UPDATE_DATA;
594
595 c->type = WS_BC_CONST_TYPE_UTF8_STRING;
596 c->u.v_string.len = ui32;
597
598 decoded = ws_decode_buffer(data, data_len,
599 WS_ENC_DATA, &ucp, c->u.v_string.len,
600 WS_ENC_END);
601 if (decoded != ui32)
602 goto error;
603
604 WS_UPDATE_DATA;
605
606 c->u.v_string.data = ws_memdup(ucp, ui32);
607 if (c->u.v_string.data == NULL)
608 goto error;
609
610 /* Check the validity of the data. */
611 if (!ws_utf8_verify(c->u.v_string.data, c->u.v_string.len,
612 &c->u.v_string.num_chars))
613 goto error;
614 break;
615
616 case WS_BC_CONST_EMPTY_STRING:
617 c->type = WS_BC_CONST_TYPE_EMPTY_STRING;
618 break;
619
620 case WS_BC_CONST_EXT_ENC_STRING:
621 ws_fatal("external character encoding not implemented yet");
622 break;
623
624 default:
625 /* Reserved. */
626 goto error;
627 break;
628 }
629 }
630
631 /* Pragma pool. */
632
633 decoded = ws_decode_buffer(data, data_len,
634 WS_ENC_MB_UINT16, &ui16,
635 WS_ENC_END);
636 if (!decoded)
637 goto error;
638
639 bc->pragmas = ws_calloc(ui16, sizeof(WsBcPragma));
640 if (bc->pragmas == NULL)
641 goto error;
642 bc->num_pragmas = ui16;
643
644 WS_UPDATE_DATA;
645
646 for (j = 0; j < bc->num_pragmas; j++) {
647 WsBcPragma *p = &bc->pragmas[j];
648
649 decoded = ws_decode_buffer(data, data_len,
650 WS_ENC_UINT8, &ui8,
651 WS_ENC_END);
652 if (decoded != 1)
653 goto error;
654
655 WS_UPDATE_DATA;
656
657 p->type = ui8;
658
659 switch (ui8) {
660 case WS_BC_PRAGMA_ACCESS_DOMAIN:
661 decoded = ws_decode_buffer(data, data_len,
662 WS_ENC_MB_UINT16, &p->index_1,
663 WS_ENC_END);
664 if (!decoded)
665 goto error;
666
667 WS_CHECK_STRING(p->index_1);
668 break;
669
670 case WS_BC_PRAGMA_ACCESS_PATH:
671 decoded = ws_decode_buffer(data, data_len,
672 WS_ENC_MB_UINT16, &p->index_1,
673 WS_ENC_END);
674 if (!decoded)
675 goto error;
676
677 WS_CHECK_STRING(p->index_1);
678 break;
679
680 case WS_BC_PRAGMA_USER_AGENT_PROPERTY:
681 decoded = ws_decode_buffer(data, data_len,
682 WS_ENC_MB_UINT16, &p->index_1,
683 WS_ENC_MB_UINT16, &p->index_2,
684 WS_ENC_END);
685 if (!decoded)
686 goto error;
687
688 WS_CHECK_STRING(p->index_1);
689 WS_CHECK_STRING(p->index_2);
690 break;
691
692 case WS_BC_PRAGMA_USER_AGENT_PROPERTY_AND_SCHEME:
693 decoded = ws_decode_buffer(data, data_len,
694 WS_ENC_MB_UINT16, &p->index_1,
695 WS_ENC_MB_UINT16, &p->index_2,
696 WS_ENC_MB_UINT16, &p->index_3,
697 WS_ENC_END);
698 if (!decoded)
699 goto error;
700
701 WS_CHECK_STRING(p->index_1);
702 WS_CHECK_STRING(p->index_2);
703 WS_CHECK_STRING(p->index_3);
704 break;
705
706 default:
707 goto error;
708 break;
709 }
710
711 WS_UPDATE_DATA;
712 }
713
714 /* Function pool. */
715
716 decoded = ws_decode_buffer(data, data_len,
717 WS_ENC_UINT8, &num_functions,
718 WS_ENC_END);
719 if (decoded != 1)
720 goto error;
721
722 WS_UPDATE_DATA;
723
724 /* Function names. */
725
726 decoded = ws_decode_buffer(data, data_len,
727 WS_ENC_UINT8, &ui8,
728 WS_ENC_END);
729 if (decoded != 1)
730 goto error;
731
732 WS_UPDATE_DATA;
733
734 if (ui8) {
735 /* We have function names. */
736 bc->function_names = ws_calloc(ui8, sizeof(WsBcFunctionName));
737 if (bc->function_names == NULL)
738 goto error;
739 bc->num_function_names = ui8;
740
741 for (k = 0; k < bc->num_function_names; k++) {
742 WsBcFunctionName *n = &bc->function_names[k];
743
744 decoded = ws_decode_buffer(data, data_len,
745 WS_ENC_UINT8, &n->index,
746 WS_ENC_UINT8, &ui8,
747 WS_ENC_END);
748 if (decoded != 2)
749 goto error;
750
751 WS_UPDATE_DATA;
752
753 decoded = ws_decode_buffer(data, data_len,
754 WS_ENC_DATA, &ucp, (size_t) ui8,
755 WS_ENC_END);
756 if (decoded != ui8)
757 goto error;
758
759 WS_UPDATE_DATA;
760
761 n->name = ws_memdup(ucp, ui8);
762 if (n->name == NULL)
763 goto error;
764
765 /* Check the validity of the name. */
766
767 if (!ws_utf8_verify((unsigned char *) n->name, ui8, NULL))
768 goto error;
769
770 /* Just check that the data contains only valid characters. */
771 for (l = 0; l < ui8; l++) {
772 unsigned int ch = (unsigned char) n->name[l];
773
774 if (('a' <= ch && ch <= 'z')
775 || ('A' <= ch && ch <= 'Z')
776 || ch == '_'
777 || (l > 0 && ('0' <= ch && ch <= '9')))
778 /* Ok. */
779 continue;
780
781 /* Invalid character in the function name. */
782 goto error;
783 }
784
785 /* Is the index valid? */
786 if (n->index >= num_functions)
787 goto error;
788 }
789 }
790
791 /* Functions. */
792
793 if (num_functions) {
794 /* We have functions. */
795 bc->functions = ws_calloc(num_functions, sizeof(WsBcFunction));
796 if (bc->functions == NULL)
797 goto error;
798 bc->num_functions = num_functions;
799
800 for (k = 0; k < bc->num_functions; k++) {
801 WsBcFunction *f = &bc->functions[k];
802
803 decoded = ws_decode_buffer(data, data_len,
804 WS_ENC_UINT8, &f->num_arguments,
805 WS_ENC_UINT8, &f->num_locals,
806 WS_ENC_MB_UINT32, &f->code_size,
807 WS_ENC_END);
808 if (!decoded)
809 goto error;
810
811 WS_UPDATE_DATA;
812
813 decoded = ws_decode_buffer(data, data_len,
814 WS_ENC_DATA, &ucp, f->code_size,
815 WS_ENC_END);
816 if (decoded != f->code_size)
817 goto error;
818
819 WS_UPDATE_DATA;
820
821 if (f->code_size) {
822 /* It is not an empty function. */
823 f->code = ws_memdup(ucp, f->code_size);
824 if (f->code == NULL)
825 goto error;
826 }
827 }
828 }
829
830 /* Did we process it all? */
831 if (data_len != 0)
832 goto error;
833
834 /* All done. */
835 return bc;
836
837 /*
838 * Error handling.
839 */
840
841 error:
842
843 ws_bc_free(bc);
844
845 return NULL;
846 }
847
848 /********************* Adding constant elements *************************/
849
ws_bc_add_const_int(WsBc * bc,WsUInt16 * index_return,WsInt32 value)850 WsBool ws_bc_add_const_int(WsBc *bc, WsUInt16 *index_return, WsInt32 value)
851 {
852 WsUInt16 i;
853 WsBcConstant *nc;
854
855 /* Do we already have a suitable integer constant? */
856 for (i = 0; i < bc->num_constants; i++) {
857 if (bc->constants[i].type == WS_BC_CONST_TYPE_INT
858 && bc->constants[i].u.v_int == value) {
859 *index_return = i;
860 return WS_TRUE;
861 }
862 }
863
864 /* Must add a new constant. */
865
866 nc = ws_realloc(bc->constants,
867 (bc->num_constants + 1) * sizeof(WsBcConstant));
868 if (nc == NULL)
869 return WS_FALSE;
870
871 bc->constants = nc;
872 bc->constants[bc->num_constants].type = WS_BC_CONST_TYPE_INT;
873 bc->constants[bc->num_constants].u.v_int = value;
874
875 *index_return = bc->num_constants++;
876
877 return WS_TRUE;
878 }
879
880
ws_bc_add_const_float(WsBc * bc,WsUInt16 * index_return,WsFloat value)881 WsBool ws_bc_add_const_float(WsBc *bc, WsUInt16 *index_return, WsFloat value)
882 {
883 WsUInt16 i;
884 WsBcConstant *nc;
885
886 /* Do we already have a suitable float32 constant? */
887 for (i = 0; i < bc->num_constants; i++) {
888 if (bc->constants[i].type == WS_BC_CONST_TYPE_FLOAT32
889 && bc->constants[i].u.v_float == value) {
890 *index_return = i;
891 return WS_TRUE;
892 }
893 }
894
895 /* Must add a new constant. */
896
897 nc = ws_realloc(bc->constants,
898 (bc->num_constants + 1) * sizeof(WsBcConstant));
899 if (nc == NULL)
900 return WS_FALSE;
901
902 bc->constants = nc;
903 bc->constants[bc->num_constants].type = WS_BC_CONST_TYPE_FLOAT32;
904 bc->constants[bc->num_constants].u.v_float = value;
905
906 *index_return = bc->num_constants++;
907
908 return WS_TRUE;
909 }
910
911
ws_bc_add_const_utf8_string(WsBc * bc,WsUInt16 * index_return,const unsigned char * data,size_t len)912 WsBool ws_bc_add_const_utf8_string(WsBc *bc, WsUInt16 *index_return,
913 const unsigned char *data, size_t len)
914 {
915 WsUInt16 i;
916 WsBcConstant *nc;
917
918 /* Do we already have a suitable UFT-8 constant? */
919 for (i = 0; i < bc->num_constants; i++) {
920 if (bc->constants[i].type == WS_BC_CONST_TYPE_UTF8_STRING
921 && bc->constants[i].u.v_string.len == len
922 && memcmp(bc->constants[i].u.v_string.data,
923 data, len) == 0) {
924 *index_return = i;
925 return WS_TRUE;
926 }
927 }
928
929 /* Must add a new constant. */
930
931 nc = ws_realloc(bc->constants,
932 (bc->num_constants + 1) * sizeof(WsBcConstant));
933 if (nc == NULL)
934 return WS_FALSE;
935
936 bc->constants = nc;
937 bc->constants[bc->num_constants].type = WS_BC_CONST_TYPE_UTF8_STRING;
938 bc->constants[bc->num_constants].u.v_string.len = len;
939 bc->constants[bc->num_constants].u.v_string.data
940 = ws_memdup(data, len);
941 if (bc->constants[bc->num_constants].u.v_string.data == NULL)
942 return WS_FALSE;
943
944 *index_return = bc->num_constants++;
945
946 return WS_TRUE;
947 }
948
949
950
ws_bc_add_const_empty_string(WsBc * bc,WsUInt16 * index_return)951 WsBool ws_bc_add_const_empty_string(WsBc *bc, WsUInt16 *index_return)
952 {
953 WsUInt16 i;
954 WsBcConstant *nc;
955
956 /* Do we already have a suitable empty string constant? */
957 for (i = 0; i < bc->num_constants; i++) {
958 if (bc->constants[i].type == WS_BC_CONST_TYPE_EMPTY_STRING) {
959 *index_return = i;
960 return WS_TRUE;
961 }
962 }
963
964 /* Must add a new constant. */
965
966 nc = ws_realloc(bc->constants,
967 (bc->num_constants + 1) * sizeof(WsBcConstant));
968 if (nc == NULL)
969 return WS_FALSE;
970
971 bc->constants = nc;
972 bc->constants[bc->num_constants].type = WS_BC_CONST_TYPE_EMPTY_STRING;
973
974 *index_return = bc->num_constants++;
975
976 return WS_TRUE;
977 }
978
979 /********************* Adding pragmas ***********************************/
980
ws_bc_add_pragma_access_domain(WsBc * bc,const unsigned char * domain,size_t domain_len)981 WsBool ws_bc_add_pragma_access_domain(WsBc *bc, const unsigned char *domain,
982 size_t domain_len)
983 {
984 WsBcPragma *p = add_pragma(bc, WS_BC_PRAGMA_TYPE_ACCESS_DOMAIN);
985
986 if (p == NULL)
987 return WS_FALSE;
988
989 if (!ws_bc_add_const_utf8_string(bc, &p->index_1, domain, domain_len))
990 return WS_FALSE;
991
992 return WS_TRUE;
993 }
994
995
ws_bc_add_pragma_access_path(WsBc * bc,const unsigned char * path,size_t path_len)996 WsBool ws_bc_add_pragma_access_path(WsBc *bc, const unsigned char *path,
997 size_t path_len)
998 {
999 WsBcPragma *p = add_pragma(bc, WS_BC_PRAGMA_TYPE_ACCESS_PATH);
1000
1001 if (p == NULL)
1002 return WS_FALSE;
1003
1004 if (!ws_bc_add_const_utf8_string(bc, &p->index_1, path, path_len))
1005 return WS_FALSE;
1006
1007 return WS_TRUE;
1008 }
1009
1010
ws_bc_add_pragma_user_agent_property(WsBc * bc,const unsigned char * name,size_t name_len,const unsigned char * property,size_t property_len)1011 WsBool ws_bc_add_pragma_user_agent_property(WsBc *bc,
1012 const unsigned char *name,
1013 size_t name_len,
1014 const unsigned char *property,
1015 size_t property_len)
1016 {
1017 WsBcPragma *p = add_pragma(bc, WS_BC_PRAGMA_TYPE_USER_AGENT_PROPERTY);
1018
1019 if (p == NULL)
1020 return WS_FALSE;
1021
1022 if (!ws_bc_add_const_utf8_string(bc, &p->index_1, name, name_len)
1023 || !ws_bc_add_const_utf8_string(bc, &p->index_2, property, property_len))
1024 return WS_FALSE;
1025
1026 return WS_TRUE;
1027 }
1028
1029
ws_bc_add_pragma_user_agent_property_and_scheme(WsBc * bc,const unsigned char * name,size_t name_len,const unsigned char * property,size_t property_len,const unsigned char * scheme,size_t scheme_len)1030 WsBool ws_bc_add_pragma_user_agent_property_and_scheme(
1031 WsBc *bc,
1032 const unsigned char *name,
1033 size_t name_len,
1034 const unsigned char *property,
1035 size_t property_len,
1036 const unsigned char *scheme,
1037 size_t scheme_len)
1038 {
1039 WsBcPragma *p;
1040
1041 p = add_pragma(bc, WS_BC_PRAGMA_TYPE_USER_AGENT_PROPERTY_AND_SCHEME);
1042
1043 if (p == NULL)
1044 return WS_FALSE;
1045
1046 if (!ws_bc_add_const_utf8_string(bc, &p->index_1, name, name_len)
1047 || !ws_bc_add_const_utf8_string(bc, &p->index_2, property, property_len)
1048 || !ws_bc_add_const_utf8_string(bc, &p->index_3, scheme, scheme_len))
1049 return WS_FALSE;
1050
1051 return WS_TRUE;
1052 }
1053
1054 /********************* Adding functions *********************************/
1055
ws_bc_add_function(WsBc * bc,WsUInt8 * index_return,char * name,WsUInt8 num_arguments,WsUInt8 num_locals,WsUInt32 code_size,unsigned char * code)1056 WsBool ws_bc_add_function(WsBc *bc, WsUInt8 *index_return, char *name,
1057 WsUInt8 num_arguments, WsUInt8 num_locals,
1058 WsUInt32 code_size, unsigned char *code)
1059 {
1060 WsBcFunction *nf;
1061
1062 /* First, add the function to the function pool. */
1063
1064 nf = ws_realloc(bc->functions,
1065 (bc->num_functions + 1) * sizeof(WsBcFunction));
1066 if (nf == NULL)
1067 return WS_FALSE;
1068
1069 bc->functions = nf;
1070 bc->functions[bc->num_functions].num_arguments = num_arguments;
1071 bc->functions[bc->num_functions].num_locals = num_locals;
1072 bc->functions[bc->num_functions].code_size = code_size;
1073 bc->functions[bc->num_functions].code = ws_memdup(code, code_size);
1074
1075 if (bc->functions[bc->num_functions].code == NULL)
1076 return WS_FALSE;
1077
1078 /* Save the index of the function. */
1079 *index_return = bc->num_functions++;
1080
1081 /* For external functions (which have name), add a name entry to the
1082 function name pool. */
1083 if (name) {
1084 WsBcFunctionName *nfn;
1085
1086 nfn = ws_realloc(bc->function_names,
1087 ((bc->num_function_names + 1)
1088 * sizeof(WsBcFunctionName)));
1089 if (nfn == NULL)
1090 return WS_FALSE;
1091
1092 bc->function_names = nfn;
1093 bc->function_names[bc->num_function_names].index = *index_return;
1094 bc->function_names[bc->num_function_names].name = ws_strdup(name);
1095
1096 if (bc->function_names[bc->num_function_names].name == NULL)
1097 return WS_FALSE;
1098
1099 bc->num_function_names++;
1100 }
1101
1102 /* All done. */
1103 return WS_TRUE;
1104 }
1105
1106 /********************* Static functions *********************************/
1107
add_pragma(WsBc * bc,WsBcPragmaType type)1108 static WsBcPragma *add_pragma(WsBc *bc, WsBcPragmaType type)
1109 {
1110 WsBcPragma *np;
1111
1112 /* Add a new pragma slot. */
1113 np = ws_realloc(bc->pragmas, (bc->num_pragmas + 1) * sizeof(WsBcPragma));
1114 if (np == NULL)
1115 return NULL;
1116
1117 bc->pragmas = np;
1118 bc->pragmas[bc->num_pragmas].type = type;
1119
1120 return &bc->pragmas[bc->num_pragmas++];
1121 }
1122