Changeset: 197145517ef4 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=197145517ef4 Modified Files: monetdb5/modules/atoms/json.c Branch: atom_strings Log Message:
Properly interpret backslash escapes when converting json to string.
Including interpreting high and low surrogates.
diffs (210 lines):
diff --git a/monetdb5/modules/atoms/json.c b/monetdb5/modules/atoms/json.c
--- a/monetdb5/modules/atoms/json.c
+++ b/monetdb5/modules/atoms/json.c
@@ -62,14 +62,6 @@ typedef str json;
break;
\
} while (0)
-#define hex(J)
\
- do {
\
- if (isxdigit((unsigned char) *(J)))
\
- (J)++;
\
- else
\
- throw(MAL, "json.parser", "illegal escape char");
\
- } while (0)
-
#define CHECK_JSON(jt)
\
do {
\
if (jt == NULL || jt->error) {
\
@@ -756,6 +748,9 @@ JSONfilterInternal(json *ret, json *js,
static str
JSONstringParser(const char *j, const char **next)
{
+ unsigned int u;
+ bool seensurrogate = false;
+
assert(*j == '"');
j++;
for (; *j; j++) {
@@ -772,16 +767,34 @@ JSONstringParser(const char *j, const ch
case 'n':
case 'r':
case 't':
+ if (seensurrogate)
+ throw(MAL, "json.parser", "illegal
escape char");
continue;
case 'u':
- j++;
- hex(j);
- hex(j);
- hex(j);
- hex(j);
- // Go back one character, because it would be
skipped by the
- // loop iterator otherwise.
- j--;
+ u = 0;
+ for (int i = 0; i < 4; i++) {
+ u <<= 4;
+ j++;
+ if ('0' <= *j && *j <= '9')
+ u |= *j - '0';
+ else if ('a' <= *j && *j <= 'f')
+ u |= *j - 'a' + 10;
+ else if ('A' <= *j && *j <= 'F')
+ u |= *j - 'A' + 10;
+ else
+ throw(MAL, "json.parser",
"illegal escape char");
+ }
+ if (seensurrogate) {
+ if ((u & 0xFC00) == 0xDC00)
+ seensurrogate = false;
+ else
+ throw(MAL, "json.parser",
"illegal escape char");
+ } else {
+ if ((u & 0xFC00) == 0xD800)
+ seensurrogate = true;
+ else if ((u & 0xFC00) == 0xDC00)
+ throw(MAL, "json.parser",
"illegal escape char");
+ }
break;
default:
*next = j;
@@ -789,9 +802,15 @@ JSONstringParser(const char *j, const ch
}
break;
case '"':
+ if (seensurrogate)
+ throw(MAL, "json.parser", "illegal escape
char");
j++;
*next = j;
return MAL_SUCCEED;
+ default:
+ if (seensurrogate)
+ throw(MAL, "json.parser", "illegal escape
char");
+ break;
}
}
*next = j;
@@ -1174,7 +1193,7 @@ static char *
JSONplaintext(char **r, size_t *l, size_t *ilen, JSON *jt, int idx, str sep,
size_t sep_len)
{
int i;
- unsigned int j, k;
+ unsigned int j, u;
switch (jt->elm[idx].kind) {
case JSON_OBJECT:
@@ -1201,18 +1220,79 @@ JSONplaintext(char **r, size_t *l, size_
*l = *ilen - *l;
}
for (j = 1; j < jt->elm[idx].valuelen - 1; j++) {
- if (jt->elm[idx].value[j] == '\\')
- **r = jt->elm[idx].value[++j];
- else
- **r = jt->elm[idx].value[j];
- (*r)++;
- (*l)--;
+ if (jt->elm[idx].value[j] == '\\') {
+ switch (jt->elm[idx].value[++j]) {
+ case '"':
+ case '\\':
+ case '/':
+ *(*r)++ = jt->elm[idx].value[j];
+ (*l)--;
+ break;
+ case 'b':
+ *(*r)++ = '\b';
+ (*l)--;
+ break;
+ case 'f':
+ *(*r)++ = '\f';
+ (*l)--;
+ break;
+ case 'r':
+ *(*r)++ = '\r';
+ (*l)--;
+ break;
+ case 'n':
+ *(*r)++ = '\n';
+ (*l)--;
+ break;
+ case 't':
+ *(*r)++ = '\t';
+ (*l)--;
+ break;
+ case 'u':
+ u = 0;
+ for (int i = 0;i < 4; i++) {
+ char c =
jt->elm[idx].value[++j];
+ u <<= 4;
+ if ('0' <= c && c <= '9')
+ u |= c - '0';
+ else if ('a' <= c && c <= 'f')
+ u |= c - 'a' + 10;
+ else /* if ('A' <= c && c <=
'F') */
+ u |= c - 'A' + 10;
+ }
+ if (u <= 0x7F) {
+ *(*r)++ = (char) u;
+ (*l)--;
+ } else if (u <= 0x7FF) {
+ *(*r)++ = 0xC0 | (u >> 6);
+ *(*r)++ = 0x80 | (u & 0x3F);
+ (*l) -= 2;
+ } else if ((u & 0xFC00) == 0xD800) {
+ /* high surrogate; must be
followed by low surrogate */
+ *(*r)++ = 0xF0 | (((u & 0x03C0)
+ 0x0040) >> 8);
+ *(*r)++ = 0x80 | ((((u &
0x03C0) + 0x0040) >> 2) & 0x3F);
+ **r = 0x80 | ((u & 0x0003) <<
4); /* no increment */
+ (*l) -= 2;
+ } else if ((u & 0xFC00) == 0xDC00) {
+ /* low surrogate; must follow
high surrogate */
+ *(*r)++ |= (u & 0x03C0) >> 6;
/* amend last value */
+ *(*r)++ = 0x80 | (u & 0x3F);
+ (*l) -= 2;
+ } else /* if (u <= 0xFFFF) */ {
+ *(*r)++ = 0xE0 | (u >> 12);
+ *(*r)++ = 0x80 | ((u >> 6) &
0x3F);
+ *(*r)++ = 0x80 | (u & 0x3F);
+ (*l) -= 3;
+ }
+ }
+ } else {
+ *(*r)++ = jt->elm[idx].value[j];
+ (*l)--;
+ }
}
- for(k = 0; k < sep_len; k++) {
- **r = *(sep + k);
- (*r)++;
- }
- (*l) -= k;
+ memcpy(*r, sep, sep_len);
+ *l -= sep_len;
+ *r += sep_len;
break;
default:
if (*l < jt->elm[idx].valuelen + sep_len + 1) {
@@ -1223,16 +1303,12 @@ JSONplaintext(char **r, size_t *l, size_
*r += offset;
*l = *ilen - offset;
}
- for (j = 0; j < jt->elm[idx].valuelen; j++) {
- **r = jt->elm[idx].value[j];
- (*r)++;
- (*l)--;
- }
- for(k = 0; k < sep_len; k++) {
- **r = *(sep + k);
- (*r)++;
- }
- (*l) -= k;
+ memcpy(*r, jt->elm[idx].value, jt->elm[idx].valuelen);
+ *l -= jt->elm[idx].valuelen;
+ *r += jt->elm[idx].valuelen;
+ memcpy(*r, sep, sep_len);
+ *l -= sep_len;
+ *r += sep_len;
}
assert(*l > 0);
**r = 0;
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list
