1ee99ce653ae839e4774120c3f3923dc129c8533
angie
  Fri Mar 16 14:41:14 2018 -0700
Moved jsonStringEscape inside jsonWriteString because it's silly to have to remember to call it first every time.
tagStorm programs were doing their own limited escaping (double-quotes only); now they get the same escaping as everywhere else.
refs MLQ #21113

diff --git src/lib/jsonParse.c src/lib/jsonParse.c
index 29216c2..a7bd90e 100644
--- src/lib/jsonParse.c
+++ src/lib/jsonParse.c
@@ -359,98 +359,116 @@
     }
 return NULL;
 }
 
 struct jsonElement *jsonParse(char *str)
 {
 // parse string into an in-memory json representation
 int pos = 0;
 struct jsonElement *ele = jsonParseExpression(str, &pos);
 skipLeadingSpacesWithPos(str, &pos);
 if(str[pos])
     errAbort("Invalid JSON: unprocessed trailing string at position: %d: %s", pos, str + pos);
 return ele;
 }
 
-char *jsonStringEscape(char *inString)
-/* backslash escape a string for use in a double quoted json string.
- * More conservative than javaScriptLiteralEncode because
- * some json parsers complain if you escape & or ' */
+int jsonStringEscapeSize(char *inString)
+/* Return the size in bytes including terminal '\0' for escaped string. */
 {
-char c;
-int outSize = 0;
-char *outString, *out, *in;
-
 if (inString == NULL)
-    return(cloneString(""));
-
-/* Count up how long it will be */
-in = inString;
+    // Empty string
+    return 1;
+int outSize = 0;
+char *in = inString, c;
 while ((c = *in++) != 0)
     {
     switch(c)
         {
         case '\"':
         case '\\':
         case '/':
         case '\b':
         case '\f':
             outSize += 2;
             break;
         case '\r':
         case '\t':
         case '\n':
             outSize += 3;
             break;
         default:
             outSize += 1;
         }
     }
-outString = needMem(outSize+1);
+return outSize + 1;
+}
 
+void jsonStringEscapeBuf(char *inString, char *buf, size_t bufSize)
+/* backslash escape a string for use in a double quoted json string.
+ * More conservative than javaScriptLiteralEncode because
+ * some json parsers complain if you escape & or '.
+ * bufSize must be at least jsonStringEscapeSize(inString). */
+{
+if (inString == NULL)
+    {
+    // Empty string
+    buf[0] = 0;
+    return;
+    }
 /* Encode string */
-in = inString;
-out = outString;
+char *in = inString, *out = buf, c;
 while ((c = *in++) != 0)
     {
+    if (out - buf >= bufSize-1)
+        errAbort("jsonStringEscapeBuf: insufficient buffer size");
     switch(c)
         {
         case '\"':
         case '\\':
         case '/':
         case '\b':
         case '\f':
             *out++ = '\\';
             *out++ = c;
             break;
         case '\r':
             *out++ = '\\';
             *out++ = 'r';
             break;
         case '\t':
             *out++ = '\\';
             *out++ = 't';
             break;
         case '\n':
             *out++ = '\\';
             *out++ = 'n';
             break;
         default:
             *out++ = c;
         }
     }
 *out++ = 0;
+}
+
+char *jsonStringEscape(char *inString)
+/* backslash escape a string for use in a double quoted json string.
+ * More conservative than javaScriptLiteralEncode because
+ * some json parsers complain if you escape & or ' */
+{
+int outSize = jsonStringEscapeSize(inString);
+char *outString = needMem(outSize);
+jsonStringEscapeBuf(inString, outString, outSize);
 return outString;
 }
 
 void jsonFindNameRecurse(struct jsonElement *ele, char *jName, struct slName **pList)
 // Search the JSON tree recursively to find all the values associated to
 // the name, and add them to head of the list.  
 {
 switch (ele->type)
     {
     case jsonObject:
         {
         if(hashNumEntries(ele->val.jeHash))
             {
             struct hashEl *el, *list = hashElListHash(ele->val.jeHash);
             slSort(&list, hashElCmp);