wsbc.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:31k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  *
  3.  * wsbc.c
  4.  *
  5.  * Author: Markku Rossi <mtr@iki.fi>
  6.  *
  7.  * Copyright (c) 1999-2000 WAPIT OY LTD.
  8.  *  All rights reserved.
  9.  *
  10.  * Byte-code handling functions.
  11.  *
  12.  */
  13. #include "wsint.h"
  14. #include "wsbc.h"
  15. /********************* Prototypes for static functions ******************/
  16. /* Add a new pragma of type `type' to the byte-code `bc'.  The
  17.  * function returns a pointer to an internal pragma structure that
  18.  * must not be freed by the caller.  It is freed when the byte-code
  19.  * `bc' is freed.  The function returns NULL if the pragma structure
  20.  * could not be allocated. */
  21. static WsBcPragma *add_pragma(WsBc *bc, WsBcPragmaType type);
  22. /********************* Manipulating byte-code structure *****************/
  23. WsBc *ws_bc_alloc(WsBcStringEncoding string_encoding)
  24. {
  25.     WsBc *bc = ws_calloc(1, sizeof(WsBc));
  26.     if (bc == NULL)
  27.         return NULL;
  28.     bc->string_encoding = string_encoding;
  29.     return bc;
  30. }
  31. void ws_bc_free(WsBc *bc)
  32. {
  33.     WsUInt16 i;
  34.     WsUInt8 j;
  35.     if (bc == NULL)
  36.         return;
  37.     /* Free constants. */
  38.     for (i = 0; i < bc->num_constants; i++) {
  39.         WsBcConstant *c = &bc->constants[i];
  40.         if (c->type == WS_BC_CONST_TYPE_UTF8_STRING)
  41.             ws_free(c->u.v_string.data);
  42.     }
  43.     ws_free(bc->constants);
  44.     /* Free pragmas. */
  45.     ws_free(bc->pragmas);
  46.     /* Free function names. */
  47.     for (j = 0; j < bc->num_function_names; j++)
  48.         ws_free(bc->function_names[j].name);
  49.     ws_free(bc->function_names);
  50.     /* Free functions. */
  51.     for (j = 0; j < bc->num_functions; j++)
  52.         ws_free(bc->functions[j].code);
  53.     ws_free(bc->functions);
  54.     /* Free the byte-code structure. */
  55.     ws_free(bc);
  56. }
  57. WsBool ws_bc_encode(WsBc *bc, unsigned char **data_return,
  58.                     size_t *data_len_return)
  59. {
  60.     WsBuffer buffer;
  61.     WsUInt32 ui;
  62.     unsigned char data[64];
  63.     unsigned char *p, *mb;
  64.     size_t len;
  65.     ws_buffer_init(&buffer);
  66.     /* Append space for the header.  We do not know yet the size of the
  67.        resulting byte-code. */
  68.     if (!ws_buffer_append_space(&buffer, NULL, WS_BC_MAX_HEADER_LEN))
  69.         goto error;
  70.     /* Constants. */
  71.     if (!ws_encode_buffer(&buffer,
  72.                           WS_ENC_MB_UINT16, bc->num_constants,
  73.                           WS_ENC_MB_UINT16, (WsUInt16) bc->string_encoding,
  74.                           WS_ENC_END))
  75.         goto error;
  76.     for (ui = 0 ; ui < bc->num_constants; ui++) {
  77.         switch (bc->constants[ui].type) {
  78.         case WS_BC_CONST_TYPE_INT:
  79.             if (WS_INT8_MIN <= bc->constants[ui].u.v_int
  80.                 && bc->constants[ui].u.v_int <= WS_INT8_MAX) {
  81.                 if (!ws_encode_buffer(&buffer,
  82.                                       WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_INT8,
  83.                                       WS_ENC_INT8,
  84.                                       (WsInt8) bc->constants[ui].u.v_int,
  85.                                       WS_ENC_END))
  86.                     goto error;
  87.             } else if (WS_INT16_MIN <= bc->constants[ui].u.v_int
  88.                        && bc->constants[ui].u.v_int <= WS_INT16_MAX) {
  89.                 if (!ws_encode_buffer(&buffer,
  90.                                       WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_INT16,
  91.                                       WS_ENC_INT16,
  92.                                       (WsInt16) bc->constants[ui].u.v_int,
  93.                                       WS_ENC_END))
  94.                     goto error;
  95.             } else {
  96.                 if (!ws_encode_buffer(&buffer,
  97.                                       WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_INT32,
  98.                                       WS_ENC_INT32, bc->constants[ui].u.v_int,
  99.                                       WS_ENC_END))
  100.                     goto error;
  101.             }
  102.             break;
  103.         case WS_BC_CONST_TYPE_FLOAT32:
  104.         case WS_BC_CONST_TYPE_FLOAT32_NAN:
  105.         case WS_BC_CONST_TYPE_FLOAT32_POSITIVE_INF:
  106.         case WS_BC_CONST_TYPE_FLOAT32_NEGATIVE_INF:
  107.             switch (bc->constants[ui].type) {
  108.             case WS_BC_CONST_TYPE_FLOAT32:
  109.                 ws_ieee754_encode_single(bc->constants[ui].u.v_float, data);
  110.                 p = data;
  111.                 break;
  112.             case WS_BC_CONST_TYPE_FLOAT32_NAN:
  113.                 p = ws_ieee754_nan;
  114.                 break;
  115.             case WS_BC_CONST_TYPE_FLOAT32_POSITIVE_INF:
  116.                 p = ws_ieee754_positive_inf;
  117.                 break;
  118.             case WS_BC_CONST_TYPE_FLOAT32_NEGATIVE_INF:
  119.                 p = ws_ieee754_negative_inf;
  120.                 break;
  121.             default:
  122.                 ws_fatal("ws_bc_encode(): internal inconsistency");
  123.                 /* NOTREACHED */
  124.                 p = NULL;  /* Initialized to keep compiler quiet. */
  125.                 break;
  126.             }
  127.             if (!ws_encode_buffer(&buffer,
  128.                                   WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_FLOAT32,
  129.                                   WS_ENC_DATA, p, 4,
  130.                                   WS_ENC_END))
  131.                 goto error;
  132.             break;
  133.             break;
  134.         case WS_BC_CONST_TYPE_UTF8_STRING:
  135.             /* Encode the strings as requested. */
  136.             switch (bc->string_encoding) {
  137.             case WS_BC_STRING_ENC_ISO_8859_1:
  138.                 {
  139.                     WsUtf8String *string = ws_utf8_alloc();
  140.                     unsigned char *latin1;
  141.                     size_t latin1_len;
  142.                     WsBool success;
  143.                     if (string == NULL)
  144.                         goto error;
  145.                     /* Create an UTF-8 string. */
  146.                     if (!ws_utf8_set_data(string,
  147.                                           bc->constants[ui].u.v_string.data,
  148.                                           bc->constants[ui].u.v_string.len)) {
  149.                         ws_utf8_free(string);
  150.                         goto error;
  151.                     }
  152.                     /* Convert it to latin1. */
  153.                     latin1 = ws_utf8_to_latin1(string, '?', &latin1_len);
  154.                     /* We'r done with the UTF-8 string. */
  155.                     ws_utf8_free(string);
  156.                     if (latin1 == NULL)
  157.                         goto error;
  158.                     /* Encode it. */
  159.                     success = ws_encode_buffer(
  160.                                   &buffer,
  161.                                   WS_ENC_UINT8,
  162.                                   (WsUInt8) WS_BC_CONST_EXT_ENC_STRING,
  163.                                   WS_ENC_MB_UINT32, (WsUInt32) latin1_len,
  164.                                   WS_ENC_DATA, latin1, latin1_len,
  165.                                   WS_ENC_END);
  166.                     ws_utf8_free_data(latin1);
  167.                     if (!success)
  168.                         goto error;
  169.                 }
  170.                 break;
  171.             case WS_BC_STRING_ENC_UTF8:
  172.                 if (!ws_encode_buffer(
  173.                         &buffer,
  174.                         WS_ENC_UINT8,
  175.                         (WsUInt8) WS_BC_CONST_UTF8_STRING,
  176.                         WS_ENC_MB_UINT32,
  177.                         (WsUInt32) bc->constants[ui].u.v_string.len,
  178.                         WS_ENC_DATA,
  179.                         bc->constants[ui].u.v_string.data,
  180.                         bc->constants[ui].u.v_string.len,
  181.                         WS_ENC_END))
  182.                     goto error;
  183.                 break;
  184.             }
  185.             break;
  186.         case WS_BC_CONST_TYPE_EMPTY_STRING:
  187.             if (!ws_encode_buffer(&buffer,
  188.                                   WS_ENC_UINT8,
  189.                                   (WsUInt8) WS_BC_CONST_EMPTY_STRING,
  190.                                   WS_ENC_END))
  191.                 goto error;
  192.             break;
  193.         }
  194.     }
  195.     /* Pragmas. */
  196.     if (!ws_encode_buffer(&buffer,
  197.                           WS_ENC_MB_UINT16, bc->num_pragmas,
  198.                           WS_ENC_END))
  199.         goto error;
  200.     for (ui = 0; ui < bc->num_pragmas; ui++) {
  201.         switch (bc->pragmas[ui].type) {
  202.         case WS_BC_PRAGMA_TYPE_ACCESS_DOMAIN:
  203.             if (!ws_encode_buffer(&buffer,
  204.                                   WS_ENC_UINT8,
  205.                                   (WsUInt8) WS_BC_PRAGMA_ACCESS_DOMAIN,
  206.                                   WS_ENC_MB_UINT16, bc->pragmas[ui].index_1,
  207.                                   WS_ENC_END))
  208.                 goto error;
  209.             break;
  210.         case WS_BC_PRAGMA_TYPE_ACCESS_PATH:
  211.             if (!ws_encode_buffer(&buffer,
  212.                                   WS_ENC_UINT8,
  213.                                   (WsUInt8) WS_BC_PRAGMA_ACCESS_PATH,
  214.                                   WS_ENC_MB_UINT16, bc->pragmas[ui].index_1,
  215.                                   WS_ENC_END))
  216.                 goto error;
  217.             break;
  218.         case WS_BC_PRAGMA_TYPE_USER_AGENT_PROPERTY:
  219.             if (!ws_encode_buffer(&buffer,
  220.                                   WS_ENC_UINT8,
  221.                                   (WsUInt8) WS_BC_PRAGMA_USER_AGENT_PROPERTY,
  222.                                   WS_ENC_MB_UINT16, bc->pragmas[ui].index_1,
  223.                                   WS_ENC_MB_UINT16, bc->pragmas[ui].index_2,
  224.                                   WS_ENC_END))
  225.                 goto error;
  226.             break;
  227.         case WS_BC_PRAGMA_TYPE_USER_AGENT_PROPERTY_AND_SCHEME:
  228.             if (!ws_encode_buffer(
  229.                     &buffer,
  230.                     WS_ENC_UINT8,
  231.                     (WsUInt8) WS_BC_PRAGMA_USER_AGENT_PROPERTY_AND_SCHEME,
  232.                     WS_ENC_MB_UINT16, bc->pragmas[ui].index_1,
  233.                     WS_ENC_MB_UINT16, bc->pragmas[ui].index_2,
  234.                     WS_ENC_MB_UINT16, bc->pragmas[ui].index_3,
  235.                     WS_ENC_END))
  236.                 goto error;
  237.             break;
  238.         }
  239.     }
  240.     /* Function pool. */
  241.     if (!ws_encode_buffer(&buffer,
  242.                           WS_ENC_UINT8, bc->num_functions,
  243.                           WS_ENC_END))
  244.         goto error;
  245.     /* Function names. */
  246.     if (!ws_encode_buffer(&buffer,
  247.                           WS_ENC_UINT8, bc->num_function_names,
  248.                           WS_ENC_END))
  249.         goto error;
  250.     for (ui = 0; ui < bc->num_function_names; ui++) {
  251.         size_t name_len = strlen(bc->function_names[ui].name);
  252.         if (!ws_encode_buffer(&buffer,
  253.                               WS_ENC_UINT8, bc->function_names[ui].index,
  254.                               WS_ENC_UINT8, (WsUInt8) name_len,
  255.                               WS_ENC_DATA, bc->function_names[ui].name, name_len,
  256.                               WS_ENC_END))
  257.             goto error;
  258.     }
  259.     /* Functions. */
  260.     for (ui = 0; ui < bc->num_functions; ui++) {
  261.         if (!ws_encode_buffer(&buffer,
  262.                               WS_ENC_UINT8, bc->functions[ui].num_arguments,
  263.                               WS_ENC_UINT8, bc->functions[ui].num_locals,
  264.                               WS_ENC_MB_UINT32, bc->functions[ui].code_size,
  265.                               WS_ENC_DATA, bc->functions[ui].code,
  266.                               (size_t) bc->functions[ui].code_size,
  267.                               WS_ENC_END))
  268.             goto error;
  269.     }
  270.     /* Fix the byte-code header. */
  271.     p = ws_buffer_ptr(&buffer);
  272.     /* Encode the size of the byte-code excluding the byte-code header. */
  273.     mb = ws_encode_mb_uint32(ws_buffer_len(&buffer) - WS_BC_MAX_HEADER_LEN,
  274.                              data, &len);
  275.     memcpy(p + WS_BC_MAX_HEADER_LEN - len, mb, len);
  276.     /* Set the byte-code file version information. */
  277.     WS_PUT_UINT8(p + WS_BC_MAX_HEADER_LEN - len - 1, WS_BC_VERSION);
  278.     /* Calculate the beginning of the bc-array and its size. */
  279.     *data_return = p + WS_BC_MAX_HEADER_LEN - len - 1;
  280.     *data_len_return = ws_buffer_len(&buffer) - WS_BC_MAX_HEADER_LEN + len + 1;
  281.     /* All done. */
  282.     return WS_TRUE;
  283.     /*
  284.      * Error handling.
  285.      */
  286. error:
  287.     ws_buffer_uninit(&buffer);
  288.     *data_return = NULL;
  289.     *data_len_return = 0;
  290.     return WS_FALSE;
  291. }
  292. void ws_bc_data_free(unsigned char *data)
  293. {
  294.     size_t len = WS_MB_UINT32_MAX_ENCODED_LEN;
  295.     if (data == NULL)
  296.         return;
  297.     /* Decode the mb-encoded length so we know how much space it uses. */
  298.     (void) ws_decode_mb_uint32(data + 1, &len);
  299.     /* Now we can compute the beginning of the array `data'. */
  300.     ws_free(data - (WS_MB_UINT32_MAX_ENCODED_LEN - len));
  301. }
  302. /* A helper macro to update the data pointers during the decoding of
  303.    byte-code data. */
  304. #define WS_UPDATE_DATA
  305.     data += decoded;
  306.     data_len -= decoded
  307. /* A helper macro to check the validity of the constant string index
  308.    `idx'. */
  309. #define WS_CHECK_STRING(idx)
  310.     if ((idx) >= bc->num_constants
  311.         || ((bc->constants[(idx)].type
  312.              != WS_BC_CONST_TYPE_UTF8_STRING)
  313.             && (bc->constants[(idx)].type
  314.                 != WS_BC_CONST_TYPE_EMPTY_STRING)))
  315.         goto error;
  316. WsBc *ws_bc_decode(const unsigned char *data, size_t data_len)
  317. {
  318.     WsBc *bc = ws_bc_alloc(WS_BC_STRING_ENC_ISO_8859_1);
  319.     WsByte b;
  320.     WsUInt32 ui32;
  321.     WsUInt16 ui16, j;
  322.     WsUInt16 ui16b;
  323.     WsUInt8 ui8, num_functions, k, l;
  324.     WsInt8 i8;
  325.     WsInt16 i16;
  326.     WsInt32 i32;
  327.     WsIeee754Result ieee754;
  328.     unsigned char *ucp;
  329.     size_t decoded;
  330.     /* Decode the byte-code header. */
  331.     decoded = ws_decode_buffer(data, data_len,
  332.                                WS_ENC_BYTE, &b,
  333.                                WS_ENC_MB_UINT32, &ui32,
  334.                                WS_ENC_END);
  335.     if (!decoded
  336.         || b != WS_BC_VERSION
  337.         || ui32 != data_len - decoded)
  338.         /* This is not a valid (or supported) byte-code header. */
  339.         goto error;
  340.     WS_UPDATE_DATA;
  341.     /* Constant pool. */
  342.     decoded = ws_decode_buffer(data, data_len,
  343.                                WS_ENC_MB_UINT16, &ui16,
  344.                                WS_ENC_MB_UINT16, &ui16b,
  345.                                WS_ENC_END);
  346.     if (!decoded)
  347.         goto error;
  348.     bc->string_encoding = ui16b;
  349.     bc->constants = ws_calloc(ui16, sizeof(WsBcConstant));
  350.     if (bc->constants == NULL)
  351.         goto error;
  352.     bc->num_constants = ui16;
  353.     WS_UPDATE_DATA;
  354.     for (j = 0; j < bc->num_constants; j++) {
  355.         WsBcConstant *c = &bc->constants[j];
  356.         decoded = ws_decode_buffer(data, data_len,
  357.                                    WS_ENC_UINT8, &ui8,
  358.                                    WS_ENC_END);
  359.         if (decoded != 1)
  360.             goto error;
  361.         WS_UPDATE_DATA;
  362.         switch (ui8) {
  363.         case WS_BC_CONST_INT8:
  364.             decoded = ws_decode_buffer(data, data_len,
  365.                                        WS_ENC_INT8, &i8,
  366.                                        WS_ENC_END);
  367.             if (decoded != 1)
  368.                 goto error;
  369.             WS_UPDATE_DATA;
  370.             c->type = WS_BC_CONST_TYPE_INT;
  371.             c->u.v_int = i8;
  372.             break;
  373.         case WS_BC_CONST_INT16:
  374.             decoded = ws_decode_buffer(data, data_len,
  375.                                        WS_ENC_INT16, &i16,
  376.                                        WS_ENC_END);
  377.             if (decoded != 2)
  378.                 goto error;
  379.             WS_UPDATE_DATA;
  380.             c->type = WS_BC_CONST_TYPE_INT;
  381.             c->u.v_int = i16;
  382.             break;
  383.         case WS_BC_CONST_INT32:
  384.             decoded = ws_decode_buffer(data, data_len,
  385.                                        WS_ENC_INT32, &i32,
  386.                                        WS_ENC_END);
  387.             if (decoded != 4)
  388.                 goto error;
  389.             WS_UPDATE_DATA;
  390.             c->type = WS_BC_CONST_TYPE_INT;
  391.             c->u.v_int = i32;
  392.             break;
  393.         case WS_BC_CONST_FLOAT32:
  394.             decoded = ws_decode_buffer(data, data_len,
  395.                                        WS_ENC_DATA, &ucp, (size_t) 4,
  396.                                        WS_ENC_END);
  397.             if (decoded != 4)
  398.                 goto error;
  399.             WS_UPDATE_DATA;
  400.             ieee754 = ws_ieee754_decode_single(ucp, &c->u.v_float);
  401.             switch (ieee754) {
  402.             case WS_IEEE754_OK:
  403.                 c->type = WS_BC_CONST_TYPE_FLOAT32;
  404.                 break;
  405.             case WS_IEEE754_NAN:
  406.                 c->type = WS_BC_CONST_TYPE_FLOAT32_NAN;
  407.                 break;
  408.             case WS_IEEE754_POSITIVE_INF:
  409.                 c->type = WS_BC_CONST_TYPE_FLOAT32_POSITIVE_INF;
  410.                 break;
  411.             case WS_IEEE754_NEGATIVE_INF:
  412.                 c->type = WS_BC_CONST_TYPE_FLOAT32_NEGATIVE_INF;
  413.                 break;
  414.             }
  415.             break;
  416.         case WS_BC_CONST_UTF8_STRING:
  417.             decoded = ws_decode_buffer(data, data_len,
  418.                                        WS_ENC_MB_UINT32, &ui32,
  419.                                        WS_ENC_END);
  420.             if (decoded == 0)
  421.                 goto error;
  422.             WS_UPDATE_DATA;
  423.             c->type = WS_BC_CONST_TYPE_UTF8_STRING;
  424.             c->u.v_string.len = ui32;
  425.             decoded = ws_decode_buffer(data, data_len,
  426.                                        WS_ENC_DATA, &ucp, c->u.v_string.len,
  427.                                        WS_ENC_END);
  428.             if (decoded != ui32)
  429.                 goto error;
  430.             WS_UPDATE_DATA;
  431.             c->u.v_string.data = ws_memdup(ucp, ui32);
  432.             if (c->u.v_string.data == NULL)
  433.                 goto error;
  434.             /* Check the validity of the data. */
  435.             if (!ws_utf8_verify(c->u.v_string.data, c->u.v_string.len,
  436.                                 &c->u.v_string.num_chars))
  437.                 goto error;
  438.             break;
  439.         case WS_BC_CONST_EMPTY_STRING:
  440.             c->type = WS_BC_CONST_TYPE_EMPTY_STRING;
  441.             break;
  442.         case WS_BC_CONST_EXT_ENC_STRING:
  443.             ws_fatal("external character encoding not implemented yet");
  444.             break;
  445.         default:
  446.             /* Reserved. */
  447.             goto error;
  448.             break;
  449.         }
  450.     }
  451.     /* Pragma pool. */
  452.     decoded = ws_decode_buffer(data, data_len,
  453.                                WS_ENC_MB_UINT16, &ui16,
  454.                                WS_ENC_END);
  455.     if (!decoded)
  456.         goto error;
  457.     bc->pragmas = ws_calloc(ui16, sizeof(WsBcPragma));
  458.     if (bc->pragmas == NULL)
  459.         goto error;
  460.     bc->num_pragmas = ui16;
  461.     WS_UPDATE_DATA;
  462.     for (j = 0; j < bc->num_pragmas; j++) {
  463.         WsBcPragma *p = &bc->pragmas[j];
  464.         decoded = ws_decode_buffer(data, data_len,
  465.                                    WS_ENC_UINT8, &ui8,
  466.                                    WS_ENC_END);
  467.         if (decoded != 1)
  468.             goto error;
  469.         WS_UPDATE_DATA;
  470.         p->type = ui8;
  471.         switch (ui8) {
  472.         case WS_BC_PRAGMA_ACCESS_DOMAIN:
  473.             decoded = ws_decode_buffer(data, data_len,
  474.                                        WS_ENC_MB_UINT16, &p->index_1,
  475.                                        WS_ENC_END);
  476.             if (!decoded)
  477.                 goto error;
  478.             WS_CHECK_STRING(p->index_1);
  479.             break;
  480.         case WS_BC_PRAGMA_ACCESS_PATH:
  481.             decoded = ws_decode_buffer(data, data_len,
  482.                                        WS_ENC_MB_UINT16, &p->index_1,
  483.                                        WS_ENC_END);
  484.             if (!decoded)
  485.                 goto error;
  486.             WS_CHECK_STRING(p->index_1);
  487.             break;
  488.         case WS_BC_PRAGMA_USER_AGENT_PROPERTY:
  489.             decoded = ws_decode_buffer(data, data_len,
  490.                                        WS_ENC_MB_UINT16, &p->index_1,
  491.                                        WS_ENC_MB_UINT16, &p->index_2,
  492.                                        WS_ENC_END);
  493.             if (!decoded)
  494.                 goto error;
  495.             WS_CHECK_STRING(p->index_1);
  496.             WS_CHECK_STRING(p->index_2);
  497.             break;
  498.         case WS_BC_PRAGMA_USER_AGENT_PROPERTY_AND_SCHEME:
  499.             decoded = ws_decode_buffer(data, data_len,
  500.                                        WS_ENC_MB_UINT16, &p->index_1,
  501.                                        WS_ENC_MB_UINT16, &p->index_2,
  502.                                        WS_ENC_MB_UINT16, &p->index_3,
  503.                                        WS_ENC_END);
  504.             if (!decoded)
  505.                 goto error;
  506.             WS_CHECK_STRING(p->index_1);
  507.             WS_CHECK_STRING(p->index_2);
  508.             WS_CHECK_STRING(p->index_3);
  509.             break;
  510.         default:
  511.             goto error;
  512.             break;
  513.         }
  514.         WS_UPDATE_DATA;
  515.     }
  516.     /* Function pool. */
  517.     decoded = ws_decode_buffer(data, data_len,
  518.                                WS_ENC_UINT8, &num_functions,
  519.                                WS_ENC_END);
  520.     if (decoded != 1)
  521.         goto error;
  522.     WS_UPDATE_DATA;
  523.     /* Function names. */
  524.     decoded = ws_decode_buffer(data, data_len,
  525.                                WS_ENC_UINT8, &ui8,
  526.                                WS_ENC_END);
  527.     if (decoded != 1)
  528.         goto error;
  529.     WS_UPDATE_DATA;
  530.     if (ui8) {
  531.         /* We have function names. */
  532.         bc->function_names = ws_calloc(ui8, sizeof(WsBcFunctionName));
  533.         if (bc->function_names == NULL)
  534.             goto error;
  535.         bc->num_function_names = ui8;
  536.         for (k = 0; k < bc->num_function_names; k++) {
  537.             WsBcFunctionName *n = &bc->function_names[k];
  538.             decoded = ws_decode_buffer(data, data_len,
  539.                                        WS_ENC_UINT8, &n->index,
  540.                                        WS_ENC_UINT8, &ui8,
  541.                                        WS_ENC_END);
  542.             if (decoded != 2)
  543.                 goto error;
  544.             WS_UPDATE_DATA;
  545.             decoded = ws_decode_buffer(data, data_len,
  546.                                        WS_ENC_DATA, &ucp, (size_t) ui8,
  547.                                        WS_ENC_END);
  548.             if (decoded != ui8)
  549.                 goto error;
  550.             WS_UPDATE_DATA;
  551.             n->name = ws_memdup(ucp, ui8);
  552.             if (n->name == NULL)
  553.                 goto error;
  554.             /* Check the validity of the name. */
  555.             if (!ws_utf8_verify((unsigned char *) n->name, ui8, NULL))
  556.                 goto error;
  557.             /* Just check that the data contains only valid characters. */
  558.             for (l = 0; l < ui8; l++) {
  559.                 unsigned int ch = (unsigned char) n->name[l];
  560.                 if (('a' <= ch && ch <= 'z')
  561.                     || ('A' <= ch && ch <= 'Z')
  562.                     || ch == '_'
  563.                     || (l > 0 && ('0' <= ch && ch <= '9')))
  564.                     /* Ok. */
  565.                     continue;
  566.                 /* Invalid character in the function name. */
  567.                 goto error;
  568.             }
  569.             /* Is the index valid? */
  570.             if (n->index >= num_functions)
  571.                 goto error;
  572.         }
  573.     }
  574.     /* Functions. */
  575.     if (num_functions) {
  576.         /* We have functions. */
  577.         bc->functions = ws_calloc(num_functions, sizeof(WsBcFunction));
  578.         if (bc->functions == NULL)
  579.             goto error;
  580.         bc->num_functions = num_functions;
  581.         for (k = 0; k < bc->num_functions; k++) {
  582.             WsBcFunction *f = &bc->functions[k];
  583.             decoded = ws_decode_buffer(data, data_len,
  584.                                        WS_ENC_UINT8, &f->num_arguments,
  585.                                        WS_ENC_UINT8, &f->num_locals,
  586.                                        WS_ENC_MB_UINT32, &f->code_size,
  587.                                        WS_ENC_END);
  588.             if (!decoded)
  589.                 goto error;
  590.             WS_UPDATE_DATA;
  591.             decoded = ws_decode_buffer(data, data_len,
  592.                                        WS_ENC_DATA, &ucp, f->code_size,
  593.                                        WS_ENC_END);
  594.             if (decoded != f->code_size)
  595.                 goto error;
  596.             WS_UPDATE_DATA;
  597.             if (f->code_size) {
  598.                 /* It is not an empty function. */
  599.                 f->code = ws_memdup(ucp, f->code_size);
  600.                 if (f->code == NULL)
  601.                     goto error;
  602.             }
  603.         }
  604.     }
  605.     /* Did we process it all? */
  606.     if (data_len != 0)
  607.         goto error;
  608.     /* All done. */
  609.     return bc;
  610.     /*
  611.      * Error handling.
  612.      */
  613. error:
  614.     ws_bc_free(bc);
  615.     return NULL;
  616. }
  617. /********************* Adding constant elements *************************/
  618. WsBool ws_bc_add_const_int(WsBc *bc, WsUInt16 *index_return, WsInt32 value)
  619. {
  620.     WsUInt16 i;
  621.     WsBcConstant *nc;
  622.     /* Do we already have a suitable integer constant? */
  623.     for (i = 0; i < bc->num_constants; i++) {
  624.         if (bc->constants[i].type == WS_BC_CONST_TYPE_INT
  625.             && bc->constants[i].u.v_int == value) {
  626.             *index_return = i;
  627.             return WS_TRUE;
  628.         }
  629.     }
  630.     /* Must add a new constant. */
  631.     nc = ws_realloc(bc->constants,
  632.                     (bc->num_constants + 1) * sizeof(WsBcConstant));
  633.     if (nc == NULL)
  634.         return WS_FALSE;
  635.     bc->constants = nc;
  636.     bc->constants[bc->num_constants].type = WS_BC_CONST_TYPE_INT;
  637.     bc->constants[bc->num_constants].u.v_int = value;
  638.     *index_return = bc->num_constants++;
  639.     return WS_TRUE;
  640. }
  641. WsBool ws_bc_add_const_float(WsBc *bc, WsUInt16 *index_return, WsFloat value)
  642. {
  643.     WsUInt16 i;
  644.     WsBcConstant *nc;
  645.     /* Do we already have a suitable float32 constant? */
  646.     for (i = 0; i < bc->num_constants; i++) {
  647.         if (bc->constants[i].type == WS_BC_CONST_TYPE_FLOAT32
  648.             && bc->constants[i].u.v_float == value) {
  649.             *index_return = i;
  650.             return WS_TRUE;
  651.         }
  652.     }
  653.     /* Must add a new constant. */
  654.     nc = ws_realloc(bc->constants,
  655.                     (bc->num_constants + 1) * sizeof(WsBcConstant));
  656.     if (nc == NULL)
  657.         return WS_FALSE;
  658.     bc->constants = nc;
  659.     bc->constants[bc->num_constants].type = WS_BC_CONST_TYPE_FLOAT32;
  660.     bc->constants[bc->num_constants].u.v_float = value;
  661.     *index_return = bc->num_constants++;
  662.     return WS_TRUE;
  663. }
  664. WsBool ws_bc_add_const_utf8_string(WsBc *bc, WsUInt16 *index_return,
  665.                                    const unsigned char *data, size_t len)
  666. {
  667.     WsUInt16 i;
  668.     WsBcConstant *nc;
  669.     /* Do we already have a suitable utf8 constant? */
  670.     for (i = 0; i < bc->num_constants; i++) {
  671.         if (bc->constants[i].type == WS_BC_CONST_TYPE_UTF8_STRING
  672.             && bc->constants[i].u.v_string.len == len
  673.             && memcmp(bc->constants[i].u.v_string.data,
  674.                       data, len) == 0) {
  675.             *index_return = i;
  676.             return WS_TRUE;
  677.         }
  678.     }
  679.     /* Must add a new constant. */
  680.     nc = ws_realloc(bc->constants,
  681.                     (bc->num_constants + 1) * sizeof(WsBcConstant));
  682.     if (nc == NULL)
  683.         return WS_FALSE;
  684.     bc->constants = nc;
  685.     bc->constants[bc->num_constants].type = WS_BC_CONST_TYPE_UTF8_STRING;
  686.     bc->constants[bc->num_constants].u.v_string.len = len;
  687.     bc->constants[bc->num_constants].u.v_string.data
  688.     = ws_memdup(data, len);
  689.     if (bc->constants[bc->num_constants].u.v_string.data == NULL)
  690.         return WS_FALSE;
  691.     *index_return = bc->num_constants++;
  692.     return WS_TRUE;
  693. }
  694. WsBool ws_bc_add_const_empty_string(WsBc *bc, WsUInt16 *index_return)
  695. {
  696.     WsUInt16 i;
  697.     WsBcConstant *nc;
  698.     /* Do we already have a suitable empty string constant? */
  699.     for (i = 0; i < bc->num_constants; i++) {
  700.         if (bc->constants[i].type == WS_BC_CONST_TYPE_EMPTY_STRING) {
  701.             *index_return = i;
  702.             return WS_TRUE;
  703.         }
  704.     }
  705.     /* Must add a new constant. */
  706.     nc = ws_realloc(bc->constants,
  707.                     (bc->num_constants + 1) * sizeof(WsBcConstant));
  708.     if (nc == NULL)
  709.         return WS_FALSE;
  710.     bc->constants = nc;
  711.     bc->constants[bc->num_constants].type = WS_BC_CONST_TYPE_EMPTY_STRING;
  712.     *index_return = bc->num_constants++;
  713.     return WS_TRUE;
  714. }
  715. /********************* Adding pragmas ***********************************/
  716. WsBool ws_bc_add_pragma_access_domain(WsBc *bc, const unsigned char *domain,
  717.                                       size_t domain_len)
  718. {
  719.     WsBcPragma *p = add_pragma(bc, WS_BC_PRAGMA_TYPE_ACCESS_DOMAIN);
  720.     if (p == NULL)
  721.         return WS_FALSE;
  722.     if (!ws_bc_add_const_utf8_string(bc, &p->index_1, domain, domain_len))
  723.         return WS_FALSE;
  724.     return WS_TRUE;
  725. }
  726. WsBool ws_bc_add_pragma_access_path(WsBc *bc, const unsigned char *path,
  727.                                     size_t path_len)
  728. {
  729.     WsBcPragma *p = add_pragma(bc, WS_BC_PRAGMA_TYPE_ACCESS_PATH);
  730.     if (p == NULL)
  731.         return WS_FALSE;
  732.     if (!ws_bc_add_const_utf8_string(bc, &p->index_1, path, path_len))
  733.         return WS_FALSE;
  734.     return WS_TRUE;
  735. }
  736. WsBool ws_bc_add_pragma_user_agent_property(WsBc *bc,
  737.                                             const unsigned char *name,
  738.                                             size_t name_len,
  739.                                             const unsigned char *property,
  740.                                             size_t property_len)
  741. {
  742.     WsBcPragma *p = add_pragma(bc, WS_BC_PRAGMA_TYPE_USER_AGENT_PROPERTY);
  743.     if (p == NULL)
  744.         return WS_FALSE;
  745.     if (!ws_bc_add_const_utf8_string(bc, &p->index_1, name, name_len)
  746.         || !ws_bc_add_const_utf8_string(bc, &p->index_2, property, property_len))
  747.         return WS_FALSE;
  748.     return WS_TRUE;
  749. }
  750. WsBool ws_bc_add_pragma_user_agent_property_and_scheme(
  751.     WsBc *bc,
  752.     const unsigned char *name,
  753.     size_t name_len,
  754.     const unsigned char *property,
  755.     size_t property_len,
  756.     const unsigned char *scheme,
  757.     size_t scheme_len)
  758. {
  759.     WsBcPragma *p;
  760.     p = add_pragma(bc, WS_BC_PRAGMA_TYPE_USER_AGENT_PROPERTY_AND_SCHEME);
  761.     if (p == NULL)
  762.         return WS_FALSE;
  763.     if (!ws_bc_add_const_utf8_string(bc, &p->index_1, name, name_len)
  764.         || !ws_bc_add_const_utf8_string(bc, &p->index_2, property, property_len)
  765.         || !ws_bc_add_const_utf8_string(bc, &p->index_3, scheme, scheme_len))
  766.         return WS_FALSE;
  767.     return WS_TRUE;
  768. }
  769. /********************* Adding functions *********************************/
  770. WsBool ws_bc_add_function(WsBc *bc, WsUInt8 *index_return, char *name,
  771.                           WsUInt8 num_arguments, WsUInt8 num_locals,
  772.                           WsUInt32 code_size, unsigned char *code)
  773. {
  774.     WsBcFunction *nf;
  775.     /* First, add the function to the function pool. */
  776.     nf = ws_realloc(bc->functions,
  777.                     (bc->num_functions + 1) * sizeof(WsBcFunction));
  778.     if (nf == NULL)
  779.         return WS_FALSE;
  780.     bc->functions = nf;
  781.     bc->functions[bc->num_functions].num_arguments = num_arguments;
  782.     bc->functions[bc->num_functions].num_locals = num_locals;
  783.     bc->functions[bc->num_functions].code_size = code_size;
  784.     bc->functions[bc->num_functions].code = ws_memdup(code, code_size);
  785.     if (bc->functions[bc->num_functions].code == NULL)
  786.         return WS_FALSE;
  787.     /* Save the index of the function. */
  788.     *index_return = bc->num_functions++;
  789.     /* For external functions (which have name), add a name entry to the
  790.        function name pool. */
  791.     if (name) {
  792.         WsBcFunctionName *nfn;
  793.         nfn = ws_realloc(bc->function_names,
  794.                          ((bc->num_function_names + 1)
  795.                           * sizeof(WsBcFunctionName)));
  796.         if (nfn == NULL)
  797.             return WS_FALSE;
  798.         bc->function_names = nfn;
  799.         bc->function_names[bc->num_function_names].index = *index_return;
  800.         bc->function_names[bc->num_function_names].name = ws_strdup(name);
  801.         if (bc->function_names[bc->num_function_names].name == NULL)
  802.             return WS_FALSE;
  803.         bc->num_function_names++;
  804.     }
  805.     /* All done. */
  806.     return WS_TRUE;
  807. }
  808. /********************* Static functions *********************************/
  809. static WsBcPragma *add_pragma(WsBc *bc, WsBcPragmaType type)
  810. {
  811.     WsBcPragma *np;
  812.     /* Add a new pragma slot. */
  813.     np = ws_realloc(bc->pragmas, (bc->num_pragmas + 1) * sizeof(WsBcPragma));
  814.     if (np == NULL)
  815.         return NULL;
  816.     bc->pragmas = np;
  817.     bc->pragmas[bc->num_pragmas].type = type;
  818.     return &bc->pragmas[bc->num_pragmas++];
  819. }