forked from lda/telodendria
Fix CanonicalJson and ArraySort.
This commit is contained in:
parent
1fa07d2d3c
commit
539fde773f
7 changed files with 81 additions and 106 deletions
|
@ -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);
|
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);
|
ArrayQuickSort(array, pi + 1, high, compare);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -271,7 +271,7 @@ ArraySort(Array * array, int (*compare) (void *, void *))
|
||||||
{
|
{
|
||||||
return;
|
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
|
/* Even though the following operations could be done using only the
|
||||||
|
|
4
TODO.txt
4
TODO.txt
|
@ -16,8 +16,9 @@ Milestone: v0.4.0
|
||||||
|
|
||||||
[~] Client-Server API
|
[~] Client-Server API
|
||||||
[~] 6: Filtering
|
[~] 6: Filtering
|
||||||
|
[ ] Finish validating filters before saving them.
|
||||||
[~] 7: Events
|
[~] 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] Rename Sha2.h to just Sha; add Sha1() function
|
||||||
[x] Make Sha256() return raw bytes; add function to
|
[x] Make Sha256() return raw bytes; add function to
|
||||||
convert to hex string.
|
convert to hex string.
|
||||||
|
@ -44,6 +45,7 @@ Milestone: v0.4.0
|
||||||
use the default. This will make debugging a lot easier.
|
use the default. This will make debugging a lot easier.
|
||||||
[ ] Make sure admin registration token is printed to log, not stdout.
|
[ ] Make sure admin registration token is printed to log, not stdout.
|
||||||
Unless they are the same, of course.
|
Unless they are the same, of course.
|
||||||
|
[ ] Fix Json UTF-8 handling.
|
||||||
|
|
||||||
Milestone: v0.5.0
|
Milestone: v0.5.0
|
||||||
-----------------
|
-----------------
|
||||||
|
|
|
@ -30,29 +30,32 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
int
|
static int
|
||||||
CanonicalJsonKeyCompare(void *k1, void *k2)
|
CanonicalJsonKeyCompare(void *k1, void *k2)
|
||||||
{
|
{
|
||||||
return strcmp((char *) k1, (char *) k2);
|
return strcmp((char *) k1, (char *) k2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
int
|
||||||
CanonicalJsonEncodeValue(JsonValue * value, Stream * out)
|
CanonicalJsonEncodeValue(JsonValue * value, Stream * out)
|
||||||
{
|
{
|
||||||
Array *arr;
|
Array *arr;
|
||||||
size_t i, len;
|
size_t i, len;
|
||||||
|
|
||||||
|
int length = 0;
|
||||||
|
|
||||||
/* Override object type to encode using the canonical functions */
|
/* Override object type to encode using the canonical functions */
|
||||||
switch (JsonValueType(value))
|
switch (JsonValueType(value))
|
||||||
{
|
{
|
||||||
case JSON_OBJECT:
|
case JSON_OBJECT:
|
||||||
CanonicalJsonEncode(JsonValueAsObject(value), out);
|
length += CanonicalJsonEncode(JsonValueAsObject(value), out);
|
||||||
break;
|
break;
|
||||||
case JSON_ARRAY:
|
case JSON_ARRAY:
|
||||||
arr = JsonValueAsArray(value);
|
arr = JsonValueAsArray(value);
|
||||||
len = ArraySize(arr);
|
len = ArraySize(arr);
|
||||||
|
|
||||||
StreamPutc(out, '[');
|
StreamPutc(out, '[');
|
||||||
|
length++;
|
||||||
|
|
||||||
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
|
@ -64,19 +67,23 @@ CanonicalJsonEncodeValue(JsonValue * value, Stream * out)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
CanonicalJsonEncodeValue(aVal, out);
|
length += CanonicalJsonEncodeValue(aVal, out);
|
||||||
if (i < len - 1)
|
if (i < len - 1)
|
||||||
{
|
{
|
||||||
StreamPutc(out, ',');
|
StreamPutc(out, ',');
|
||||||
|
length++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamPutc(out, ']');
|
StreamPutc(out, ']');
|
||||||
|
length++;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
JsonEncodeValue(value, out, JSON_DEFAULT);
|
length += JsonEncodeValue(value, out, JSON_DEFAULT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -87,16 +94,17 @@ CanonicalJsonEncode(HashMap * object, Stream * out)
|
||||||
Array *keys;
|
Array *keys;
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t keyCount;
|
size_t keyCount;
|
||||||
|
int length;
|
||||||
|
|
||||||
if (!object || !out)
|
if (!object)
|
||||||
{
|
{
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
keys = ArrayCreate();
|
keys = ArrayCreate();
|
||||||
if (!keys)
|
if (!keys)
|
||||||
{
|
{
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (HashMapIterate(object, &key, (void **) &value))
|
while (HashMapIterate(object, &key, (void **) &value))
|
||||||
|
@ -106,7 +114,11 @@ CanonicalJsonEncode(HashMap * object, Stream * out)
|
||||||
|
|
||||||
ArraySort(keys, CanonicalJsonKeyCompare);
|
ArraySort(keys, CanonicalJsonKeyCompare);
|
||||||
|
|
||||||
|
/* The total number of bytes written */
|
||||||
|
length = 0;
|
||||||
|
|
||||||
StreamPutc(out, '{');
|
StreamPutc(out, '{');
|
||||||
|
length++;
|
||||||
|
|
||||||
keyCount = ArraySize(keys);
|
keyCount = ArraySize(keys);
|
||||||
for (i = 0; i < keyCount; i++)
|
for (i = 0; i < keyCount; i++)
|
||||||
|
@ -128,18 +140,21 @@ CanonicalJsonEncode(HashMap * object, Stream * out)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonEncodeString(key, out);
|
length += JsonEncodeString(key, out);
|
||||||
StreamPutc(out, ':');
|
StreamPutc(out, ':');
|
||||||
CanonicalJsonEncodeValue(value, out);
|
length++;
|
||||||
|
length += CanonicalJsonEncodeValue(value, out);
|
||||||
|
|
||||||
if (i < keyCount - 1)
|
if (i < keyCount - 1)
|
||||||
{
|
{
|
||||||
StreamPutc(out, ',');
|
StreamPutc(out, ',');
|
||||||
|
length++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamPutc(out, '}');
|
StreamPutc(out, '}');
|
||||||
|
length++;
|
||||||
|
|
||||||
ArrayFree(keys);
|
ArrayFree(keys);
|
||||||
return 1;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
|
|
||||||
#include <HashMap.h>
|
#include <HashMap.h>
|
||||||
#include <Stream.h>
|
#include <Stream.h>
|
||||||
|
#include <Json.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode a JSON object following the rules of Canonical JSON. See the
|
* Encode a JSON object following the rules of Canonical JSON. See the
|
||||||
|
@ -71,25 +72,19 @@
|
||||||
* .Fn JsonEncode ,
|
* .Fn JsonEncode ,
|
||||||
* because it is much cheaper both in terms of memory and CPU time.
|
* because it is much cheaper both in terms of memory and CPU time.
|
||||||
* .Pp
|
* .Pp
|
||||||
* This function returns a boolean value indicating whether or not the
|
* This function returns the number of bytes written to the
|
||||||
* operation was sucessful. This function will fail only if NULL was
|
* stream, just like
|
||||||
* given for any parameter. Otherwise, if an invalid pointer is given,
|
* .Fn JsonEncode .
|
||||||
* undefined behavior results.
|
|
||||||
*/
|
*/
|
||||||
extern int CanonicalJsonEncode(HashMap *, Stream *);
|
extern int CanonicalJsonEncode(HashMap *, Stream *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function encodes a JSON object to a string.
|
* Encode a JSON value following the rules of Canonical JSON.
|
||||||
* .Xr Json 3
|
* See the documentation for
|
||||||
* doesn't have any way to send JSON to a string, because there's
|
* .Fn JsonEncodeValue ,
|
||||||
* absolutely no reason to handle JSON strings in most cases. However,
|
* documented in
|
||||||
* the sole reason Canonical JSON exists is so that JSON objects can
|
* .Xr Json 3 .
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
extern char * CanonicalJsonEncodeToString(HashMap *);
|
extern int CanonicalJsonEncodeValue(JsonValue *, Stream *);
|
||||||
|
|
||||||
#endif /* TELODENDRIA_CANONICALJSON_H */
|
#endif /* TELODENDRIA_CANONICALJSON_H */
|
||||||
|
|
|
@ -183,7 +183,7 @@ recipe_build() {
|
||||||
if [ $(mod_time "$src") -ge $(mod_time "$out") ] || [ $do_rebuild -eq 1 ]; then
|
if [ $(mod_time "$src") -ge $(mod_time "$out") ] || [ $do_rebuild -eq 1 ]; then
|
||||||
echo "CC $(basename $out)"
|
echo "CC $(basename $out)"
|
||||||
mkdir -p "$(dirname $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
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -34,74 +34,6 @@
|
||||||
#include <Db.h>
|
#include <Db.h>
|
||||||
#include <Json.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 HttpServer *server = NULL;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -30,7 +30,9 @@
|
||||||
#include <HashMap.h>
|
#include <HashMap.h>
|
||||||
#include <Str.h>
|
#include <Str.h>
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
|
|
||||||
#include <Json.h>
|
#include <Json.h>
|
||||||
|
#include <CanonicalJson.h>
|
||||||
|
|
||||||
#define FLAG_ENCODE (1 << 0)
|
#define FLAG_ENCODE (1 << 0)
|
||||||
#define FLAG_SELECT (1 << 1)
|
#define FLAG_SELECT (1 << 1)
|
||||||
|
@ -42,7 +44,7 @@ usage(char *prog)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
query(char *select, HashMap * json)
|
query(char *select, HashMap * json, int canonical)
|
||||||
{
|
{
|
||||||
char *key;
|
char *key;
|
||||||
JsonValue *rootVal = JsonValueObject(json);
|
JsonValue *rootVal = JsonValueObject(json);
|
||||||
|
@ -170,7 +172,15 @@ query(char *select, HashMap * json)
|
||||||
|
|
||||||
if (val)
|
if (val)
|
||||||
{
|
{
|
||||||
JsonEncodeValue(val, StreamStdout(), JSON_PRETTY);
|
if (canonical)
|
||||||
|
{
|
||||||
|
CanonicalJsonEncodeValue(val, StreamStdout());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
JsonEncodeValue(val, StreamStdout(), JSON_PRETTY);
|
||||||
|
}
|
||||||
|
|
||||||
StreamPutc(StreamStdout(), '\n');
|
StreamPutc(StreamStdout(), '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,11 +192,19 @@ query(char *select, HashMap * json)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
encode(char *str)
|
encode(char *str, int canonical)
|
||||||
{
|
{
|
||||||
JsonValue *val = JsonValueString(str);
|
JsonValue *val = JsonValueString(str);
|
||||||
|
|
||||||
JsonEncodeValue(val, StreamStdout(), JSON_DEFAULT);
|
if (canonical)
|
||||||
|
{
|
||||||
|
CanonicalJsonEncodeValue(val, StreamStdout());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
JsonEncodeValue(val, StreamStdout(), JSON_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
JsonValueFree(val);
|
JsonValueFree(val);
|
||||||
StreamPutc(StreamStdout(), '\n');
|
StreamPutc(StreamStdout(), '\n');
|
||||||
}
|
}
|
||||||
|
@ -200,8 +218,10 @@ Main(Array * args)
|
||||||
char *input = NULL;
|
char *input = NULL;
|
||||||
ArgParseState arg;
|
ArgParseState arg;
|
||||||
|
|
||||||
|
int canonical = 0;
|
||||||
|
|
||||||
ArgParseStateInit(&arg);
|
ArgParseStateInit(&arg);
|
||||||
while ((ch = ArgParse(&arg, args, "s:e:")) != -1)
|
while ((ch = ArgParse(&arg, args, "cs:e:")) != -1)
|
||||||
{
|
{
|
||||||
switch (ch)
|
switch (ch)
|
||||||
{
|
{
|
||||||
|
@ -213,6 +233,9 @@ Main(Array * args)
|
||||||
flag = FLAG_ENCODE;
|
flag = FLAG_ENCODE;
|
||||||
input = arg.optArg;
|
input = arg.optArg;
|
||||||
break;
|
break;
|
||||||
|
case 'c':
|
||||||
|
canonical = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage(ArrayGet(args, 0));
|
usage(ArrayGet(args, 0));
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -233,13 +256,21 @@ Main(Array * args)
|
||||||
switch (flag)
|
switch (flag)
|
||||||
{
|
{
|
||||||
case FLAG_SELECT:
|
case FLAG_SELECT:
|
||||||
query(input, json); /* This will implicitly free json */
|
query(input, json, canonical); /* This will implicitly free json */
|
||||||
break;
|
break;
|
||||||
case FLAG_ENCODE:
|
case FLAG_ENCODE:
|
||||||
encode(input);
|
encode(input, canonical);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
JsonEncode(json, StreamStdout(), JSON_PRETTY);
|
if (canonical)
|
||||||
|
{
|
||||||
|
CanonicalJsonEncode(json, StreamStdout());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
JsonEncode(json, StreamStdout(), JSON_PRETTY);
|
||||||
|
}
|
||||||
|
|
||||||
StreamPutc(StreamStdout(), '\n');
|
StreamPutc(StreamStdout(), '\n');
|
||||||
JsonFree(json);
|
JsonFree(json);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue