void check_value(double num) { float native = num; unsigned char buf[4]; struct ieee_single *s = (struct ieee_single *) & native; unsigned int *uip = (unsigned int *) s; unsigned int n = ntohl(*uip); double d; ws_ieee754_encode_single(num, buf); if (memcmp(buf, &n, 4) != 0) { printf("\n"); printf("%f failed:\n", num); printf("ws: "); ws_ieee754_print(buf); printf("native: "); ws_ieee754_print((unsigned char *) &n); abort(); } if (ws_ieee754_decode_single(buf, &d) != WS_IEEE754_OK || d != native) { printf("\ndecode of %f failed: got %f\n", num, d); abort(); } }
int main(int argc, char *argv[]) { unsigned char buf[4]; unsigned int rounds = 0; if (argc > 1) { int i; for (i = 1; i < argc; i++) check_value(strtod(argv[1], NULL)); return 0; } ws_ieee754_encode_single(5.75, buf); ws_ieee754_print(buf); check_value(5.75); ws_ieee754_encode_single(340282346638528859811704183484516925440.0, buf); ws_ieee754_print(buf); check_value(340282346638528859811704183484516925440.0); ws_ieee754_encode_single( -340282346638528859811704183484516925440.0, buf); ws_ieee754_print(buf); check_value( -340282346638528859811704183484516925440.0); ws_ieee754_encode_single(3.0 * pow(2, -129), buf); ws_ieee754_print(buf); check_value(3.0 * pow(2, -129)); ws_ieee754_encode_single(pow(2, -149), buf); ws_ieee754_print(buf); check_value(pow(2, -149)); ws_ieee754_encode_single(pow(2, -149) * .1, buf); ws_ieee754_print(buf); check_value(pow(2, -149) * .1); ws_ieee754_encode_single( -pow(2, -149), buf); ws_ieee754_print(buf); check_value( -pow(2, -149)); ws_ieee754_encode_single( -pow(2, -149) * .1, buf); ws_ieee754_print(buf); while (1) { double a = random(); double b = random(); if (b == 0.0) continue; check_value(a / b); check_value(a * b); if ((++rounds % 100000) == 0) { printf("%d ", rounds); fflush(stdout); } } return 0; }
WsBool ws_bc_encode(WsBc *bc, unsigned char **data_return, size_t *data_len_return) { WsBuffer buffer; WsUInt32 ui; unsigned char data[64]; unsigned char *p, *mb; size_t len; ws_buffer_init(&buffer); /* Append space for the header. We do not know yet the size of the resulting byte-code. */ if (!ws_buffer_append_space(&buffer, NULL, WS_BC_MAX_HEADER_LEN)) goto error; /* Constants. */ if (!ws_encode_buffer(&buffer, WS_ENC_MB_UINT16, bc->num_constants, WS_ENC_MB_UINT16, (WsUInt16) bc->string_encoding, WS_ENC_END)) goto error; for (ui = 0 ; ui < bc->num_constants; ui++) { switch (bc->constants[ui].type) { case WS_BC_CONST_TYPE_INT: if (WS_INT8_MIN <= bc->constants[ui].u.v_int && bc->constants[ui].u.v_int <= WS_INT8_MAX) { if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_INT8, WS_ENC_INT8, (WsInt8) bc->constants[ui].u.v_int, WS_ENC_END)) goto error; } else if (WS_INT16_MIN <= bc->constants[ui].u.v_int && bc->constants[ui].u.v_int <= WS_INT16_MAX) { if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_INT16, WS_ENC_INT16, (WsInt16) bc->constants[ui].u.v_int, WS_ENC_END)) goto error; } else { if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_INT32, WS_ENC_INT32, bc->constants[ui].u.v_int, WS_ENC_END)) goto error; } break; case WS_BC_CONST_TYPE_FLOAT32: case WS_BC_CONST_TYPE_FLOAT32_NAN: case WS_BC_CONST_TYPE_FLOAT32_POSITIVE_INF: case WS_BC_CONST_TYPE_FLOAT32_NEGATIVE_INF: switch (bc->constants[ui].type) { case WS_BC_CONST_TYPE_FLOAT32: ws_ieee754_encode_single(bc->constants[ui].u.v_float, data); p = data; break; case WS_BC_CONST_TYPE_FLOAT32_NAN: p = ws_ieee754_nan; break; case WS_BC_CONST_TYPE_FLOAT32_POSITIVE_INF: p = ws_ieee754_positive_inf; break; case WS_BC_CONST_TYPE_FLOAT32_NEGATIVE_INF: p = ws_ieee754_negative_inf; break; default: ws_fatal("ws_bc_encode(): internal inconsistency"); /* NOTREACHED */ p = NULL; /* Initialized to keep compiler quiet. */ break; } if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_FLOAT32, WS_ENC_DATA, p, 4, WS_ENC_END)) goto error; break; break; case WS_BC_CONST_TYPE_UTF8_STRING: /* Encode the strings as requested. */ switch (bc->string_encoding) { case WS_BC_STRING_ENC_ISO_8859_1: { WsUtf8String *string = ws_utf8_alloc(); unsigned char *latin1; size_t latin1_len; WsBool success; if (string == NULL) goto error; /* Create an UTF-8 string. */ if (!ws_utf8_set_data(string, bc->constants[ui].u.v_string.data, bc->constants[ui].u.v_string.len)) { ws_utf8_free(string); goto error; } /* Convert it to latin1. */ latin1 = ws_utf8_to_latin1(string, '?', &latin1_len); /* We'r done with the UTF-8 string. */ ws_utf8_free(string); if (latin1 == NULL) goto error; /* Encode it. */ success = ws_encode_buffer( &buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_EXT_ENC_STRING, WS_ENC_MB_UINT32, (WsUInt32) latin1_len, WS_ENC_DATA, latin1, latin1_len, WS_ENC_END); ws_utf8_free_data(latin1); if (!success) goto error; } break; case WS_BC_STRING_ENC_UTF8: if (!ws_encode_buffer( &buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_UTF8_STRING, WS_ENC_MB_UINT32, (WsUInt32) bc->constants[ui].u.v_string.len, WS_ENC_DATA, bc->constants[ui].u.v_string.data, bc->constants[ui].u.v_string.len, WS_ENC_END)) goto error; break; } break; case WS_BC_CONST_TYPE_EMPTY_STRING: if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_EMPTY_STRING, WS_ENC_END)) goto error; break; } } /* Pragmas. */ if (!ws_encode_buffer(&buffer, WS_ENC_MB_UINT16, bc->num_pragmas, WS_ENC_END)) goto error; for (ui = 0; ui < bc->num_pragmas; ui++) { switch (bc->pragmas[ui].type) { case WS_BC_PRAGMA_TYPE_ACCESS_DOMAIN: if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_PRAGMA_ACCESS_DOMAIN, WS_ENC_MB_UINT16, bc->pragmas[ui].index_1, WS_ENC_END)) goto error; break; case WS_BC_PRAGMA_TYPE_ACCESS_PATH: if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_PRAGMA_ACCESS_PATH, WS_ENC_MB_UINT16, bc->pragmas[ui].index_1, WS_ENC_END)) goto error; break; case WS_BC_PRAGMA_TYPE_USER_AGENT_PROPERTY: if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_PRAGMA_USER_AGENT_PROPERTY, WS_ENC_MB_UINT16, bc->pragmas[ui].index_1, WS_ENC_MB_UINT16, bc->pragmas[ui].index_2, WS_ENC_END)) goto error; break; case WS_BC_PRAGMA_TYPE_USER_AGENT_PROPERTY_AND_SCHEME: if (!ws_encode_buffer( &buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_PRAGMA_USER_AGENT_PROPERTY_AND_SCHEME, WS_ENC_MB_UINT16, bc->pragmas[ui].index_1, WS_ENC_MB_UINT16, bc->pragmas[ui].index_2, WS_ENC_MB_UINT16, bc->pragmas[ui].index_3, WS_ENC_END)) goto error; break; } } /* Function pool. */ if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, bc->num_functions, WS_ENC_END)) goto error; /* Function names. */ if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, bc->num_function_names, WS_ENC_END)) goto error; for (ui = 0; ui < bc->num_function_names; ui++) { size_t name_len = strlen(bc->function_names[ui].name); if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, bc->function_names[ui].index, WS_ENC_UINT8, (WsUInt8) name_len, WS_ENC_DATA, bc->function_names[ui].name, name_len, WS_ENC_END)) goto error; } /* Functions. */ for (ui = 0; ui < bc->num_functions; ui++) { if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, bc->functions[ui].num_arguments, WS_ENC_UINT8, bc->functions[ui].num_locals, WS_ENC_MB_UINT32, bc->functions[ui].code_size, WS_ENC_DATA, bc->functions[ui].code, (size_t) bc->functions[ui].code_size, WS_ENC_END)) goto error; } /* Fix the byte-code header. */ p = ws_buffer_ptr(&buffer); /* Encode the size of the byte-code excluding the byte-code header. */ mb = ws_encode_mb_uint32(ws_buffer_len(&buffer) - WS_BC_MAX_HEADER_LEN, data, &len); memcpy(p + WS_BC_MAX_HEADER_LEN - len, mb, len); /* Set the byte-code file version information. */ WS_PUT_UINT8(p + WS_BC_MAX_HEADER_LEN - len - 1, WS_BC_VERSION); /* Calculate the beginning of the bc-array and its size. */ *data_return = p + WS_BC_MAX_HEADER_LEN - len - 1; *data_len_return = ws_buffer_len(&buffer) - WS_BC_MAX_HEADER_LEN + len + 1; /* All done. */ return WS_TRUE; /* * Error handling. */ error: ws_buffer_uninit(&buffer); *data_return = NULL; *data_len_return = 0; return WS_FALSE; }
static WsBool read_float_from_exp(WsCompiler *compiler, WsBuffer *buffer, WsFloat *result) { WsUInt32 ch; unsigned char *p; int sign = '+'; unsigned char buf[4]; /* Do we have an exponent part. */ if (!ws_stream_getc(compiler->input, &ch)) goto done; if (ch != 'e' && ch != 'E') { /* No exponent part. */ ws_stream_ungetc(compiler->input, ch); goto done; } /* Sign. */ if (!ws_stream_getc(compiler->input, &ch)) { /* This is an error. */ ws_src_error(compiler, 0, "truncated float literal"); return WS_FALSE; } if (ch == '-') sign = '-'; else if (ch == '+') sign = '+'; else ws_stream_ungetc(compiler->input, ch); /* DecimalDigits. */ if (!ws_stream_getc(compiler->input, &ch)) { ws_src_error(compiler, 0, "truncated float literal"); return WS_FALSE; } if (!WS_IS_DECIMAL_DIGIT(ch)) { ws_src_error(compiler, 0, "no decimal digits in exponent part"); return WS_FALSE; } /* Append exponent part read so far. */ if (!ws_buffer_append_space(buffer, &p, 2)) { ws_error_memory(compiler); return WS_FALSE; } p[0] = 'e'; p[1] = sign; /* Read decimal digits. */ while (WS_IS_DECIMAL_DIGIT(ch)) { if (!ws_buffer_append_space(buffer, &p, 1)) { ws_error_memory(compiler); return WS_FALSE; } p[0] = (unsigned char) ch; if (!ws_stream_getc(compiler->input, &ch)) /* EOF. This is ok. */ goto done; } /* Unget the extra character. */ ws_stream_ungetc(compiler->input, ch); /* FALLTHROUGH */ done: if (!ws_buffer_append_space(buffer, &p, 1)) { ws_error_memory(compiler); return WS_FALSE; } p[0] = 0; /* Now the buffer contains a valid floating point number. */ *result = (WsFloat) strtod((char *) ws_buffer_ptr(buffer), NULL); /* Check that the generated floating point number fits to `float32'. */ if (*result == HUGE_VAL || *result == -HUGE_VAL || ws_ieee754_encode_single(*result, buf) != WS_IEEE754_OK) ws_src_error(compiler, 0, "floating point literal too large"); return WS_TRUE; }