From 8abe227c63c30c5b8e5207fbaf44a4bcfed7dc84 Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Sat, 9 Mar 2013 01:08:12 +0200 Subject: [PATCH] initial implementation of global object escape() --- src/duk_builtin_global.c | 73 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/src/duk_builtin_global.c b/src/duk_builtin_global.c index c27dfbdd..08427d79 100644 --- a/src/duk_builtin_global.c +++ b/src/duk_builtin_global.c @@ -167,9 +167,78 @@ int duk_builtin_global_object_encode_uri_component(duk_context *ctx) { return DUK_RET_UNIMPLEMENTED_ERROR; /*FIXME*/ } -#if 1 /* FIXME: Section B */ +#ifdef DUK_USE_SECTION_B + +/* E5.1 Section B.2.2, step 7. */ +#define _MKBITS(a,b,c,d,e,f,g,h) ((unsigned char) ( \ + ((a) << 0) | ((b) << 1) | ((c) << 2) | ((d) << 3) | \ + ((e) << 4) | ((f) << 5) | ((g) << 6) | ((h) << 7) \ + )) +unsigned char duk_escape_as_is_table[16] = { + _MKBITS(0, 0, 0, 0, 0, 0, 0, 0), _MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */ + _MKBITS(0, 0, 0, 0, 0, 0, 0, 0), _MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */ + _MKBITS(0, 0, 0, 0, 0, 0, 0, 0), _MKBITS(0, 0, 1, 1, 0, 1, 1, 1), /* 0x20-0x2f */ + _MKBITS(1, 1, 1, 1, 1, 1, 1, 1), _MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */ + _MKBITS(1, 1, 1, 1, 1, 1, 1, 1), _MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */ + _MKBITS(1, 1, 1, 1, 1, 1, 1, 1), _MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */ + _MKBITS(0, 1, 1, 1, 1, 1, 1, 1), _MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */ + _MKBITS(1, 1, 1, 1, 1, 1, 1, 1), _MKBITS(1, 1, 1, 0, 0, 0, 0, 0) /* 0x70-0x7f */ +}; + +/* bit number in the byte is a bit counterintuitive, but minimizes ops */ +#define ESCAPE_AS_IS(cp) (duk_escape_as_is_table[(cp) >> 3] & (1 << ((cp) & 0x07))) + +/* FIXME: could this be implemented as a generic "transform" utility with + * a changing callback? What other functions could share the same helper? + */ int duk_builtin_global_object_escape(duk_context *ctx) { - return DUK_RET_UNIMPLEMENTED_ERROR; /*FIXME*/ + duk_hthread *thr = (duk_hthread *) ctx; + duk_hstring *h_str; + duk_hbuffer_growable *h_buf; + duk_u8 *p_start, *p_end, *p; + duk_u32 cp; + + h_str = duk_to_hstring(ctx, 0); + DUK_ASSERT(h_str != NULL); + + (void) duk_push_new_growable_buffer(ctx, 0); + h_buf = (duk_hbuffer_growable *) duk_get_hbuffer(ctx, -1); + DUK_ASSERT(h_buf != NULL); + DUK_ASSERT(DUK_HBUFFER_HAS_GROWABLE(h_buf)); + + p_start = DUK_HSTRING_GET_DATA(h_str); + p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_str); + p = p_start; + + /* Since escape() is a legacy function, no fast path here to save space. */ + while (p < p_end) { + duk_u8 buf[6]; + size_t len; + + cp = duk_unicode_xutf8_get_u32(thr, &p, p_start, p_end); + if ((cp < 128) && ESCAPE_AS_IS(cp)) { + buf[0] = (duk_u8) cp; + len = 1; + } else if (cp < 256) { + buf[0] = (duk_u8) '%'; + buf[1] = (duk_u8) duk_uc_nybbles[cp >> 4]; + buf[2] = (duk_u8) duk_uc_nybbles[cp & 0x0f]; + len = 3; + } else { + /* FIXME: non-BMP chars will now be clipped */ + buf[0] = (duk_u8) '%'; + buf[1] = (duk_u8) 'u'; + buf[2] = (duk_u8) duk_uc_nybbles[cp >> 12]; + buf[3] = (duk_u8) duk_uc_nybbles[(cp >> 8) & 0x0f]; + buf[4] = (duk_u8) duk_uc_nybbles[(cp >> 4) & 0x0f]; + buf[5] = (duk_u8) duk_uc_nybbles[cp & 0x0f]; + len = 6; + } + duk_hbuffer_append_bytes(thr, h_buf, buf, len); + } + + duk_to_string(ctx, -1); + return 1; } int duk_builtin_global_object_unescape(duk_context *ctx) {