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