Fix CanonicalJson and ArraySort.

This commit is contained in:
Jordan Bancino 2023-06-21 02:37:56 +00:00
parent 1fa07d2d3c
commit 539fde773f
7 changed files with 81 additions and 106 deletions

View file

@ -259,7 +259,7 @@ ArrayQuickSort(Array * array, size_t low, size_t high, int (*compare) (void *, v
{
size_t pi = ArrayPartition(array, low, high, compare);
ArrayQuickSort(array, low, pi - 1, compare);
ArrayQuickSort(array, low, pi ? pi - 1 : 0, compare);
ArrayQuickSort(array, pi + 1, high, compare);
}
}
@ -271,7 +271,7 @@ ArraySort(Array * array, int (*compare) (void *, void *))
{
return;
}
ArrayQuickSort(array, 0, array->size, compare);
ArrayQuickSort(array, 0, array->size - 1, compare);
}
/* Even though the following operations could be done using only the

View file

@ -16,8 +16,9 @@ Milestone: v0.4.0
[~] Client-Server API
[~] 6: Filtering
[ ] Finish validating filters before saving them.
[~] 7: Events
[ ] Compute size of JSON object in Canonical JSON
[x] Compute size of JSON object in Canonical JSON
[x] Rename Sha2.h to just Sha; add Sha1() function
[x] Make Sha256() return raw bytes; add function to
convert to hex string.
@ -44,6 +45,7 @@ Milestone: v0.4.0
use the default. This will make debugging a lot easier.
[ ] Make sure admin registration token is printed to log, not stdout.
Unless they are the same, of course.
[ ] Fix Json UTF-8 handling.
Milestone: v0.5.0
-----------------

View file

@ -30,29 +30,32 @@
#include <stdio.h>
#include <string.h>
int
static int
CanonicalJsonKeyCompare(void *k1, void *k2)
{
return strcmp((char *) k1, (char *) k2);
}
static void
int
CanonicalJsonEncodeValue(JsonValue * value, Stream * out)
{
Array *arr;
size_t i, len;
int length = 0;
/* Override object type to encode using the canonical functions */
switch (JsonValueType(value))
{
case JSON_OBJECT:
CanonicalJsonEncode(JsonValueAsObject(value), out);
length += CanonicalJsonEncode(JsonValueAsObject(value), out);
break;
case JSON_ARRAY:
arr = JsonValueAsArray(value);
len = ArraySize(arr);
StreamPutc(out, '[');
length++;
for (i = 0; i < len; i++)
{
@ -64,19 +67,23 @@ CanonicalJsonEncodeValue(JsonValue * value, Stream * out)
continue;
}
CanonicalJsonEncodeValue(aVal, out);
length += CanonicalJsonEncodeValue(aVal, out);
if (i < len - 1)
{
StreamPutc(out, ',');
length++;
}
}
StreamPutc(out, ']');
length++;
break;
default:
JsonEncodeValue(value, out, JSON_DEFAULT);
length += JsonEncodeValue(value, out, JSON_DEFAULT);
break;
}
return length;
}
int
@ -87,16 +94,17 @@ CanonicalJsonEncode(HashMap * object, Stream * out)
Array *keys;
size_t i;
size_t keyCount;
int length;
if (!object || !out)
if (!object)
{
return 0;
return -1;
}
keys = ArrayCreate();
if (!keys)
{
return 0;
return -1;
}
while (HashMapIterate(object, &key, (void **) &value))
@ -106,7 +114,11 @@ CanonicalJsonEncode(HashMap * object, Stream * out)
ArraySort(keys, CanonicalJsonKeyCompare);
/* The total number of bytes written */
length = 0;
StreamPutc(out, '{');
length++;
keyCount = ArraySize(keys);
for (i = 0; i < keyCount; i++)
@ -128,18 +140,21 @@ CanonicalJsonEncode(HashMap * object, Stream * out)
continue;
}
JsonEncodeString(key, out);
length += JsonEncodeString(key, out);
StreamPutc(out, ':');
CanonicalJsonEncodeValue(value, out);
length++;
length += CanonicalJsonEncodeValue(value, out);
if (i < keyCount - 1)
{
StreamPutc(out, ',');
length++;
}
}
StreamPutc(out, '}');
length++;
ArrayFree(keys);
return 1;
return length;
}

View file

@ -55,6 +55,7 @@
#include <HashMap.h>
#include <Stream.h>
#include <Json.h>
/**
* Encode a JSON object following the rules of Canonical JSON. See the
@ -71,25 +72,19 @@
* .Fn JsonEncode ,
* because it is much cheaper both in terms of memory and CPU time.
* .Pp
* This function returns a boolean value indicating whether or not the
* operation was sucessful. This function will fail only if NULL was
* given for any parameter. Otherwise, if an invalid pointer is given,
* undefined behavior results.
* This function returns the number of bytes written to the
* stream, just like
* .Fn JsonEncode .
*/
extern int CanonicalJsonEncode(HashMap *, Stream *);
/**
* This function encodes a JSON object to a string.
* .Xr Json 3
* doesn't have any way to send JSON to a string, because there's
* absolutely no reason to handle JSON strings in most cases. However,
* the sole reason Canonical JSON exists is so that JSON objects can
* be signed in a consisten way. Thus, it is likely you need a string
* to pass to the signing function.
* .Pp
* This function returns a C string containing the canonical JSON
* representation of the given object, or NULL if the encoding failed.
* Encode a JSON value following the rules of Canonical JSON.
* See the documentation for
* .Fn JsonEncodeValue ,
* documented in
* .Xr Json 3 .
*/
extern char * CanonicalJsonEncodeToString(HashMap *);
extern int CanonicalJsonEncodeValue(JsonValue *, Stream *);
#endif /* TELODENDRIA_CANONICALJSON_H */

View file

@ -183,7 +183,7 @@ recipe_build() {
if [ $(mod_time "$src") -ge $(mod_time "$out") ] || [ $do_rebuild -eq 1 ]; then
echo "CC $(basename $out)"
mkdir -p "$(dirname $out)"
if ! $CC $CFLAGS -o "$out" "$src" ${CYTOPLASM_FLAGS} ${LDFLAGS} ${STATIC}; then
if ! $CC $CFLAGS -o "$out" "$src" $objs ${CYTOPLASM_FLAGS} ${LDFLAGS} ${STATIC}; then
exit 1
fi
fi

View file

@ -34,74 +34,6 @@
#include <Db.h>
#include <Json.h>
static void
HexDump(size_t off, char *hexBuf, char *asciiBuf, void *args)
{
char *fmt;
(void) args;
if (hexBuf && asciiBuf)
{
fmt = "%04lx: | %s | %s |";
}
else
{
fmt = "%04lx";
}
Log(LOG_DEBUG, fmt, off, hexBuf, asciiBuf);
}
void
TelodendriaMemoryHook(MemoryAction a, MemoryInfo * i, void *args)
{
char *action;
int err = 0;
(void) args;
switch (a)
{
case MEMORY_ALLOCATE:
action = "Allocated";
break;
case MEMORY_REALLOCATE:
action = "Re-allocated";
break;
case MEMORY_FREE:
action = "Freed";
break;
case MEMORY_BAD_POINTER:
err = 1;
action = "Bad pointer to";
break;
case MEMORY_CORRUPTED:
err = 1;
action = "Corrupted block of";
break;
default:
action = "Unknown operation on";
break;
}
Log(err ? LOG_ERR : LOG_DEBUG,
"%s:%d: %s %lu bytes of memory at %p.",
MemoryInfoGetFile(i), MemoryInfoGetLine(i),
action, MemoryInfoGetSize(i),
MemoryInfoGetPointer(i));
if (a != MEMORY_ALLOCATE && a != MEMORY_REALLOCATE)
{
MemoryHexDump(i, HexDump, NULL);
}
if (err)
{
raise(SIGINT);
}
}
static HttpServer *server = NULL;
static void

View file

@ -30,7 +30,9 @@
#include <HashMap.h>
#include <Str.h>
#include <Memory.h>
#include <Json.h>
#include <CanonicalJson.h>
#define FLAG_ENCODE (1 << 0)
#define FLAG_SELECT (1 << 1)
@ -42,7 +44,7 @@ usage(char *prog)
}
static void
query(char *select, HashMap * json)
query(char *select, HashMap * json, int canonical)
{
char *key;
JsonValue *rootVal = JsonValueObject(json);
@ -170,7 +172,15 @@ query(char *select, HashMap * json)
if (val)
{
JsonEncodeValue(val, StreamStdout(), JSON_PRETTY);
if (canonical)
{
CanonicalJsonEncodeValue(val, StreamStdout());
}
else
{
JsonEncodeValue(val, StreamStdout(), JSON_PRETTY);
}
StreamPutc(StreamStdout(), '\n');
}
@ -182,11 +192,19 @@ query(char *select, HashMap * json)
}
static void
encode(char *str)
encode(char *str, int canonical)
{
JsonValue *val = JsonValueString(str);
JsonEncodeValue(val, StreamStdout(), JSON_DEFAULT);
if (canonical)
{
CanonicalJsonEncodeValue(val, StreamStdout());
}
else
{
JsonEncodeValue(val, StreamStdout(), JSON_DEFAULT);
}
JsonValueFree(val);
StreamPutc(StreamStdout(), '\n');
}
@ -200,8 +218,10 @@ Main(Array * args)
char *input = NULL;
ArgParseState arg;
int canonical = 0;
ArgParseStateInit(&arg);
while ((ch = ArgParse(&arg, args, "s:e:")) != -1)
while ((ch = ArgParse(&arg, args, "cs:e:")) != -1)
{
switch (ch)
{
@ -213,6 +233,9 @@ Main(Array * args)
flag = FLAG_ENCODE;
input = arg.optArg;
break;
case 'c':
canonical = 1;
break;
default:
usage(ArrayGet(args, 0));
return 1;
@ -233,13 +256,21 @@ Main(Array * args)
switch (flag)
{
case FLAG_SELECT:
query(input, json); /* This will implicitly free json */
query(input, json, canonical); /* This will implicitly free json */
break;
case FLAG_ENCODE:
encode(input);
encode(input, canonical);
break;
default:
JsonEncode(json, StreamStdout(), JSON_PRETTY);
if (canonical)
{
CanonicalJsonEncode(json, StreamStdout());
}
else
{
JsonEncode(json, StreamStdout(), JSON_PRETTY);
}
StreamPutc(StreamStdout(), '\n');
JsonFree(json);
break;