aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2018-05-12 18:03:13 +0200
committerDavid Robillard <d@drobilla.net>2018-05-27 18:23:15 +0200
commitf48dac14b6533b4cdd4804513216f4f11de36d9a (patch)
treea26996f7344bf67890b3004649522023b7cccfe4
parentcc1378913b22737fc1abb81de15313099d005eae (diff)
downloadserd-f48dac14b6533b4cdd4804513216f4f11de36d9a.tar.gz
serd-f48dac14b6533b4cdd4804513216f4f11de36d9a.tar.bz2
serd-f48dac14b6533b4cdd4804513216f4f11de36d9a.zip
Set datatypes on integer, decimal, and base64 nodes
-rw-r--r--serd/serd.h24
-rw-r--r--src/node.c99
-rw-r--r--tests/serd_test.c20
3 files changed, 110 insertions, 33 deletions
diff --git a/serd/serd.h b/serd/serd.h
index c765f8dd..f148acb4 100644
--- a/serd/serd.h
+++ b/serd/serd.h
@@ -554,18 +554,27 @@ serd_node_new_relative_uri(const char* str,
represent a double and float, respectively.
@param d The value for the new node.
+
@param frac_digits The maximum number of digits after the decimal place.
+
+ @param datatype Datatype of node, may be NULL in which case the node has
+ type xsd:decimal.
*/
SERD_API
SerdNode*
-serd_node_new_decimal(double d, unsigned frac_digits);
+serd_node_new_decimal(double d, unsigned frac_digits, const SerdNode* datatype);
/**
Create a new node by serialising `i` into an xsd:integer string.
+
+ @param i Integer value to serialise.
+
+ @param datatype Datatype of node, may be NULL in which case the node has
+ type xsd:integer.
*/
SERD_API
SerdNode*
-serd_node_new_integer(int64_t i);
+serd_node_new_integer(int64_t i, const SerdNode* datatype);
/**
Create a node by serialising `buf` into an xsd:base64Binary string.
@@ -573,12 +582,19 @@ serd_node_new_integer(int64_t i);
binary data, which can be decoded using serd_base64_decode().
@param buf Raw binary input data.
+
@param size Size of `buf`.
+
@param wrap_lines Wrap lines at 76 characters to conform to RFC 2045.
+
+ @param datatype Datatype of node, may be NULL in which case the node has
+ type xsd:base64Binary.
*/
SERD_API
-SerdNode*
-serd_node_new_blob(const void* buf, size_t size, bool wrap_lines);
+SerdNode* serd_node_new_blob(const void* buf,
+ size_t size,
+ bool wrap_lines,
+ const SerdNode* datatype);
/**
Return the type of a node (SERD_URI, SERD_BLANK, or SERD_LITERAL).
diff --git a/src/node.c b/src/node.c
index 36c2c8ca..523893df 100644
--- a/src/node.c
+++ b/src/node.c
@@ -39,6 +39,19 @@
static const size_t serd_node_align = sizeof(SerdNode);
+typedef struct StaticNode {
+ SerdNode node;
+ char buf[sizeof(NS_XSD) + sizeof("base64Binary") + 1];
+} StaticNode;
+
+#define DEFINE_XSD_NODE(name) \
+ static const StaticNode serd_xsd_ ## name = { \
+ { sizeof(NS_XSD #name), 0, SERD_URI }, NS_XSD #name };
+
+DEFINE_XSD_NODE(decimal)
+DEFINE_XSD_NODE(integer)
+DEFINE_XSD_NODE(base64Binary)
+
static SerdNode*
serd_node_new_from_uri(const SerdURI* uri, const SerdURI* base);
@@ -46,7 +59,29 @@ static size_t
serd_node_pad_size(const size_t n_bytes)
{
const size_t pad = serd_node_align - (n_bytes + 2) % serd_node_align;
- return n_bytes + 2 + pad;
+ const size_t size = n_bytes + 2 + pad;
+ assert(size % serd_node_align == 0);
+ return size;
+}
+
+static const SerdNode*
+serd_node_get_meta_c(const SerdNode* node)
+{
+ return node + 1 + (serd_node_pad_size(node->n_bytes) / serd_node_align);
+}
+
+static const SerdNode*
+serd_node_maybe_get_meta_c(const SerdNode* node)
+{
+ return (node->flags & (SERD_HAS_LANGUAGE | SERD_HAS_DATATYPE))
+ ? (node + 1 + (serd_node_pad_size(node->n_bytes) / serd_node_align))
+ : NULL;
+}
+
+static SerdNode*
+serd_node_get_meta(SerdNode* node)
+{
+ return node + 1 + (serd_node_pad_size(node->n_bytes) / serd_node_align);
}
size_t
@@ -391,21 +426,26 @@ serd_digits(double abs)
}
SerdNode*
-serd_node_new_decimal(double d, unsigned frac_digits)
+serd_node_new_decimal(double d, unsigned frac_digits, const SerdNode* datatype)
{
if (isnan(d) || isinf(d)) {
return NULL;
}
+ const SerdNode* type = datatype ? datatype : &serd_xsd_decimal.node;
const double abs_d = fabs(d);
const unsigned int_digits = serd_digits(abs_d);
const size_t len = int_digits + frac_digits + 3;
- SerdNode* const node = serd_node_malloc(len, 0, SERD_LITERAL);
- char* const buf = serd_node_buffer(node);
- const double int_part = floor(abs_d);
+ const size_t type_len = serd_node_total_size(type);
+ const size_t total_len = len + type_len;
+
+ SerdNode* const node =
+ serd_node_malloc(total_len, SERD_HAS_DATATYPE, SERD_LITERAL);
// Point s to decimal point location
- char* s = buf + int_digits;
+ char* const buf = serd_node_buffer(node);
+ const double int_part = floor(abs_d);
+ char* s = buf + int_digits;
if (d < 0.0) {
*buf = '-';
++s;
@@ -443,19 +483,25 @@ serd_node_new_decimal(double d, unsigned frac_digits)
}
}
+ memcpy(serd_node_get_meta(node), type, type_len);
return node;
}
SerdNode*
-serd_node_new_integer(int64_t i)
+serd_node_new_integer(int64_t i, const SerdNode* datatype)
{
- int64_t abs_i = (i < 0) ? -i : i;
- const unsigned digits = serd_digits(abs_i);
- SerdNode* node = serd_node_malloc(digits + 2, 0, SERD_LITERAL);
- char* buf = serd_node_buffer(node);
+ const SerdNode* type = datatype ? datatype : &serd_xsd_integer.node;
+ int64_t abs_i = (i < 0) ? -i : i;
+ const unsigned digits = serd_digits(abs_i);
+ const size_t type_len = serd_node_total_size(type);
+ const size_t total_len = digits + 2 + type_len;
+
+ SerdNode* node =
+ serd_node_malloc(total_len, SERD_HAS_DATATYPE, SERD_LITERAL);
// Point s to the end
- char* s = buf + digits - 1;
+ char* buf = serd_node_buffer(node);
+ char* s = buf + digits - 1;
if (i < 0) {
*buf = '-';
++s;
@@ -468,20 +514,30 @@ serd_node_new_integer(int64_t i)
*s-- = '0' + (abs_i % 10);
} while ((abs_i /= 10) > 0);
+ memcpy(serd_node_get_meta(node), type, type_len);
return node;
}
SerdNode*
-serd_node_new_blob(const void* buf, size_t size, bool wrap_lines)
+serd_node_new_blob(const void* buf,
+ size_t size,
+ bool wrap_lines,
+ const SerdNode* datatype)
{
- const size_t len = serd_base64_get_length(size, wrap_lines);
- SerdNode* const node = serd_node_malloc(len + 1, 0, SERD_LITERAL);
+ const SerdNode* type = datatype ? datatype : &serd_xsd_base64Binary.node;
+ const size_t len = serd_base64_get_length(size, wrap_lines);
+ const size_t type_len = serd_node_total_size(type);
+ const size_t total_len = len + 1 + type_len;
+
+ SerdNode* const node =
+ serd_node_malloc(total_len, SERD_HAS_DATATYPE, SERD_LITERAL);
if (serd_base64_encode(serd_node_buffer(node), buf, size, wrap_lines)) {
node->flags |= SERD_HAS_NEWLINE;
}
node->n_bytes = len + 1;
+ memcpy(serd_node_get_meta(node), type, type_len);
return node;
}
@@ -503,15 +559,6 @@ serd_node_get_length(const SerdNode* node)
return node ? node->n_bytes : 0;
}
-static const SerdNode*
-serd_node_get_meta_node(const SerdNode* node)
-{
- const size_t len = serd_node_pad_size(node->n_bytes);
- assert((intptr_t)node % serd_node_align == 0);
- assert(len % serd_node_align == 0);
- return node + 1 + (len / serd_node_align);
-}
-
const SerdNode*
serd_node_get_datatype(const SerdNode* node)
{
@@ -519,7 +566,7 @@ serd_node_get_datatype(const SerdNode* node)
return NULL;
}
- const SerdNode* const datatype = serd_node_get_meta_node(node);
+ const SerdNode* const datatype = serd_node_get_meta_c(node);
assert(datatype->type == SERD_URI || datatype->type == SERD_CURIE);
return datatype;
}
@@ -531,7 +578,7 @@ serd_node_get_language(const SerdNode* node)
return NULL;
}
- const SerdNode* const lang = serd_node_get_meta_node(node);
+ const SerdNode* const lang = serd_node_get_meta_c(node);
assert(lang->type == SERD_LITERAL);
return lang;
}
diff --git a/tests/serd_test.c b/tests/serd_test.c
index e5037945..e63e9594 100644
--- a/tests/serd_test.c
+++ b/tests/serd_test.c
@@ -33,6 +33,8 @@
# define NAN (INFINITY - INFINITY)
#endif
+#define NS_XSD "http://www.w3.org/2001/XMLSchema#"
+
static int
test_strtod(double dbl, double max_delta)
{
@@ -172,7 +174,7 @@ main(void)
};
for (unsigned i = 0; i < sizeof(dbl_test_nums) / sizeof(double); ++i) {
- SerdNode* node = serd_node_new_decimal(dbl_test_nums[i], 8);
+ SerdNode* node = serd_node_new_decimal(dbl_test_nums[i], 8, NULL);
const char* node_str = serd_node_get_string(node);
const bool pass = (node_str && dbl_test_strs[i])
? !strcmp(node_str, dbl_test_strs[i])
@@ -183,6 +185,10 @@ main(void)
const size_t len = node_str ? strlen(node_str) : 0;
if (serd_node_get_length(node) != len) {
FAILF("Length %zu != %zu\n", serd_node_get_length(node), len);
+ } else if (dbl_test_strs[i] &&
+ strcmp(serd_node_get_string(serd_node_get_datatype(node)),
+ NS_XSD "decimal")) {
+ FAIL("Decimal node has incorrect default datatype\n");
}
serd_node_free(node);
}
@@ -198,7 +204,7 @@ main(void)
};
for (unsigned i = 0; i < sizeof(int_test_nums) / sizeof(double); ++i) {
- SerdNode* node = serd_node_new_integer(int_test_nums[i]);
+ SerdNode* node = serd_node_new_integer(int_test_nums[i], NULL);
const char* node_str = serd_node_get_string(node);
if (strcmp(node_str, (const char*)int_test_strs[i])) {
FAILF("Serialised `%s' != %s\n", node_str, int_test_strs[i]);
@@ -206,6 +212,9 @@ main(void)
const size_t len = strlen(node_str);
if (serd_node_get_length(node) != len) {
FAILF("Length %zu,%zu != %zu\n", serd_node_get_length(node), len);
+ } else if (strcmp(serd_node_get_string(serd_node_get_datatype(node)),
+ NS_XSD "integer")) {
+ FAIL("Integer node has incorrect default datatype\n");
}
serd_node_free(node);
}
@@ -218,7 +227,7 @@ main(void)
}
size_t out_size;
- SerdNode* blob = serd_node_new_blob(data, size, size % 5);
+ SerdNode* blob = serd_node_new_blob(data, size, size % 5, NULL);
const char* blob_str = serd_node_get_string(blob);
uint8_t* out = (uint8_t*)serd_base64_decode(
blob_str, serd_node_get_length(blob), &out_size);
@@ -232,6 +241,11 @@ main(void)
}
}
+ if (strcmp(serd_node_get_string(serd_node_get_datatype(blob)),
+ NS_XSD "base64Binary")) {
+ FAIL("Blob node has incorrect default datatype\n");
+ }
+
serd_node_free(blob);
free(out);
free(data);