a68de58269a65b534722a154f848a7481c8998b0 larrym Wed Apr 18 13:32:59 2012 -0700 support escaped chars in json strings diff --git src/hg/lib/jsHelper.c src/hg/lib/jsHelper.c index 5dc89f1..6ccc920 100644 --- src/hg/lib/jsHelper.c +++ src/hg/lib/jsHelper.c @@ -747,51 +747,87 @@ char c = s[*posPtr]; if (!isspace(c)) return; (*posPtr)++; } } static void getSpecificChar(char c, char *str, int *posPtr) { // get specified char from string or errAbort if(str[*posPtr] != c) errAbort("Unexpected character '%c' (expected '%c') - string position %d\n", str[*posPtr], c, *posPtr); (*posPtr)++; } +static char *getString(char *str, int *posPtr) +{ +// read a double-quote delimited string; we handle backslash escaping. +// returns allocated string. +char prevChar = 0; +int i; +struct dyString *ds = dyStringNew(1024); +getSpecificChar('"', str, posPtr); +for(i = 0;; i++) + { + char c = str[*posPtr + i]; + if(!c) + errAbort("Premature end of string (missing trailing double-quote); string position '%d'", *posPtr); + else if(prevChar == '\\') + { + switch(c) + { + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 't': + c = '\t'; + break; + } + dyStringAppendC(ds, c); + prevChar = 0; // watch out for edge case where this is an escaped backslash + } + else if(c == '"') + break; + else if(c != '\\') + { + dyStringAppendC(ds, c); + prevChar = c; + } + } +*posPtr += i; +getSpecificChar('"', str, posPtr); +return dyStringCannibalize(&ds); +} + static struct jsonElement *jsonParseExpression(char *str, int *posPtr); static struct jsonElement *jsonParseObject(char *str, int *posPtr) { struct hash *h = newHash(0); getSpecificChar('{', str, posPtr); while(str[*posPtr] != '}') { - int i; + // parse out a name : val pair skipLeadingSpacesWithPos(str, posPtr); - getSpecificChar('"', str, posPtr); - for(i = 0; str[*posPtr + i] && str[*posPtr + i] != '"'; i++) - ; - char *name = cloneStringZ(str + *posPtr, i); - *posPtr += i; - getSpecificChar('"', str, posPtr); - + char *name = getString(str, posPtr); skipLeadingSpacesWithPos(str, posPtr); getSpecificChar(':', str, posPtr); skipLeadingSpacesWithPos(str, posPtr); - hashAdd(h, name, jsonParseExpression(str, posPtr)); skipLeadingSpacesWithPos(str, posPtr); if(str[*posPtr] == ',') (*posPtr)++; else break; } skipLeadingSpacesWithPos(str, posPtr); getSpecificChar('}', str, posPtr); return (struct jsonElement *) newJsonHash(h); } static struct jsonElement *jsonParseList(char *str, int *posPtr) { struct slRef *list = NULL; @@ -805,38 +841,31 @@ slAddHead(&list, e); skipLeadingSpacesWithPos(str, posPtr); if(str[*posPtr] == ',') (*posPtr)++; else break; } skipLeadingSpacesWithPos(str, posPtr); getSpecificChar(']', str, posPtr); slReverse(&list); return (struct jsonElement *) newJsonList(list); } static struct jsonElement *jsonParseString(char *str, int *posPtr) { -int i; -getSpecificChar('"', str, posPtr); -for(i = 0; str[*posPtr + i] && str[*posPtr + i] != '"'; i++) - ; -char *val = cloneStringZ(str + *posPtr, i); -*posPtr += i; -getSpecificChar('"', str, posPtr); -return (struct jsonElement *) newJsonString(val); +return (struct jsonElement *) newJsonString(getString(str, posPtr)); } static struct jsonElement *jsonParseBoolean(char *str, int *posPtr) { struct jsonBooleanElement *ele = NULL; int i; for(i = 0; str[*posPtr + i] && isalpha(str[*posPtr + i]); i++); ; char *val = cloneStringZ(str + *posPtr, i); if(sameWord(val, "true")) ele = newJsonBoolean(TRUE); else if(sameWord(val, "false")) ele = newJsonBoolean(FALSE); else errAbort("Invalid boolean value '%s'; pos: %d", val, *posPtr);