commit
9bcf2a4434
@ -0,0 +1,44 @@
|
||||
#include "webfuse/impl/json/doc.h"
|
||||
#include "webfuse/impl/json/node_intern.h"
|
||||
#include "webfuse/impl/json/reader.h"
|
||||
#include "webfuse/impl/json/parser.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
struct wf_json_doc
|
||||
{
|
||||
struct wf_json root;
|
||||
};
|
||||
|
||||
struct wf_json_doc *
|
||||
wf_impl_json_doc_loadb(
|
||||
char * data,
|
||||
size_t length)
|
||||
{
|
||||
struct wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, data, length);
|
||||
|
||||
struct wf_json_doc * doc = malloc(sizeof(struct wf_json_doc));
|
||||
if (!wf_impl_json_parse_value(&reader, &doc->root))
|
||||
{
|
||||
free(doc);
|
||||
doc = NULL;
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_json_doc_dispose(
|
||||
struct wf_json_doc * doc)
|
||||
{
|
||||
wf_impl_json_cleanup(&doc->root);
|
||||
free(doc);
|
||||
}
|
||||
|
||||
struct wf_json const *
|
||||
wf_impl_json_doc_root(
|
||||
struct wf_json_doc * doc)
|
||||
{
|
||||
return &doc->root;
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
#ifndef WF_IMPL_JSON_DOC_H
|
||||
#define WF_IMPL_JSON_DOC_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stddef.h>
|
||||
#else
|
||||
#include <cstddef>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
struct wf_json_doc;
|
||||
struct wf_json;
|
||||
|
||||
extern struct wf_json_doc *
|
||||
wf_impl_json_doc_loadb(
|
||||
char * data,
|
||||
size_t length);
|
||||
|
||||
extern void
|
||||
wf_impl_json_doc_dispose(
|
||||
struct wf_json_doc * doc);
|
||||
|
||||
extern struct wf_json const *
|
||||
wf_impl_json_doc_root(
|
||||
struct wf_json_doc * doc);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,206 @@
|
||||
#include "webfuse/impl/json/node_intern.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static struct wf_json const wf_json_undefined =
|
||||
{
|
||||
.type = WF_JSON_TYPE_UNDEFINED,
|
||||
.value = { .b = false }
|
||||
};
|
||||
|
||||
enum wf_json_type
|
||||
wf_impl_json_type(
|
||||
struct wf_json const * json)
|
||||
{
|
||||
return json->type;
|
||||
}
|
||||
|
||||
bool
|
||||
wf_impl_json_bool_get(
|
||||
struct wf_json const * json)
|
||||
{
|
||||
return (WF_JSON_TYPE_BOOL == json->type) ? json->value.b : false;
|
||||
}
|
||||
|
||||
bool
|
||||
wf_impl_json_is_undefined(
|
||||
struct wf_json const * json)
|
||||
{
|
||||
return (WF_JSON_TYPE_UNDEFINED == json->type);
|
||||
}
|
||||
|
||||
bool
|
||||
wf_impl_json_is_null(
|
||||
struct wf_json const * json)
|
||||
{
|
||||
return (WF_JSON_TYPE_NULL == json->type);
|
||||
}
|
||||
|
||||
bool
|
||||
wf_impl_json_is_bool(
|
||||
struct wf_json const * json)
|
||||
{
|
||||
return (WF_JSON_TYPE_BOOL == json->type);
|
||||
}
|
||||
|
||||
bool
|
||||
wf_impl_json_is_int(
|
||||
struct wf_json const * json)
|
||||
{
|
||||
return (WF_JSON_TYPE_INT == json->type);
|
||||
}
|
||||
|
||||
bool
|
||||
wf_impl_json_is_string(
|
||||
struct wf_json const * json)
|
||||
{
|
||||
return (WF_JSON_TYPE_STRING == json->type);
|
||||
}
|
||||
|
||||
bool
|
||||
wf_impl_json_is_array(
|
||||
struct wf_json const * json)
|
||||
{
|
||||
return (WF_JSON_TYPE_ARRAY == json->type);
|
||||
}
|
||||
|
||||
bool
|
||||
wf_impl_json_is_object(
|
||||
struct wf_json const * json)
|
||||
{
|
||||
return (WF_JSON_TYPE_OBJECT == json->type);
|
||||
}
|
||||
|
||||
int
|
||||
wf_impl_json_int_get(
|
||||
struct wf_json const * json)
|
||||
{
|
||||
return (WF_JSON_TYPE_INT == json->type) ? json->value.i : 0;
|
||||
}
|
||||
|
||||
char const *
|
||||
wf_impl_json_string_get(
|
||||
struct wf_json const * json)
|
||||
{
|
||||
return (WF_JSON_TYPE_STRING == json->type) ? json->value.s.data : "";
|
||||
}
|
||||
|
||||
size_t
|
||||
wf_impl_json_string_size(
|
||||
struct wf_json const * json)
|
||||
{
|
||||
return (WF_JSON_TYPE_STRING == json->type) ? json->value.s.size : 0;
|
||||
}
|
||||
|
||||
|
||||
struct wf_json const *
|
||||
wf_impl_json_array_get(
|
||||
struct wf_json const * json,
|
||||
size_t pos)
|
||||
{
|
||||
struct wf_json const * result = &wf_json_undefined;
|
||||
if ((WF_JSON_TYPE_ARRAY == json->type) && (pos < json->value.a.size))
|
||||
{
|
||||
result = &(json->value.a.items[pos]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t
|
||||
wf_impl_json_array_size(
|
||||
struct wf_json const * json)
|
||||
{
|
||||
return (WF_JSON_TYPE_ARRAY == json->type) ? json->value.a.size : 0;
|
||||
}
|
||||
|
||||
struct wf_json const *
|
||||
wf_impl_json_object_get(
|
||||
struct wf_json const * json,
|
||||
char const * key)
|
||||
{
|
||||
if (WF_JSON_TYPE_OBJECT == json->type)
|
||||
{
|
||||
size_t const count = json->value.o.size;
|
||||
for(size_t i = 0; i < count; i++)
|
||||
{
|
||||
struct wf_json_object_item * actual = &(json->value.o.items[i]);
|
||||
if (0 == strcmp(key, actual->key))
|
||||
{
|
||||
return &(actual->json);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &wf_json_undefined;
|
||||
}
|
||||
|
||||
size_t
|
||||
wf_impl_json_object_size(
|
||||
struct wf_json const * json)
|
||||
{
|
||||
return (WF_JSON_TYPE_OBJECT == json->type) ? json->value.o.size : 0;
|
||||
}
|
||||
|
||||
char const *
|
||||
wf_impl_json_object_key(
|
||||
struct wf_json const * json,
|
||||
size_t pos)
|
||||
{
|
||||
char const * result = "";
|
||||
if ((WF_JSON_TYPE_OBJECT == json->type) && (pos < json->value.o.size))
|
||||
{
|
||||
result = json->value.o.items[pos].key;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct wf_json const *
|
||||
wf_impl_json_object_value(
|
||||
struct wf_json const * json,
|
||||
size_t pos)
|
||||
{
|
||||
struct wf_json const * result = &wf_json_undefined;
|
||||
if ((WF_JSON_TYPE_OBJECT == json->type) && (pos < json->value.o.size))
|
||||
{
|
||||
result = &(json->value.o.items[pos].json);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_json_cleanup(
|
||||
struct wf_json * json)
|
||||
{
|
||||
switch (json->type)
|
||||
{
|
||||
case WF_JSON_TYPE_ARRAY:
|
||||
{
|
||||
size_t const count = json->value.a.size;
|
||||
for(size_t i = 0; i < count; i++)
|
||||
{
|
||||
struct wf_json * actual = &(json->value.a.items[i]);
|
||||
wf_impl_json_cleanup(actual);
|
||||
}
|
||||
free(json->value.a.items);
|
||||
}
|
||||
break;
|
||||
case WF_JSON_TYPE_OBJECT:
|
||||
{
|
||||
size_t const count = json->value.o.size;
|
||||
for(size_t i = 0; i < count; i++)
|
||||
{
|
||||
struct wf_json * actual = &(json->value.o.items[i].json);
|
||||
wf_impl_json_cleanup(actual);
|
||||
}
|
||||
free(json->value.o.items);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
#ifndef WF_IMPL_JSON_NODE_H
|
||||
#define WF_IMPL_JSON_NODE_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#else
|
||||
#include <cstddef>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
enum wf_json_type
|
||||
{
|
||||
WF_JSON_TYPE_UNDEFINED,
|
||||
WF_JSON_TYPE_NULL,
|
||||
WF_JSON_TYPE_BOOL,
|
||||
WF_JSON_TYPE_INT,
|
||||
WF_JSON_TYPE_STRING,
|
||||
WF_JSON_TYPE_ARRAY,
|
||||
WF_JSON_TYPE_OBJECT
|
||||
};
|
||||
|
||||
struct wf_json;
|
||||
|
||||
extern enum wf_json_type
|
||||
wf_impl_json_type(
|
||||
struct wf_json const * json);
|
||||
|
||||
extern bool
|
||||
wf_impl_json_is_undefined(
|
||||
struct wf_json const * json);
|
||||
|
||||
extern bool
|
||||
wf_impl_json_is_null(
|
||||
struct wf_json const * json);
|
||||
|
||||
extern bool
|
||||
wf_impl_json_is_bool(
|
||||
struct wf_json const * json);
|
||||
|
||||
extern bool
|
||||
wf_impl_json_is_int(
|
||||
struct wf_json const * json);
|
||||
|
||||
extern bool
|
||||
wf_impl_json_is_string(
|
||||
struct wf_json const * json);
|
||||
|
||||
extern bool
|
||||
wf_impl_json_is_array(
|
||||
struct wf_json const * json);
|
||||
|
||||
extern bool
|
||||
wf_impl_json_is_object(
|
||||
struct wf_json const * json);
|
||||
|
||||
extern bool
|
||||
wf_impl_json_bool_get(
|
||||
struct wf_json const * json);
|
||||
|
||||
extern int
|
||||
wf_impl_json_int_get(
|
||||
struct wf_json const * json);
|
||||
|
||||
extern char const *
|
||||
wf_impl_json_string_get(
|
||||
struct wf_json const * json);
|
||||
|
||||
extern size_t
|
||||
wf_impl_json_string_size(
|
||||
struct wf_json const * json);
|
||||
|
||||
extern struct wf_json const *
|
||||
wf_impl_json_array_get(
|
||||
struct wf_json const * json,
|
||||
size_t pos);
|
||||
|
||||
extern size_t
|
||||
wf_impl_json_array_size(
|
||||
struct wf_json const * json);
|
||||
|
||||
extern struct wf_json const *
|
||||
wf_impl_json_object_get(
|
||||
struct wf_json const * json,
|
||||
char const * key);
|
||||
|
||||
extern size_t
|
||||
wf_impl_json_object_size(
|
||||
struct wf_json const * json);
|
||||
|
||||
extern char const *
|
||||
wf_impl_json_object_key(
|
||||
struct wf_json const * json,
|
||||
size_t pos);
|
||||
|
||||
extern struct wf_json const *
|
||||
wf_impl_json_object_value(
|
||||
struct wf_json const * json,
|
||||
size_t pos);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,60 @@
|
||||
#ifndef WF_IMPL_JSON_NODE_INTERN_H
|
||||
#define WF_IMPL_JSON_NODE_INTERN_H
|
||||
|
||||
#include "webfuse/impl/json/node.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
struct wf_json_string
|
||||
{
|
||||
char * data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct wf_json_array
|
||||
{
|
||||
struct wf_json * items;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct wf_json_object_item;
|
||||
|
||||
struct wf_json_object
|
||||
{
|
||||
struct wf_json_object_item * items;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
union wf_json_value
|
||||
{
|
||||
bool b;
|
||||
int i;
|
||||
struct wf_json_string s;
|
||||
struct wf_json_array a;
|
||||
struct wf_json_object o;
|
||||
};
|
||||
|
||||
struct wf_json
|
||||
{
|
||||
enum wf_json_type type;
|
||||
union wf_json_value value;
|
||||
};
|
||||
|
||||
struct wf_json_object_item
|
||||
{
|
||||
struct wf_json json;
|
||||
char * key;
|
||||
};
|
||||
|
||||
extern void
|
||||
wf_impl_json_cleanup(
|
||||
struct wf_json * json);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,291 @@
|
||||
#include "webfuse/impl/json/parser.h"
|
||||
#include "webfuse/impl/json/reader.h"
|
||||
#include "webfuse/impl/json/node_intern.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define WF_JSON_PARSER_INITIAL_CAPACITY 4
|
||||
|
||||
static bool
|
||||
wf_impl_json_parse_null(
|
||||
struct wf_json_reader * reader,
|
||||
struct wf_json * json);
|
||||
|
||||
static bool
|
||||
wf_impl_json_parse_true(
|
||||
struct wf_json_reader * reader,
|
||||
struct wf_json * json);
|
||||
|
||||
static bool
|
||||
wf_impl_json_parse_false(
|
||||
struct wf_json_reader * reader,
|
||||
struct wf_json * json);
|
||||
|
||||
static bool
|
||||
wf_impl_json_parse_int(
|
||||
struct wf_json_reader * reader,
|
||||
struct wf_json * json);
|
||||
|
||||
static bool
|
||||
wf_impl_json_parse_string(
|
||||
struct wf_json_reader * reader,
|
||||
struct wf_json * json);
|
||||
|
||||
static bool
|
||||
wf_impl_json_parse_array(
|
||||
struct wf_json_reader * reader,
|
||||
struct wf_json * json);
|
||||
|
||||
static bool
|
||||
wf_impl_json_parse_object(
|
||||
struct wf_json_reader * reader,
|
||||
struct wf_json * json);
|
||||
|
||||
// --
|
||||
|
||||
bool
|
||||
wf_impl_json_parse_value(
|
||||
struct wf_json_reader * reader,
|
||||
struct wf_json * json)
|
||||
{
|
||||
bool result = false;
|
||||
char const c = wf_impl_json_reader_skip_whitespace(reader);
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 'n':
|
||||
result = wf_impl_json_parse_null(reader, json);
|
||||
break;
|
||||
case 't':
|
||||
result = wf_impl_json_parse_true(reader, json);
|
||||
break;
|
||||
case 'f':
|
||||
result = wf_impl_json_parse_false(reader, json);
|
||||
break;
|
||||
case '\"':
|
||||
result = wf_impl_json_parse_string(reader, json);
|
||||
break;
|
||||
case '[':
|
||||
result = wf_impl_json_parse_array(reader, json);
|
||||
break;
|
||||
case '{':
|
||||
result = wf_impl_json_parse_object(reader, json);
|
||||
break;
|
||||
case '-': // fall-through
|
||||
case '0': // fall-through
|
||||
case '1': // fall-through
|
||||
case '2': // fall-through
|
||||
case '3': // fall-through
|
||||
case '4': // fall-through
|
||||
case '5': // fall-through
|
||||
case '6': // fall-through
|
||||
case '7': // fall-through
|
||||
case '8': // fall-through
|
||||
case '9':
|
||||
result = wf_impl_json_parse_int(reader, json);
|
||||
break;
|
||||
default:
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --
|
||||
|
||||
static bool
|
||||
wf_impl_json_parse_null(
|
||||
struct wf_json_reader * reader,
|
||||
struct wf_json * json)
|
||||
{
|
||||
bool const result = wf_impl_json_reader_read_const(reader, "null", 4);
|
||||
if (result)
|
||||
{
|
||||
json->type = WF_JSON_TYPE_NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool
|
||||
wf_impl_json_parse_true(
|
||||
struct wf_json_reader * reader,
|
||||
struct wf_json * json)
|
||||
{
|
||||
bool const result = wf_impl_json_reader_read_const(reader, "true", 4);
|
||||
if (result)
|
||||
{
|
||||
json->type = WF_JSON_TYPE_BOOL;
|
||||
json->value.b = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool
|
||||
wf_impl_json_parse_false(
|
||||
struct wf_json_reader * reader,
|
||||
struct wf_json * json)
|
||||
{
|
||||
bool const result = wf_impl_json_reader_read_const(reader, "false", 5);
|
||||
if (result)
|
||||
{
|
||||
json->type = WF_JSON_TYPE_BOOL;
|
||||
json->value.b = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
wf_impl_json_parse_int(
|
||||
struct wf_json_reader * reader,
|
||||
struct wf_json * json)
|
||||
{
|
||||
int value;
|
||||
bool const result = wf_impl_json_reader_read_int(reader, &value);
|
||||
if (result)
|
||||
{
|
||||
json->type = WF_JSON_TYPE_INT;
|
||||
json->value.i = value;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool
|
||||
wf_impl_json_parse_string(
|
||||
struct wf_json_reader * reader,
|
||||
struct wf_json * json)
|
||||
{
|
||||
char * value;
|
||||
size_t size;
|
||||
bool const result = wf_impl_json_reader_read_string(reader, &value, &size);
|
||||
if (result)
|
||||
{
|
||||
json->type = WF_JSON_TYPE_STRING;
|
||||
json->value.s.data = value;
|
||||
json->value.s.size = size;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool
|
||||
wf_impl_json_parse_array(
|
||||
struct wf_json_reader * reader,
|
||||
struct wf_json * json)
|
||||
{
|
||||
wf_impl_json_reader_skip_whitespace(reader);
|
||||
char c = wf_impl_json_reader_get_char(reader);
|
||||
if ('[' != c) { return false; }
|
||||
|
||||
size_t capacity = WF_JSON_PARSER_INITIAL_CAPACITY;
|
||||
json->type = WF_JSON_TYPE_ARRAY;
|
||||
json->value.a.items = malloc(sizeof(struct wf_json) * capacity);
|
||||
json->value.a.size = 0;
|
||||
|
||||
c = wf_impl_json_reader_skip_whitespace(reader);
|
||||
if (']' == c)
|
||||
{
|
||||
wf_impl_json_reader_get_char(reader);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool result;
|
||||
do
|
||||
{
|
||||
if (json->value.a.size >= capacity)
|
||||
{
|
||||
capacity *= 2;
|
||||
json->value.a.items = realloc(json->value.a.items, sizeof(struct wf_json) * capacity);
|
||||
}
|
||||
|
||||
result = wf_impl_json_parse_value(reader, &(json->value.a.items[json->value.a.size]));
|
||||
if (result)
|
||||
{
|
||||
json->value.a.size++;
|
||||
wf_impl_json_reader_skip_whitespace(reader);
|
||||
c = wf_impl_json_reader_get_char(reader);
|
||||
}
|
||||
} while ((result) && (',' == c));
|
||||
|
||||
if (']' != c)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
wf_impl_json_cleanup(json);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool
|
||||
wf_impl_json_parse_object(
|
||||
struct wf_json_reader * reader,
|
||||
struct wf_json * json)
|
||||
{
|
||||
wf_impl_json_reader_skip_whitespace(reader);
|
||||
char c = wf_impl_json_reader_get_char(reader);
|
||||
if ('{' != c) { return false; }
|
||||
|
||||
size_t capacity = WF_JSON_PARSER_INITIAL_CAPACITY;
|
||||
json->type = WF_JSON_TYPE_OBJECT;
|
||||
json->value.o.items = malloc(sizeof(struct wf_json_object_item) * capacity);
|
||||
json->value.o.size = 0;
|
||||
|
||||
c = wf_impl_json_reader_skip_whitespace(reader);
|
||||
if ('}' == c)
|
||||
{
|
||||
wf_impl_json_reader_get_char(reader);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool result;
|
||||
do
|
||||
{
|
||||
if (json->value.o.size >= capacity)
|
||||
{
|
||||
capacity *= 2;
|
||||
json->value.o.items = realloc(json->value.o.items, sizeof(struct wf_json_object_item) * capacity);
|
||||
}
|
||||
|
||||
struct wf_json_object_item * item = &(json->value.o.items[json->value.o.size]);
|
||||
size_t key_size;
|
||||
result = wf_impl_json_reader_read_string(reader, &(item->key), &key_size);
|
||||
if (result)
|
||||
{
|
||||
wf_impl_json_reader_skip_whitespace(reader);
|
||||
result = (':' == wf_impl_json_reader_get_char(reader));
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
result = wf_impl_json_parse_value(reader, &(item->json));
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
json->value.o.size++;
|
||||
wf_impl_json_reader_skip_whitespace(reader);
|
||||
c = wf_impl_json_reader_get_char(reader);
|
||||
}
|
||||
} while ((result) && (',' == c));
|
||||
|
||||
if ('}' != c)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
wf_impl_json_cleanup(json);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
#ifndef WF_IMPL_JSON_PARSER_H
|
||||
#define WF_IMPL_JSON_PARSER_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
struct wf_json_reader;
|
||||
struct wf_json;
|
||||
|
||||
extern bool
|
||||
wf_impl_json_parse_value(
|
||||
struct wf_json_reader * reader,
|
||||
struct wf_json * json);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,181 @@
|
||||
#include "webfuse/impl/json/reader.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static char
|
||||
wf_impl_json_unescape(
|
||||
char c);
|
||||
|
||||
void
|
||||
wf_impl_json_reader_init(
|
||||
struct wf_json_reader * reader,
|
||||
char * contents,
|
||||
size_t length)
|
||||
{
|
||||
reader->contents = contents;
|
||||
reader->length = length;
|
||||
reader->pos = 0;
|
||||
}
|
||||
|
||||
char
|
||||
wf_impl_json_reader_skip_whitespace(
|
||||
struct wf_json_reader * reader)
|
||||
{
|
||||
char c = wf_impl_json_reader_peek(reader);
|
||||
while ((' ' == c) || ('\n' == c) || ('\t' == c) || ('\r' == c))
|
||||
{
|
||||
reader->pos++;
|
||||
c = wf_impl_json_reader_peek(reader);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
char
|
||||
wf_impl_json_reader_peek(
|
||||
struct wf_json_reader * reader)
|
||||
{
|
||||
char result = '\0';
|
||||
if (reader->pos < reader->length)
|
||||
{
|
||||
result = reader->contents[reader->pos];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
char
|
||||
wf_impl_json_reader_get_char(
|
||||
struct wf_json_reader * reader)
|
||||
{
|
||||
char result = '\0';
|
||||
if (reader->pos < reader->length)
|
||||
{
|
||||
result = reader->contents[reader->pos++];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_json_reader_unget_char(
|
||||
struct wf_json_reader * reader)
|
||||
{
|
||||
if (0 < reader->pos)
|
||||
{
|
||||
reader->pos--;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
wf_impl_json_reader_read_const(
|
||||
struct wf_json_reader * reader,
|
||||
char const * value,
|
||||
size_t length)
|
||||
{
|
||||
size_t remaining = reader->length - reader->pos;
|
||||
bool const result = ((remaining >= length) && (0 == strncmp((&reader->contents[reader->pos]), value, length)));
|
||||
if (result)
|
||||
{
|
||||
reader->pos += length;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
wf_impl_json_reader_read_int(
|
||||
struct wf_json_reader * reader,
|
||||
int * value)
|
||||
{
|
||||
char c = wf_impl_json_reader_get_char(reader);
|
||||
bool const is_signed = ('-' == c);
|
||||
if (is_signed)
|
||||
{
|
||||
c = wf_impl_json_reader_get_char(reader);
|
||||
}
|
||||
|
||||
bool const result = (('0' <= c) && (c <= '9'));
|
||||
if (result)
|
||||
{
|
||||
int v = c - '0';
|
||||
c = wf_impl_json_reader_peek(reader);
|
||||
while (('0' <= c) && (c <= '9'))
|
||||
{
|
||||
v *= 10;
|
||||
v += c - '0';
|
||||
reader->pos++;
|
||||
c = wf_impl_json_reader_peek(reader);
|
||||
}
|
||||
|
||||
*value = (is_signed) ? -v : v;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
wf_impl_json_reader_read_string(
|
||||
struct wf_json_reader * reader,
|
||||
char * * value,
|
||||
size_t * size)
|
||||
{
|
||||
wf_impl_json_reader_skip_whitespace(reader);
|
||||
char c = wf_impl_json_reader_get_char(reader);
|
||||
if ('\"' != c) { return false; }
|
||||
|
||||
size_t start = reader->pos;
|
||||
size_t p = reader->pos;
|
||||
c = wf_impl_json_reader_get_char(reader);
|
||||
while (('\"' != c) && ('\0' != c))
|
||||
{
|
||||
if ('\\' != c)
|
||||
{
|
||||
reader->contents[p++] = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
char unescaped = wf_impl_json_unescape(wf_impl_json_reader_get_char(reader));
|
||||
if ('\0' != unescaped)
|
||||
{
|
||||
reader->contents[p++] = unescaped;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
c = wf_impl_json_reader_get_char(reader);
|
||||
}
|
||||
|
||||
bool const result = ('\"' == c);
|
||||
if (result)
|
||||
{
|
||||
reader->contents[p] = '\0';
|
||||
*value = &(reader->contents[start]);
|
||||
*size = p - start;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static char
|
||||
wf_impl_json_unescape(
|
||||
char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '\"': return '\"';
|
||||
case '\\': return '\\';
|
||||
case '/': return '/';
|
||||
case 'b': return '\b';
|
||||
case 'f': return '\f';
|
||||
case 'n': return '\n';
|
||||
case 'r': return '\r';
|
||||
case 't': return '\t';
|
||||
default:
|
||||
return '\0';
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
#ifndef WF_IMPL_JSON_READER_H
|
||||
#define WF_IMPL_JSON_READER_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#else
|
||||
#include <cstddef>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
struct wf_json_reader
|
||||
{
|
||||
char * contents;
|
||||
size_t length;
|
||||
size_t pos;
|
||||
};
|
||||
|
||||
extern void
|
||||
wf_impl_json_reader_init(
|
||||
struct wf_json_reader * reader,
|
||||
char * contents,
|
||||
size_t length);
|
||||
|
||||
extern char
|
||||
wf_impl_json_reader_skip_whitespace(
|
||||
struct wf_json_reader * reader);
|
||||
|
||||
extern char
|
||||
wf_impl_json_reader_peek(
|
||||
struct wf_json_reader * reader);
|
||||
|
||||
extern char
|
||||
wf_impl_json_reader_get_char(
|
||||
struct wf_json_reader * reader);
|
||||
|
||||
extern void
|
||||
wf_impl_json_reader_unget_char(
|
||||
struct wf_json_reader * reader);
|
||||
|
||||
extern bool
|
||||
wf_impl_json_reader_read_const(
|
||||
struct wf_json_reader * reader,
|
||||
char const * value,
|
||||
size_t length);
|
||||
|
||||
extern bool
|
||||
wf_impl_json_reader_read_int(
|
||||
struct wf_json_reader * reader,
|
||||
int * value);
|
||||
|
||||
extern bool
|
||||
wf_impl_json_reader_read_string(
|
||||
struct wf_json_reader * reader,
|
||||
char * * value,
|
||||
size_t * size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,67 @@
|
||||
#include "webfuse/impl/jsonrpc/response_writer.h"
|
||||
#include "webfuse/impl/message.h"
|
||||
#include "webfuse/impl/json/writer.h"
|
||||
|
||||
#include <libwebsockets.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define WF_RESPONSE_WRITER_DEFAULT_MESSAGE_SIZE 1024
|
||||
|
||||
struct wf_jsonrpc_response_writer
|
||||
{
|
||||
struct wf_json_writer * json_writer;
|
||||
int id;
|
||||
};
|
||||
|
||||
struct wf_jsonrpc_response_writer *
|
||||
wf_impl_jsonrpc_response_writer_create(int id)
|
||||
{
|
||||
struct wf_jsonrpc_response_writer * writer = malloc(sizeof(struct wf_jsonrpc_response_writer));
|
||||
writer->json_writer = wf_impl_json_writer_create(WF_RESPONSE_WRITER_DEFAULT_MESSAGE_SIZE, LWS_PRE);
|
||||
writer->id = id;
|
||||
|
||||
wf_impl_json_write_object_begin(writer->json_writer);
|
||||
wf_impl_json_write_object_begin_object(writer->json_writer, "result");
|
||||
|
||||
return writer;
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_jsonrpc_response_writer_dispose(
|
||||
struct wf_jsonrpc_response_writer * writer)
|
||||
{
|
||||
wf_impl_json_writer_dispose(writer->json_writer);
|
||||
free(writer);
|
||||
}
|
||||
|
||||
struct wf_message *
|
||||
wf_impl_jsonrpc_response_writer_take_message(
|
||||
struct wf_jsonrpc_response_writer * writer)
|
||||
{
|
||||
wf_impl_json_write_object_end(writer->json_writer);
|
||||
wf_impl_json_write_object_int(writer->json_writer, "id", writer->id);
|
||||
wf_impl_json_write_object_end(writer->json_writer);
|
||||
|
||||
size_t length;
|
||||
char * data = wf_impl_json_writer_take(writer->json_writer, &length);
|
||||
|
||||
return wf_impl_message_create(data, length);
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_jsonrpc_response_add_int(
|
||||
struct wf_jsonrpc_response_writer * writer,
|
||||
char const * key,
|
||||
int value)
|
||||
{
|
||||
wf_impl_json_write_object_int(writer->json_writer, key, value);
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_jsonrpc_response_add_string(
|
||||
struct wf_jsonrpc_response_writer * writer,
|
||||
char const * key,
|
||||
char const * value)
|
||||
{
|
||||
wf_impl_json_write_object_string(writer->json_writer, key, value);
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
#ifndef WF_IMPL_JSONRPC_RESPONSE_WRITER_H
|
||||
#define WF_IMPL_JSONRPC_RESPONSE_WRITER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
struct wf_jsonrpc_response_writer;
|
||||
struct wf_messge;
|
||||
|
||||
extern struct wf_jsonrpc_response_writer *
|
||||
wf_impl_jsonrpc_response_writer_create(int id);
|
||||
|
||||
extern void
|
||||
wf_impl_jsonrpc_response_writer_dispose(
|
||||
struct wf_jsonrpc_response_writer * writer);
|
||||
|
||||
extern struct wf_message *
|
||||
wf_impl_jsonrpc_response_writer_take_message(
|
||||
struct wf_jsonrpc_response_writer * writer);
|
||||
|
||||
extern void
|
||||
wf_impl_jsonrpc_response_add_int(
|
||||
struct wf_jsonrpc_response_writer * writer,
|
||||
char const * key,
|
||||
int value);
|
||||
|
||||
extern void
|
||||
wf_impl_jsonrpc_response_add_string(
|
||||
struct wf_jsonrpc_response_writer * writer,
|
||||
char const * key,
|
||||
char const * value);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,10 +0,0 @@
|
||||
[wrap-file]
|
||||
directory = jansson-2.11
|
||||
|
||||
source_url = http://www.digip.org/jansson/releases/jansson-2.11.tar.bz2
|
||||
source_filename = jansson-2.11.tar.bz2
|
||||
source_hash = 783132e2fc970feefc2fa54199ef65ee020bd8e0e991a78ea44b8586353a0947
|
||||
|
||||
patch_url = https://wrapdb.mesonbuild.com/v1/projects/jansson/2.11/3/get_zip
|
||||
patch_filename = jansson-2.11-3-wrap.zip
|
||||
patch_hash = 0bcac510994890048d42658c674e33dd7d88715fc1e3bf49d10012f57b0e0020
|
@ -0,0 +1,23 @@
|
||||
#include "webfuse/impl/json/doc.h"
|
||||
#include "webfuse/impl/json/node.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(json_doc, loadb)
|
||||
{
|
||||
char text[] = "true";
|
||||
wf_json_doc * doc = wf_impl_json_doc_loadb(text, 4);
|
||||
ASSERT_NE(nullptr, doc);
|
||||
|
||||
wf_json const * root = wf_impl_json_doc_root(doc);
|
||||
ASSERT_EQ(WF_JSON_TYPE_BOOL, wf_impl_json_type(root));
|
||||
ASSERT_TRUE(wf_impl_json_bool_get(root));
|
||||
|
||||
wf_impl_json_doc_dispose(doc);
|
||||
}
|
||||
|
||||
TEST(json_doc, loadb_fail_invalid_json)
|
||||
{
|
||||
char text[] = "true";
|
||||
wf_json_doc * doc = wf_impl_json_doc_loadb(text, 3);
|
||||
ASSERT_EQ(nullptr, doc);
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
#include "webfuse/impl/json/node.h"
|
||||
#include "webfuse/test_util/json_doc.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using webfuse_test::JsonDoc;
|
||||
|
||||
TEST(json_node, null)
|
||||
{
|
||||
JsonDoc doc("null");
|
||||
ASSERT_EQ(WF_JSON_TYPE_NULL, wf_impl_json_type(doc.root()));
|
||||
ASSERT_TRUE(wf_impl_json_is_null(doc.root()));
|
||||
}
|
||||
|
||||
TEST(json_node, true)
|
||||
{
|
||||
JsonDoc doc("true");
|
||||
ASSERT_EQ(WF_JSON_TYPE_BOOL, wf_impl_json_type(doc.root()));
|
||||
ASSERT_TRUE(wf_impl_json_is_bool(doc.root()));
|
||||
ASSERT_TRUE(wf_impl_json_bool_get(doc.root()));
|
||||
}
|
||||
|
||||
TEST(json_node, false)
|
||||
{
|
||||
JsonDoc doc("false");
|
||||
ASSERT_EQ(WF_JSON_TYPE_BOOL, wf_impl_json_type(doc.root()));
|
||||
ASSERT_TRUE(wf_impl_json_is_bool(doc.root()));
|
||||
ASSERT_FALSE(wf_impl_json_bool_get(doc.root()));
|
||||
}
|
||||
|
||||
TEST(json_node, int)
|
||||
{
|
||||
JsonDoc doc("42");
|
||||
ASSERT_EQ(WF_JSON_TYPE_INT, wf_impl_json_type(doc.root()));
|
||||
ASSERT_TRUE(wf_impl_json_is_int(doc.root()));
|
||||
ASSERT_EQ(42, wf_impl_json_int_get(doc.root()));
|
||||
}
|
||||
|
||||
TEST(json_node, string)
|
||||
{
|
||||
JsonDoc doc("\"brummni\"");
|
||||
ASSERT_EQ(WF_JSON_TYPE_STRING, wf_impl_json_type(doc.root()));
|
||||
ASSERT_TRUE(wf_impl_json_is_string(doc.root()));
|
||||
ASSERT_STREQ("brummni", wf_impl_json_string_get(doc.root()));
|
||||
}
|
||||
|
||||
TEST(json_node, array)
|
||||
{
|
||||
JsonDoc doc("[1,2,3]");
|
||||
ASSERT_EQ(WF_JSON_TYPE_ARRAY, wf_impl_json_type(doc.root()));
|
||||
ASSERT_TRUE(wf_impl_json_is_array(doc.root()));
|
||||
ASSERT_EQ(3, wf_impl_json_array_size(doc.root()));
|
||||
ASSERT_EQ(WF_JSON_TYPE_INT, wf_impl_json_type(wf_impl_json_array_get(doc.root(), 0)));
|
||||
ASSERT_EQ(WF_JSON_TYPE_UNDEFINED, wf_impl_json_type(wf_impl_json_array_get(doc.root(), 4)));
|
||||
}
|
||||
|
||||
TEST(json_node, object)
|
||||
{
|
||||
JsonDoc doc("{\"answer\": 42}");
|
||||
ASSERT_EQ(WF_JSON_TYPE_OBJECT, wf_impl_json_type(doc.root()));
|
||||
ASSERT_TRUE(wf_impl_json_is_object(doc.root()));
|
||||
ASSERT_EQ(1, wf_impl_json_object_size(doc.root()));
|
||||
|
||||
ASSERT_EQ(WF_JSON_TYPE_INT, wf_impl_json_type(wf_impl_json_object_get(doc.root(), "answer")));
|
||||
ASSERT_STREQ("answer", wf_impl_json_object_key(doc.root(), 0));
|
||||
ASSERT_EQ(WF_JSON_TYPE_INT, wf_impl_json_type(wf_impl_json_object_value(doc.root(), 0)));
|
||||
|
||||
ASSERT_EQ(WF_JSON_TYPE_UNDEFINED, wf_impl_json_type(wf_impl_json_object_get(doc.root(), "unknown")));
|
||||
ASSERT_STREQ("", wf_impl_json_object_key(doc.root(), 1));
|
||||
ASSERT_EQ(WF_JSON_TYPE_UNDEFINED, wf_impl_json_type(wf_impl_json_object_value(doc.root(), 1)));
|
||||
}
|
||||
|
||||
TEST(json_node, default_values)
|
||||
{
|
||||
JsonDoc doc("null");
|
||||
|
||||
ASSERT_EQ (false, wf_impl_json_bool_get(doc.root()));
|
||||
ASSERT_EQ (0 , wf_impl_json_int_get(doc.root()));
|
||||
ASSERT_STREQ("" , wf_impl_json_string_get(doc.root()));
|
||||
|
||||
ASSERT_EQ (0 , wf_impl_json_array_size(doc.root()));
|
||||
ASSERT_EQ (WF_JSON_TYPE_UNDEFINED, wf_impl_json_type(wf_impl_json_array_get(doc.root(), 0)));
|
||||
|
||||
ASSERT_EQ (0 , wf_impl_json_object_size(doc.root()));
|
||||
ASSERT_STREQ("" , wf_impl_json_object_key(doc.root(), 0));
|
||||
ASSERT_EQ (WF_JSON_TYPE_UNDEFINED, wf_impl_json_type(wf_impl_json_object_get(doc.root(), 0)));
|
||||
ASSERT_EQ (WF_JSON_TYPE_UNDEFINED, wf_impl_json_type(wf_impl_json_object_value(doc.root(), 0)));
|
||||
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
#include "webfuse/impl/json/parser.h"
|
||||
#include "webfuse/impl/json/reader.h"
|
||||
#include "webfuse/impl/json/node_intern.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <string>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool try_parse(std::string const & value)
|
||||
{
|
||||
std::string contents = value;
|
||||
struct wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, const_cast<char*>(contents.data()), contents.size());
|
||||
wf_json json;
|
||||
|
||||
bool const result = wf_impl_json_parse_value(&reader, &json);
|
||||
if (result)
|
||||
{
|
||||
wf_impl_json_cleanup(&json);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
TEST(json_parser, fail_no_contents)
|
||||
{
|
||||
ASSERT_FALSE(try_parse(""));
|
||||
}
|
||||
|
||||
TEST(json_parser, fail_invalid_null)
|
||||
{
|
||||
ASSERT_FALSE(try_parse("none"));
|
||||
}
|
||||
|
||||
TEST(json_parser, fail_invalid_true)
|
||||
{
|
||||
ASSERT_FALSE(try_parse("tru"));
|
||||
}
|
||||
|
||||
TEST(json_parser, fail_invalid_false)
|
||||
{
|
||||
ASSERT_FALSE(try_parse("fals"));
|
||||
}
|
||||
|
||||
TEST(json_parser, fail_invalid_int)
|
||||
{
|
||||
ASSERT_FALSE(try_parse("-"));
|
||||
}
|
||||
|
||||
TEST(json_parser, fail_invalid_string)
|
||||
{
|
||||
ASSERT_FALSE(try_parse("\"invalid"));
|
||||
}
|
||||
|
||||
TEST(json_parser, empty_array)
|
||||
{
|
||||
ASSERT_TRUE(try_parse("[]"));
|
||||
}
|
||||
|
||||
TEST(json_parser, large_array)
|
||||
{
|
||||
ASSERT_TRUE(try_parse("[1,2,3,4,5,6,7,8,9]"));
|
||||
}
|
||||
|
||||
TEST(json_parser, fail_unterminated_array)
|
||||
{
|
||||
ASSERT_FALSE(try_parse("[1"));
|
||||
}
|
||||
|
||||
TEST(json_parser, fail_missing_array_separator)
|
||||
{
|
||||
ASSERT_FALSE(try_parse("[1 2]"));
|
||||
}
|
||||
|
||||
TEST(json_parser, fail_missing_array_value)
|
||||
{
|
||||
ASSERT_FALSE(try_parse("[1,]"));
|
||||
}
|
||||
|
||||
TEST(json_parser, empty_object)
|
||||
{
|
||||
ASSERT_TRUE(try_parse("{}"));
|
||||
}
|
||||
|
||||
TEST(json_parser, large_object)
|
||||
{
|
||||
ASSERT_TRUE(try_parse("{\"a\":1,\"b\":2,\"c\":3,\"d\":4,\"e\":5}"));
|
||||
}
|
||||
|
||||
TEST(json_parser, fail_unterminated_object)
|
||||
{
|
||||
ASSERT_FALSE(try_parse("{\"a\":1"));
|
||||
}
|
||||
|
||||
TEST(json_parser, fail_invalid_object_key)
|
||||
{
|
||||
ASSERT_FALSE(try_parse("{a:1}"));
|
||||
}
|
||||
|
||||
TEST(json_parser, fail_missing_object_terminator)
|
||||
{
|
||||
ASSERT_FALSE(try_parse("{\"a\"1}"));
|
||||
}
|
||||
|
||||
TEST(json_parser, fail_missing_object_value)
|
||||
{
|
||||
ASSERT_FALSE(try_parse("{\"a\":}"));
|
||||
}
|
||||
|
||||
TEST(json_parser, fail_missing_object_separator)
|
||||
{
|
||||
ASSERT_FALSE(try_parse("{\"a\":1 \"b\":2}"));
|
||||
}
|
||||
|
||||
TEST(json_parser, fail_missing_object_item)
|
||||
{
|
||||
ASSERT_FALSE(try_parse("{\"a\":1,}"));
|
||||
}
|
@ -0,0 +1,214 @@
|
||||
#include "webfuse/impl/json/reader.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include <climits>
|
||||
|
||||
TEST(json_reader, skip_whitespace)
|
||||
{
|
||||
char text[] = " \t\r\n*";
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, text, 5);
|
||||
char c = wf_impl_json_reader_skip_whitespace(&reader);
|
||||
ASSERT_EQ('*', c);
|
||||
ASSERT_STREQ("*", &reader.contents[reader.pos]);
|
||||
}
|
||||
|
||||
TEST(json_reader, skip_whitespace_eof)
|
||||
{
|
||||
char text[] = " ";
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, text, 1);
|
||||
char c = wf_impl_json_reader_skip_whitespace(&reader);
|
||||
ASSERT_EQ('\0', c);
|
||||
}
|
||||
|
||||
TEST(json_reader, peek)
|
||||
{
|
||||
char text[] = "*";
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, text, 1);
|
||||
char c = wf_impl_json_reader_peek(&reader);
|
||||
ASSERT_EQ('*', c);
|
||||
}
|
||||
|
||||
TEST(json_reader, peek_eof)
|
||||
{
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, nullptr, 0);
|
||||
char c = wf_impl_json_reader_peek(&reader);
|
||||
ASSERT_EQ('\0', c);
|
||||
}
|
||||
|
||||
TEST(json_reader, get_char)
|
||||
{
|
||||
char text[] = "*";
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, text, 1);
|
||||
ASSERT_EQ('*', wf_impl_json_reader_get_char(&reader));
|
||||
ASSERT_EQ('\0', wf_impl_json_reader_get_char(&reader));
|
||||
ASSERT_EQ('\0', wf_impl_json_reader_get_char(&reader));
|
||||
}
|
||||
|
||||
TEST(json_reader, unget_char)
|
||||
{
|
||||
char text[] = "*";
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, text, 1);
|
||||
|
||||
ASSERT_EQ('*', wf_impl_json_reader_get_char(&reader));
|
||||
wf_impl_json_reader_unget_char(&reader);
|
||||
ASSERT_EQ('*', wf_impl_json_reader_get_char(&reader));
|
||||
|
||||
wf_impl_json_reader_unget_char(&reader);
|
||||
wf_impl_json_reader_unget_char(&reader);
|
||||
ASSERT_EQ('*', wf_impl_json_reader_get_char(&reader));
|
||||
}
|
||||
|
||||
TEST(json_reader, read_const)
|
||||
{
|
||||
char text[] = "value";
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, text, 5);
|
||||
|
||||
ASSERT_TRUE(wf_impl_json_reader_read_const(&reader, "value", 5));
|
||||
}
|
||||
|
||||
TEST(json_reader, read_const_fail_out_of_bounds)
|
||||
{
|
||||
char text[] = "value";
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, text, 2);
|
||||
|
||||
ASSERT_FALSE(wf_impl_json_reader_read_const(&reader, "value", 5));
|
||||
}
|
||||
|
||||
TEST(json_reader, read_const_fail_no_match)
|
||||
{
|
||||
char text[] = "hello";
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, text, 5);
|
||||
|
||||
ASSERT_FALSE(wf_impl_json_reader_read_const(&reader, "value", 5));
|
||||
}
|
||||
|
||||
TEST(json_reader, read_positive_int)
|
||||
{
|
||||
char text[] = "42";
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, text, 5);
|
||||
|
||||
int value;
|
||||
ASSERT_TRUE(wf_impl_json_reader_read_int(&reader, &value));
|
||||
ASSERT_EQ(42, value);
|
||||
}
|
||||
|
||||
TEST(json_reader, read_negative_int)
|
||||
{
|
||||
char text[] = "-1234";
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, text, 5);
|
||||
|
||||
int value;
|
||||
ASSERT_TRUE(wf_impl_json_reader_read_int(&reader, &value));
|
||||
ASSERT_EQ(-1234, value);
|
||||
}
|
||||
|
||||
TEST(json_reader, read_int_max)
|
||||
{
|
||||
std::string text = std::to_string(INT_MAX);
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, const_cast<char*>(text.data()), text.size());
|
||||
|
||||
int value;
|
||||
ASSERT_TRUE(wf_impl_json_reader_read_int(&reader, &value));
|
||||
ASSERT_EQ(INT_MAX, value);
|
||||
}
|
||||
|
||||
TEST(json_reader, read_int_min)
|
||||
{
|
||||
std::string text = std::to_string(INT_MIN);
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, const_cast<char*>(text.data()), text.size());
|
||||
|
||||
int value;
|
||||
ASSERT_TRUE(wf_impl_json_reader_read_int(&reader, &value));
|
||||
ASSERT_EQ(INT_MIN, value);
|
||||
}
|
||||
|
||||
TEST(json_reader, read_int_fail_invalid)
|
||||
{
|
||||
std::string text = "brummni";
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, const_cast<char*>(text.data()), text.size());
|
||||
|
||||
int value;
|
||||
ASSERT_FALSE(wf_impl_json_reader_read_int(&reader, &value));
|
||||
}
|
||||
|
||||
TEST(json_reader, read_int_fail_sign_only)
|
||||
{
|
||||
std::string text = "-";
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, const_cast<char*>(text.data()), text.size());
|
||||
|
||||
int value;
|
||||
ASSERT_FALSE(wf_impl_json_reader_read_int(&reader, &value));
|
||||
}
|
||||
|
||||
TEST(json_reader, read_string)
|
||||
{
|
||||
std::string text = "\"brummni\"";
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, const_cast<char*>(text.data()), text.size());
|
||||
|
||||
char * value;
|
||||
size_t size;
|
||||
ASSERT_TRUE(wf_impl_json_reader_read_string(&reader, &value, &size));
|
||||
ASSERT_STREQ("brummni", value);
|
||||
ASSERT_EQ(7, size);
|
||||
}
|
||||
|
||||
TEST(json_reader, read_string_escaped)
|
||||
{
|
||||
std::string text = "\"_\\\"_\\\\_\\/_\\b_\\f_\\n_\\r_\\t_\"";
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, const_cast<char*>(text.data()), text.size());
|
||||
|
||||
char * value;
|
||||
size_t size;
|
||||
ASSERT_TRUE(wf_impl_json_reader_read_string(&reader, &value, &size));
|
||||
ASSERT_STREQ("_\"_\\_/_\b_\f_\n_\r_\t_", value);
|
||||
ASSERT_EQ(17, size);
|
||||
}
|
||||
|
||||
TEST(json_reader, read_string_fail_missig_start_quot)
|
||||
{
|
||||
std::string text = "brummni\"";
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, const_cast<char*>(text.data()), text.size());
|
||||
|
||||
char * value;
|
||||
size_t size;
|
||||
ASSERT_FALSE(wf_impl_json_reader_read_string(&reader, &value, &size));
|
||||
}
|
||||
|
||||
TEST(json_reader, read_string_fail_missig_end_quot)
|
||||
{
|
||||
std::string text = "\"brummni";
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, const_cast<char*>(text.data()), text.size());
|
||||
|
||||
char * value;
|
||||
size_t size;
|
||||
ASSERT_FALSE(wf_impl_json_reader_read_string(&reader, &value, &size));
|
||||
}
|
||||
|
||||
TEST(json_reader, read_string_fail_invalid_escape_seq)
|
||||
{
|
||||
std::string text = "\"\\i\"";
|
||||
wf_json_reader reader;
|
||||
wf_impl_json_reader_init(&reader, const_cast<char*>(text.data()), text.size());
|
||||
|
||||
char * value;
|
||||
size_t size;
|
||||
ASSERT_FALSE(wf_impl_json_reader_read_string(&reader, &value, &size));
|
||||
}
|
@ -1,147 +1,123 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "webfuse/impl/jsonrpc/response_intern.h"
|
||||
#include "webfuse/impl/jsonrpc/error.h"
|
||||
#include "webfuse/impl/json/node.h"
|
||||
#include "webfuse/status.h"
|
||||
#include "webfuse/test_util/json_doc.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using webfuse_test::JsonDoc;
|
||||
|
||||
TEST(wf_json_response, init_result)
|
||||
{
|
||||
json_t * message = json_object();
|
||||
json_object_set_new(message, "result", json_integer(47));
|
||||
json_object_set_new(message, "id", json_integer(11));
|
||||
JsonDoc doc("{\"result\": 47, \"id\": 11}");
|
||||
|
||||
struct wf_jsonrpc_response response;
|
||||
wf_impl_jsonrpc_response_init(&response, message);
|
||||
wf_impl_jsonrpc_response_init(&response, doc.root());
|
||||
|
||||
ASSERT_EQ(nullptr, response.error);
|
||||
ASSERT_TRUE(json_is_integer(response.result));
|
||||
ASSERT_EQ(47, json_integer_value(response.result));
|
||||
ASSERT_TRUE(wf_impl_json_is_int(response.result));
|
||||
ASSERT_EQ(47, wf_impl_json_int_get(response.result));
|
||||
ASSERT_EQ(11, response.id);
|
||||
|
||||
wf_impl_jsonrpc_response_cleanup(&response);
|
||||
json_decref(message);
|
||||
}
|
||||
|
||||
TEST(wf_json_response, init_error)
|
||||
{
|
||||
json_t * message = json_object();
|
||||
json_t * err = json_object();
|
||||
json_object_set_new(err, "code", json_integer(42));
|
||||
json_object_set_new(err, "message", json_string("Don't Panic!"));
|
||||
json_object_set_new(message, "error", err);
|
||||
json_object_set_new(message, "id", json_integer(23));
|
||||
JsonDoc doc("{\"error\": {\"code\": 42, \"message\": \"Don't Panic!\"}, \"id\": 23}");
|
||||
|
||||
struct wf_jsonrpc_response response;
|
||||
wf_impl_jsonrpc_response_init(&response, message);
|
||||
wf_impl_jsonrpc_response_init(&response, doc.root());
|
||||
|
||||
ASSERT_EQ(42, json_integer_value(json_object_get(response.error, "code")));
|
||||
ASSERT_STREQ("Don't Panic!", json_string_value(json_object_get(response.error, "message")));
|
||||
ASSERT_EQ(42, wf_impl_jsonrpc_error_code(response.error));
|
||||
ASSERT_STREQ("Don't Panic!", wf_impl_jsonrpc_error_message(response.error));
|
||||
ASSERT_EQ(nullptr, response.result);
|
||||
ASSERT_EQ(23, response.id);
|
||||
|
||||
wf_impl_jsonrpc_response_cleanup(&response);
|
||||
json_decref(message);
|
||||
}
|
||||
|
||||
TEST(wf_json_response, init_fail_missing_result_and_error)
|
||||
{
|
||||
json_t * message = json_object();
|
||||
json_object_set_new(message, "id", json_integer(12));
|
||||
JsonDoc doc("{\"id\": 12}");
|
||||
|
||||
struct wf_jsonrpc_response response;
|
||||
wf_impl_jsonrpc_response_init(&response, message);
|
||||
wf_impl_jsonrpc_response_init(&response, doc.root());
|
||||
|
||||
ASSERT_EQ(WF_BAD_FORMAT, json_integer_value(json_object_get(response.error, "code")));
|
||||
ASSERT_EQ(WF_BAD_FORMAT, wf_impl_jsonrpc_error_code(response.error));
|
||||
ASSERT_EQ(nullptr, response.result);
|
||||
ASSERT_EQ(12, response.id);
|
||||
|
||||
wf_impl_jsonrpc_response_cleanup(&response);
|
||||
json_decref(message);
|
||||
}
|
||||
|
||||
TEST(wf_json_response, init_fail_missing_id)
|
||||
{
|
||||
json_t * message = json_object();
|
||||
json_object_set_new(message, "result", json_integer(47));
|
||||
JsonDoc doc("{\"result\": 47}");
|
||||
|
||||
struct wf_jsonrpc_response response;
|
||||
wf_impl_jsonrpc_response_init(&response, message);
|
||||
wf_impl_jsonrpc_response_init(&response, doc.root());
|
||||
|
||||
ASSERT_EQ(WF_BAD_FORMAT, json_integer_value(json_object_get(response.error, "code")));
|
||||
ASSERT_EQ(WF_BAD_FORMAT, wf_impl_jsonrpc_error_code(response.error));
|
||||
ASSERT_EQ(nullptr, response.result);
|
||||
ASSERT_EQ(-1, response.id);
|
||||
|
||||
wf_impl_jsonrpc_response_cleanup(&response);
|
||||
json_decref(message);
|
||||
}
|
||||
|
||||
TEST(wf_json_response, init_fail_wrong_id_type)
|
||||
{
|
||||
json_t * message = json_object();
|
||||
json_object_set_new(message, "result", json_integer(47));
|
||||
json_object_set_new(message, "id", json_string("42"));
|
||||
JsonDoc doc("{\"result\": 47, \"id\": \"42\"}");
|
||||
|
||||
struct wf_jsonrpc_response response;
|
||||
wf_impl_jsonrpc_response_init(&response, message);
|
||||
wf_impl_jsonrpc_response_init(&response, doc.root());
|
||||
|
||||
ASSERT_EQ(WF_BAD_FORMAT, json_integer_value(json_object_get(response.error, "code")));
|
||||
ASSERT_EQ(WF_BAD_FORMAT, wf_impl_jsonrpc_error_code(response.error));
|
||||
ASSERT_EQ(nullptr, response.result);
|
||||
ASSERT_EQ(-1, response.id);
|
||||
|
||||
wf_impl_jsonrpc_response_cleanup(&response);
|
||||
json_decref(message);
|
||||
}
|
||||
|
||||
TEST(wf_json_response, init_fail_error_missing_code)
|
||||
{
|
||||
json_t * message = json_object();
|
||||
json_t * err = json_object();
|
||||
json_object_set_new(err, "message", json_string("Don't Panic!"));
|
||||
json_object_set_new(message, "error", err);
|
||||
json_object_set_new(message, "id", json_integer(23));
|
||||
JsonDoc doc("{\"error\": {\"message\": \"Don't Panic!\"}, \"id\": 23}");
|
||||
|
||||
struct wf_jsonrpc_response response;
|
||||
wf_impl_jsonrpc_response_init(&response, message);
|
||||
wf_impl_jsonrpc_response_init(&response, doc.root());
|
||||
|
||||
ASSERT_EQ(WF_BAD_FORMAT, json_integer_value(json_object_get(response.error, "code")));
|
||||
ASSERT_EQ(WF_BAD_FORMAT, wf_impl_jsonrpc_error_code(response.error));
|
||||
ASSERT_EQ(nullptr, response.result);
|
||||
ASSERT_EQ(23, response.id);
|
||||
|
||||
wf_impl_jsonrpc_response_cleanup(&response);
|
||||
json_decref(message);
|
||||
}
|
||||
|
||||
TEST(wf_json_response, init_fail_error_wrong_code_type)
|
||||
{
|
||||
json_t * message = json_object();
|
||||
json_t * err = json_object();
|
||||
json_object_set_new(err, "code", json_string("42"));
|
||||
json_object_set_new(err, "message", json_string("Don't Panic!"));
|
||||
json_object_set_new(message, "error", err);
|
||||
json_object_set_new(message, "id", json_integer(23));
|
||||
JsonDoc doc("{\"error\": {\"code\": \"42\", \"message\": \"Don't Panic!\"}, \"id\": 23}");
|
||||
|
||||
struct wf_jsonrpc_response response;
|
||||
wf_impl_jsonrpc_response_init(&response, message);
|
||||
wf_impl_jsonrpc_response_init(&response, doc.root());
|
||||
|
||||
ASSERT_EQ(WF_BAD_FORMAT, json_integer_value(json_object_get(response.error, "code")));
|
||||
ASSERT_EQ(WF_BAD_FORMAT, wf_impl_jsonrpc_error_code(response.error));
|
||||
ASSERT_EQ(nullptr, response.result);
|
||||
ASSERT_EQ(23, response.id);
|
||||
|
||||
wf_impl_jsonrpc_response_cleanup(&response);
|
||||
json_decref(message);
|
||||
}
|
||||
|
||||
TEST(wf_json_response, init_fail_error_wrong_type)
|
||||
{
|
||||
json_t * message = json_object();
|
||||
json_object_set_new(message, "error", json_string("invalid error type"));
|
||||
json_object_set_new(message, "id", json_integer(23));
|
||||
JsonDoc doc("{\"error\": \"invalid error type\", \"id\": 23}");
|
||||
|
||||
struct wf_jsonrpc_response response;
|
||||
wf_impl_jsonrpc_response_init(&response, message);
|
||||
wf_impl_jsonrpc_response_init(&response, doc.root());
|
||||
|
||||
ASSERT_EQ(WF_BAD_FORMAT, json_integer_value(json_object_get(response.error, "code")));
|
||||
ASSERT_EQ(WF_BAD_FORMAT, wf_impl_jsonrpc_error_code(response.error));
|
||||
ASSERT_EQ(nullptr, response.result);
|
||||
ASSERT_EQ(23, response.id);
|
||||
|
||||
wf_impl_jsonrpc_response_cleanup(&response);
|
||||
json_decref(message);
|
||||
}
|
||||
|
@ -1,22 +1,22 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <cstring>
|
||||
#include "webfuse/impl/message.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <libwebsockets.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(wf_message, create)
|
||||
{
|
||||
json_t * value = json_object();
|
||||
char * data = (char*) malloc(LWS_PRE + 2);
|
||||
data[LWS_PRE ] = '{';
|
||||
data[LWS_PRE + 1] = '}';
|
||||
|
||||
struct wf_message * message = wf_impl_message_create(value);
|
||||
struct wf_message * message = wf_impl_message_create(&(data[LWS_PRE]), 2);
|
||||
ASSERT_NE(nullptr, message);
|
||||
ASSERT_EQ(2, message->length);
|
||||
ASSERT_TRUE(0 == strncmp("{}", message->data, 2));
|
||||
|
||||
wf_impl_message_dispose(message);
|
||||
json_decref(value);
|
||||
}
|
||||
|
||||
TEST(wf_message, fail_to_create)
|
||||
{
|
||||
struct wf_message * message = wf_impl_message_create(nullptr);
|
||||
ASSERT_EQ(nullptr, message);
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <jansson.h>
|
||||
|
||||
namespace webfuse_test
|
||||
{
|
||||
|
||||
class JanssonTestEnvironment: public ::testing::Environment
|
||||
{
|
||||
public:
|
||||
~JanssonTestEnvironment() override { }
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
json_object_seed(0);
|
||||
}
|
||||
};
|
||||
|
||||
::testing::Environment * const jansson_env = ::testing::AddGlobalTestEnvironment(new JanssonTestEnvironment());
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
#include "webfuse/test_util/json_doc.hpp"
|
||||
|
||||
namespace webfuse_test
|
||||
{
|
||||
|
||||
JsonDoc::JsonDoc(std::string const & text)
|
||||
: contents(text)
|
||||
{
|
||||
doc = wf_impl_json_doc_loadb(const_cast<char*>(contents.data()), contents.size());
|
||||
}
|
||||
|
||||
JsonDoc::JsonDoc(JsonDoc && other)
|
||||
{
|
||||
contents = std::move(other.contents);
|
||||
doc = other.doc;
|
||||
other.doc = nullptr;
|
||||
}
|
||||
|
||||
JsonDoc& JsonDoc::operator=(JsonDoc && other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
wf_impl_json_doc_dispose(doc);
|
||||
contents = std::move(other.contents);
|
||||
doc = other.doc;
|
||||
other.doc = nullptr;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
JsonDoc::~JsonDoc()
|
||||
{
|
||||
if (nullptr != doc)
|
||||
{
|
||||
wf_impl_json_doc_dispose(doc);
|
||||
}
|
||||
}
|
||||
|
||||
wf_json const * JsonDoc::root()
|
||||
{
|
||||
return wf_impl_json_doc_root(doc);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
#ifndef WF_TEST_UTIL_JSON_DOC_HPP
|
||||
#define WF_TEST_UTIL_JSON_DOC_HPP
|
||||
|
||||
#include "webfuse/impl/json/doc.h"
|
||||
#include <string>
|
||||
|
||||
namespace webfuse_test
|
||||
{
|
||||
|
||||
class JsonDoc
|
||||
{
|
||||
JsonDoc(JsonDoc const&) = delete;
|
||||
JsonDoc& operator=(JsonDoc const&) = delete;
|
||||
public:
|
||||
explicit JsonDoc(std::string const & text);
|
||||
JsonDoc(JsonDoc && other);
|
||||
JsonDoc& operator=(JsonDoc && other);
|
||||
~JsonDoc();
|
||||
wf_json const * root();
|
||||
private:
|
||||
std::string contents;
|
||||
wf_json_doc * doc;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in new issue