From bc6da35e59c59afc599e67ec45b9f67cfcdeca84 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Thu, 6 Feb 2014 18:19:07 +0100 Subject: [PATCH] Add decode/encode URI functions. --- jsbuiltin.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++ jsbuiltin.h | 29 ++++++++++++++ jsstring.c | 29 -------------- 3 files changed, 139 insertions(+), 29 deletions(-) diff --git a/jsbuiltin.c b/jsbuiltin.c index 3a75a70..591ef0a 100644 --- a/jsbuiltin.c +++ b/jsbuiltin.c @@ -66,6 +66,111 @@ static int jsB_isFinite(js_State *J, int argc) return 1; } +static int Encode(js_State *J, const char *str, const char *unescaped) +{ + struct sbuffer *sb = NULL; + + static const char *HEX = "0123456789ABCDEF"; + + while (*str) { + int c = (unsigned char) *str++; + if (strchr(unescaped, c)) + sb = sb_putc(sb, c); + else { + sb = sb_putc(sb, '%'); + sb = sb_putc(sb, HEX[(c >> 4) & 0xf]); + sb = sb_putc(sb, HEX[c & 0xf]); + } + } + sb = sb_putc(sb, 0); + + if (js_try(J)) { + free(sb); + js_throw(J); + } + js_pushstring(J, sb ? sb->s : ""); + js_endtry(J); + free(sb); + return 1; +} + +static inline int ishex(int c) +{ + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); +} + +static inline int tohex(int c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 0xA; + if (c >= 'A' && c <= 'F') return c - 'A' + 0xA; + return 0; +} + +static int Decode(js_State *J, const char *str, const char *reserved) +{ + struct sbuffer *sb = NULL; + int a, b; + + while (*str) { + int c = (unsigned char) *str++; + if (c != '%') + sb = sb_putc(sb, c); + else { + if (!str[0] || !str[1]) + js_urierror(J, "truncated escape sequence"); + a = *str++; + b = *str++; + if (!ishex(a) || !ishex(b)) + js_urierror(J, "invalid escape sequence"); + c = tohex(a) << 4 | tohex(b); + if (!strchr(reserved, c)) + sb = sb_putc(sb, c); + else { + sb = sb_putc(sb, '%'); + sb = sb_putc(sb, a); + sb = sb_putc(sb, b); + } + } + } + sb = sb_putc(sb, 0); + + if (js_try(J)) { + free(sb); + js_throw(J); + } + js_pushstring(J, sb ? sb->s : ""); + js_endtry(J); + free(sb); + return 1; +} + +#define URIRESERVED ";/?:@&=+$," +#define URIALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define URIDIGIT "0123456789" +#define URIMARK "-_.!~*`()" +#define URIUNESCAPED URIALPHA URIDIGIT URIMARK + +static int jsB_decodeURI(js_State *J, int argc) +{ + return Decode(J, js_tostring(J, 1), URIRESERVED "#"); +} + +static int jsB_decodeURIComponent(js_State *J, int argc) +{ + return Decode(J, js_tostring(J, 1), ""); +} + +static int jsB_encodeURI(js_State *J, int argc) +{ + return Encode(J, js_tostring(J, 1), URIUNESCAPED URIRESERVED "#"); +} + +static int jsB_encodeURIComponent(js_State *J, int argc) +{ + return Encode(J, js_tostring(J, 1), URIUNESCAPED); +} + void jsB_init(js_State *J) { /* Create the prototype objects here, before the constructors */ @@ -114,4 +219,9 @@ void jsB_init(js_State *J) jsB_globalf(J, "parseFloat", jsB_parseFloat, 1); jsB_globalf(J, "isNaN", jsB_isNaN, 1); jsB_globalf(J, "isFinite", jsB_isFinite, 1); + + jsB_globalf(J, "decodeURI", jsB_decodeURI, 1); + jsB_globalf(J, "decodeURIComponent", jsB_decodeURIComponent, 1); + jsB_globalf(J, "encodeURI", jsB_encodeURI, 1); + jsB_globalf(J, "encodeURIComponent", jsB_encodeURIComponent, 1); } diff --git a/jsbuiltin.h b/jsbuiltin.h index c27ff47..87dbe69 100644 --- a/jsbuiltin.h +++ b/jsbuiltin.h @@ -17,4 +17,33 @@ void jsB_propf(js_State *J, const char *name, js_CFunction cfun, int n); void jsB_propn(js_State *J, const char *name, double number); void jsB_props(js_State *J, const char *name, const char *string); +struct sbuffer { int n, m; char s[64]; }; + +static struct sbuffer *sb_putc(struct sbuffer *sb, int c) +{ + if (!sb) { + sb = malloc(sizeof *sb); + sb->n = 0; + sb->m = sizeof sb->s; + } else if (sb->n == sb->m) { + sb = realloc(sb, (sb->m *= 2) + offsetof(struct sbuffer, s)); + } + sb->s[sb->n++] = c; + return sb; +} + +static inline struct sbuffer *sb_puts(struct sbuffer *sb, const char *s) +{ + while (*s) + sb = sb_putc(sb, *s++); + return sb; +} + +static inline struct sbuffer *sb_putm(struct sbuffer *sb, const char *s, const char *e) +{ + while (s < e) + sb = sb_putc(sb, *s++); + return sb; +} + #endif diff --git a/jsstring.c b/jsstring.c index 5488bc5..f7fa126 100644 --- a/jsstring.c +++ b/jsstring.c @@ -7,35 +7,6 @@ #define nelem(a) (sizeof (a) / sizeof (a)[0]) -struct sbuffer { int n, m; char s[64]; }; - -static struct sbuffer *sb_putc(struct sbuffer *sb, int c) -{ - if (!sb) { - sb = malloc(sizeof *sb); - sb->n = 0; - sb->m = sizeof sb->s; - } else if (sb->n == sb->m) { - sb = realloc(sb, (sb->m *= 2) + offsetof(struct sbuffer, s)); - } - sb->s[sb->n++] = c; - return sb; -} - -static struct sbuffer *sb_puts(struct sbuffer *sb, const char *s) -{ - while (*s) - sb = sb_putc(sb, *s++); - return sb; -} - -static struct sbuffer *sb_putm(struct sbuffer *sb, const char *s, const char *e) -{ - while (s < e) - sb = sb_putc(sb, *s++); - return sb; -} - static int jsB_new_String(js_State *J, int argc) { js_newstring(J, argc > 0 ? js_tostring(J, 1) : "");