]> code.citadel.org Git - citadel.git/blobdiff - libcitadel/lib/json.c
Remove preprocessor tests for OpenSSL. It's a requirement.
[citadel.git] / libcitadel / lib / json.c
index 044be9cdf38b338d83a9c57f7bb52bae863a94f4..277bfe0cb44b700ad0a8b34502f6c6d3a9757f39 100644 (file)
@@ -1,12 +1,10 @@
-/*
- * $Id: wildfire.c 6962 2009-01-18 19:33:45Z dothebart $
- */
-/**
- * \defgroup Subst Variable substitution type stuff
- * \ingroup CitadelConfig
- */
-
-/*@{*/
+//
+// JSON data type and serializer for Citadel
+//
+// Copyright (c) 1987-2023 by the citadel.org team
+//
+// This program is open source software.  Use, duplication, or disclosure
+// is subject to the terms of the GNU General Public License, version 3.
 
 #include "sysdep.h"
 #include <sys/types.h>
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
-
 #include "libcitadel.h"
 
-
 #define JSON_STRING 0
 #define JSON_NUM 1
 #define JSON_NULL 2
@@ -36,8 +32,7 @@ struct JsonValue {
 };
 
 
-void DeleteJSONValue(void *vJsonValue)
-{
+void DeleteJSONValue(void *vJsonValue) {
        JsonValue *Val = (JsonValue*) vJsonValue;
        FreeStrBuf(&Val->Name);
        FreeStrBuf(&Val->Value);
@@ -45,153 +40,189 @@ void DeleteJSONValue(void *vJsonValue)
        free(Val);
 }
 
-JsonValue *NewJsonObject(const char *Key, long keylen)
-{
+
+JsonValue *NewJsonObject(const char *Key, long keylen) {
        JsonValue *Ret;
 
        Ret = (JsonValue*) malloc(sizeof(JsonValue));
        memset(Ret, 0, sizeof(JsonValue));
        Ret->Type = JSON_OBJECT;
-       if (Key != NULL)
+       if (Key != NULL) {
                Ret->Name = NewStrBufPlain(Key, keylen);
+       }
        Ret->SubValues = NewHash(1, NULL);
        return Ret;
 }
 
-JsonValue *NewJsonArray(const char *Key, long keylen)
-{
+
+JsonValue *NewJsonArray(const char *Key, long keylen) {
        JsonValue *Ret;
 
        Ret = (JsonValue*) malloc(sizeof(JsonValue));
        memset(Ret, 0, sizeof(JsonValue));
        Ret->Type = JSON_ARRAY;
-       if (Key != NULL)
+       if (Key != NULL) {
                Ret->Name = NewStrBufPlain(Key, keylen);
-       Ret->SubValues = NewHash(1, Flathash);
+       }
+       Ret->SubValues = NewHash(1, lFlathash);
        return Ret;
 }
 
 
-JsonValue *NewJsonNumber(const char *Key, long keylen, long Number)
-{
+JsonValue *NewJsonNumber(const char *Key, long keylen, long Number) {
        JsonValue *Ret;
 
        Ret = (JsonValue*) malloc(sizeof(JsonValue));
        memset(Ret, 0, sizeof(JsonValue));
        Ret->Type = JSON_NUM;
-       if (Key != NULL)
+       if (Key != NULL) {
                Ret->Name = NewStrBufPlain(Key, keylen);
+       }
        Ret->Value = NewStrBufPlain(NULL, 64);
        StrBufPrintf(Ret->Value, "%ld", Number);
        return Ret;
 }
 
 
-
-JsonValue *NewJsonBigNumber(const char *Key, long keylen, double Number)
-{
+JsonValue *NewJsonBigNumber(const char *Key, long keylen, double Number) {
        JsonValue *Ret;
 
        Ret = (JsonValue*) malloc(sizeof(JsonValue));
        memset(Ret, 0, sizeof(JsonValue));
        Ret->Type = JSON_NUM;
-       if (Key != NULL)
+       if (Key != NULL) {
                Ret->Name = NewStrBufPlain(Key, keylen);
+       }
        Ret->Value = NewStrBufPlain(NULL, 128);
        StrBufPrintf(Ret->Value, "%f", Number);
        return Ret;
 }
 
-JsonValue *NewJsonString(const char *Key, long keylen, StrBuf *CopyMe)
-{
+
+JsonValue *NewJsonString(const char *Key, long keylen, StrBuf *CopyMe, int copy_or_smash) {
        JsonValue *Ret;
 
        Ret = (JsonValue*) malloc(sizeof(JsonValue));
        memset(Ret, 0, sizeof(JsonValue));
        Ret->Type = JSON_STRING;
-       if (Key != NULL)
+       if (Key != NULL) {
                Ret->Name = NewStrBufPlain(Key, keylen);
-       Ret->Value = NewStrBufDup(CopyMe);
+       }
+       if (copy_or_smash == NEWJSONSTRING_COPYBUF) {
+               Ret->Value = NewStrBufDup(CopyMe);
+       }
+       else if (copy_or_smash == NEWJSONSTRING_SMASHBUF) {
+               Ret->Value = CopyMe;
+       }
+       else {
+               Ret->Value = NULL;              // error condition
+       }
        return Ret;
 }
 
-JsonValue *NewJsonPlainString(const char *Key, long keylen, const char *CopyMe, long len)
-{
+
+JsonValue *NewJsonPlainString(const char *Key, long keylen, const char *CopyMe, long len) {
        JsonValue *Ret;
 
        Ret = (JsonValue*) malloc(sizeof(JsonValue));
        memset(Ret, 0, sizeof(JsonValue));
        Ret->Type = JSON_STRING;
-       if (Key != NULL)
+       if (Key != NULL) {
                Ret->Name = NewStrBufPlain(Key, keylen);
+       }
        Ret->Value = NewStrBufPlain(CopyMe, len);
        return Ret;
 }
 
-JsonValue *NewJsonNull(const char *Key, long keylen)
-{
+
+JsonValue *NewJsonNull(const char *Key, long keylen) {
        JsonValue *Ret;
 
        Ret = (JsonValue*) malloc(sizeof(JsonValue));
        memset(Ret, 0, sizeof(JsonValue));
        Ret->Type = JSON_NULL;
-       if (Key != NULL)
+       if (Key != NULL) {
                Ret->Name = NewStrBufPlain(Key, keylen);
+       }
        Ret->Value = NewStrBufPlain(HKEY("nulll"));
        return Ret;
 }
 
-JsonValue *NewJsonBool(const char *Key, long keylen, int value)
-{
+
+JsonValue *NewJsonBool(const char *Key, long keylen, int value) {
        JsonValue *Ret;
 
        Ret = (JsonValue*) malloc(sizeof(JsonValue));
        memset(Ret, 0, sizeof(JsonValue));
        Ret->Type = JSON_BOOL;
-       if (Key != NULL)
+       if (Key != NULL) {
                Ret->Name = NewStrBufPlain(Key, keylen);
-       if (value)
+       }
+       if (value) {
                Ret->Value = NewStrBufPlain(HKEY("true"));
-       else
+       }
+       else {
                Ret->Value = NewStrBufPlain(HKEY("false"));
+       }
        return Ret;
 }
 
-void JsonArrayAppend(JsonValue *Array, JsonValue *Val)
-{
+
+void JsonArrayAppend(JsonValue *Array, JsonValue *Val) {
        long n;
-       if (Array->Type != JSON_ARRAY)
-               return; /* todo assert! */
+       if (Array->Type != JSON_ARRAY) {
+               return;
+       }
 
        n = GetCount(Array->SubValues);
-       Put(Array->SubValues, (const char*) &n, sizeof(n), Val, DeleteJSONValue);
+       Put(Array->SubValues, LKEY(n), Val, DeleteJSONValue);
 }
 
-void JsonObjectAppend(JsonValue *Array, JsonValue *Val)
-{
-       if ((Array->Type != JSON_OBJECT) || (Val->Name == NULL))
-               return; /* todo assert! */
 
+void JsonObjectAppend(JsonValue *Array, JsonValue *Val) {
+       if ((Array->Type != JSON_OBJECT) || (Val->Name == NULL)) {
+               return;
+       }
        Put(Array->SubValues, SKEY(Val->Name), Val, DeleteJSONValue);
 }
 
 
-
-
-
-void SerializeJson(StrBuf *Target, JsonValue *Val)
-{
+void SerializeJson(StrBuf *Target, JsonValue *Val, int FreeVal) {
        void *vValue, *vPrevious;
        JsonValue *SubVal;
        HashPos *It;
        const char *Key;
        long keylen;
 
-
        switch (Val->Type) {
        case JSON_STRING:
                StrBufAppendBufPlain(Target, HKEY("\""), 0);
-               StrECMAEscAppend(Target, Val->Value, NULL);
+               int i;
+               char *plain = (char *)ChrPtr(Val->Value);
+               if (!IsEmptyStr(plain)) {
+                       int len = strlen(plain);
+                       for (i=0; i<len; ++i) {
+                               // JSON escaped strings as per RFC 7159 section 7
+                               if (plain[i] == '\r') {
+                                       StrBufAppendBufPlain(Target, HKEY("\\r"), 0);
+                               }
+                               else if (plain[i] == '\n') {
+                                       StrBufAppendBufPlain(Target, HKEY("\\n"), 0);
+                               }
+                               else if (plain[i] == '\"') {
+                                       StrBufAppendBufPlain(Target, HKEY("\\\""), 0);
+                               }
+                               else if (plain[i] == '\\') {
+                                       StrBufAppendBufPlain(Target, HKEY("\\\\"), 0);
+                               }
+                               else if (plain[i] < 32) {
+                                       StrBufAppendPrintf(Target, "\\u%04x", plain[i]);
+                               }
+                               else {
+                                       StrBufAppendBufPlain(Target, &plain[i], 1, 0);
+                               }
+                       }
+               }
                StrBufAppendBufPlain(Target, HKEY("\""), 0);
                break;
        case JSON_NUM:
@@ -207,27 +238,22 @@ void SerializeJson(StrBuf *Target, JsonValue *Val)
                vPrevious = NULL;
                StrBufAppendBufPlain(Target, HKEY("["), 0);
                It = GetNewHashPos(Val->SubValues, 0);
-               while (GetNextHashPos(Val->SubValues, 
-                                     It,
-                                     &keylen, &Key, 
-                                     &vValue)){
-                       if (vPrevious != NULL) 
+               while (GetNextHashPos(Val->SubValues, It, &keylen, &Key, &vValue)) {
+                       if (vPrevious != NULL) {
                                StrBufAppendBufPlain(Target, HKEY(","), 0);
-
+                       }
                        SubVal = (JsonValue*) vValue;
-                       SerializeJson(Target, SubVal);
+                       SerializeJson(Target, SubVal, 0);
                        vPrevious = vValue;
                }
                StrBufAppendBufPlain(Target, HKEY("]"), 0);
+               DeleteHashPos(&It);
                break;
        case JSON_OBJECT:
                vPrevious = NULL;
                StrBufAppendBufPlain(Target, HKEY("{"), 0);
                It = GetNewHashPos(Val->SubValues, 0);
-               while (GetNextHashPos(Val->SubValues, 
-                                     It,
-                                     &keylen, &Key, 
-                                     &vValue)){
+               while (GetNextHashPos(Val->SubValues, It, &keylen, &Key, &vValue)) {
                        SubVal = (JsonValue*) vValue;
 
                        if (vPrevious != NULL) {
@@ -237,13 +263,14 @@ void SerializeJson(StrBuf *Target, JsonValue *Val)
                        StrBufAppendBuf(Target, SubVal->Name, 0);
                        StrBufAppendBufPlain(Target, HKEY("\":"), 0);
 
-                       SerializeJson(Target, SubVal);
+                       SerializeJson(Target, SubVal, 0);
                        vPrevious = vValue;
                }
                StrBufAppendBufPlain(Target, HKEY("}"), 0);
+               DeleteHashPos(&It);
                break;
        }
-
+       if (FreeVal) {
+               DeleteJSONValue(Val);
+       }
 }
-
-