summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--README40
-rw-r--r--include/nsutils/assert.h24
-rw-r--r--include/nsutils/base64.h73
-rw-r--r--include/nsutils/endian.h71
-rw-r--r--include/nsutils/time.h2
-rw-r--r--include/nsutils/unistd.h2
-rw-r--r--src/base64.c315
-rw-r--r--src/time.c4
-rw-r--r--src/unistd.c4
-rw-r--r--test/base64.c84
-rwxr-xr-xtest/runtest.sh64
12 files changed, 610 insertions, 79 deletions
diff --git a/Makefile b/Makefile
index 51c251d..e275537 100644
--- a/Makefile
+++ b/Makefile
@@ -2,11 +2,11 @@
#
# Makefile for libnsutils
#
-# Copyright 2014-1015 Vincent Sanders <vince@netsurf-browser.org>
+# Copyright 2014-2020 Vincent Sanders <vince@netsurf-browser.org>
# Component settings
COMPONENT := nsutils
-COMPONENT_VERSION := 0.0.3
+COMPONENT_VERSION := 0.1.1
# Default to a static library
COMPONENT_TYPE ?= lib-static
@@ -49,8 +49,10 @@ include $(NSBUILD)/Makefile.top
# Extra installation rules
I := /$(INCLUDEDIR)/nsutils
+INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/nsutils/assert.h
INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/nsutils/errors.h
INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/nsutils/base64.h
+INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/nsutils/endian.h
INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/nsutils/time.h
INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/nsutils/unistd.h
INSTALL_ITEMS := $(INSTALL_ITEMS) /$(LIBDIR)/pkgconfig:lib$(COMPONENT).pc.in
diff --git a/README b/README
new file mode 100644
index 0000000..45e0a12
--- /dev/null
+++ b/README
@@ -0,0 +1,40 @@
+Libnsutils - NetSurf utility functions
+======================================
+
+Overview
+--------
+
+ Libnsutils provides a small number of useful utility routines which
+ require platform-specific implementations.
+
+Requirements
+------------
+
+ Libnsutils requires the following tools:
+
+ + A C99 capable C compiler
+ + GNU make or compatible
+ + Pkg-config
+
+Compilation
+-----------
+
+ If necessary, modify the toolchain settings in the Makefile.
+ Invoke make:
+ $ make
+
+Verification
+------------
+
+ To verify that the library is working, it is necessary to specify a
+ different makefile target than that used for normal compilation, thus:
+
+ $ make test
+
+API documentation
+-----------------
+
+ Currently, there is none. However, the code is well commented and the
+ public API may be found in the "include" directory. The testcase sources
+ may also be of use in working out how to use it.
+
diff --git a/include/nsutils/assert.h b/include/nsutils/assert.h
new file mode 100644
index 0000000..7f59f2f
--- /dev/null
+++ b/include/nsutils/assert.h
@@ -0,0 +1,24 @@
+/*
+ * This file is part of LibNSUtils.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2022 Michael Drake <tlsa@netsurf-browser.org>
+ */
+
+/**
+ * \file
+ * Static assertion macro.
+ */
+
+#ifndef NSUTILS_ASSERT_H__
+#define NSUTILS_ASSERT_H__
+
+/** Compile time assertion macro. */
+#define ns_static_assert(e) \
+{ \
+ enum { \
+ ns_static_assert_check = 1 / (!!(e)) \
+ }; \
+}
+
+#endif
diff --git a/include/nsutils/base64.h b/include/nsutils/base64.h
index 672b69c..fb26426 100644
--- a/include/nsutils/base64.h
+++ b/include/nsutils/base64.h
@@ -15,6 +15,8 @@
#ifndef NSUTILS_BASE64_H_
#define NSUTILS_BASE64_H_
+#include <inttypes.h>
+
#include <nsutils/errors.h>
/**
@@ -26,7 +28,7 @@
* \param input_length The length of the source data.
* \param output The buffer to recive data into, the caller must free.
* \param output_length The length of data placed in \a output
- * \return NSERROR_OK on success and \a output updated else error code.
+ * \return NSUERROR_OK on success and \a output updated else error code.
*/
nsuerror nsu_base64_encode_alloc(const uint8_t *input,
size_t input_length,
@@ -34,6 +36,56 @@ nsuerror nsu_base64_encode_alloc(const uint8_t *input,
size_t *output_length);
/**
+ * Base 64 encode data.
+ *
+ * encode source data into buffer it using the Base64 encoding.
+ *
+ * \param input The source data to encode.
+ * \param input_length The length of the source data.
+ * \param output The output buffer
+ * \param output_length The size of the \a output buffer on entry updated with length written on exit.
+ * \return NSUERROR_OK on success and \a output_length updated else error code.
+ */
+nsuerror nsu_base64_encode(const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t *output_length);
+
+/**
+ * Base 64 encode data.
+ *
+ * allocate a buffer and encode source data into it using the base64 URL safe
+ * encoding.
+ *
+ * \param input The source data to encode.
+ * \param input_length The length of the source data.
+ * \param output The buffer to recive data into, the caller must free.
+ * \param output_length The length of data placed in \a output
+ * \return NSERROR_OK on success and \a output updated else error code.
+ */
+nsuerror nsu_base64_encode_alloc_url(const uint8_t *input,
+ size_t input_length,
+ uint8_t **output,
+ size_t *output_length);
+
+
+/**
+ * Base 64 encode data.
+ *
+ * encode source data into buffer using the Base64 URL safe encoding.
+ *
+ * \param input The source data to encode.
+ * \param input_length The length of the source data.
+ * \param output The output buffer
+ * \param output_length The size of the \a output buffer on entry updated with length written on exit.
+ * \return NSUERROR_OK on success and \a output_length updated else error code.
+ */
+nsuerror nsu_base64_encode_url(const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t *output_length);
+
+/**
* Base 64 decode data.
*
* allocate a buffer and decode source data into it using the Base64 encoding.
@@ -48,5 +100,22 @@ nsuerror nsu_base64_decode_alloc(const uint8_t *input,
size_t input_length,
uint8_t **output,
size_t *output_length);
-
+
+/**
+ * Base 64 decode data.
+ *
+ * Allocate a buffer and decode source data into it using the Base64 URL safe
+ * encoding.
+ *
+ * \param input The source data to decode.
+ * \param input_length The length of the source data.
+ * \param output The buffer to recive data into, the caller must free.
+ * \param output_length The length of data placed in \a output
+ * \return NSERROR_OK on success and \a output updated else error code.
+ */
+nsuerror nsu_base64_decode_alloc_url(const uint8_t *input,
+ size_t input_length,
+ uint8_t **output,
+ size_t *output_length);
+
#endif
diff --git a/include/nsutils/endian.h b/include/nsutils/endian.h
new file mode 100644
index 0000000..a15c7e2
--- /dev/null
+++ b/include/nsutils/endian.h
@@ -0,0 +1,71 @@
+/*
+ * This file is part of LibNSUtils.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
+ */
+
+/**
+ * \file
+ * Endianness helper functions.
+ */
+
+#ifndef NSUTILS_ENDIAN_H__
+#define NSUTILS_ENDIAN_H__
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+/**
+ * Detect if the host is little endian.
+ *
+ * \return True if the host is little endian; false otherwise.
+ */
+static inline bool endian_host_is_le(void)
+{
+ const uint16_t test = 1;
+
+ return ((const uint8_t *) &test)[0];
+}
+
+/**
+ * Swap the endianness of a 32bit value.
+ *
+ * \param val Value to swap endianness of
+ * \return Endian-swapped value
+ */
+static inline uint32_t endian_swap(uint32_t val)
+{
+ return ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) |
+ ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24);
+}
+
+/**
+ * Convert a host-endian 32bit value to its big-endian equivalent.
+ *
+ * \param host Value to convert
+ * \return Big endian value
+ */
+static inline uint32_t endian_host_to_big(uint32_t host)
+{
+ if (endian_host_is_le())
+ return endian_swap(host);
+
+ return host;
+}
+
+/**
+ * Convert a big-endian 32bit value to its host-endian equivalent.
+ *
+ * \param host Value to convert
+ * \return Host endian value
+ */
+static inline uint32_t endian_big_to_host(uint32_t big)
+{
+ if (endian_host_is_le())
+ return endian_swap(big);
+
+ return big;
+}
+
+#endif
diff --git a/include/nsutils/time.h b/include/nsutils/time.h
index db60914..f162b75 100644
--- a/include/nsutils/time.h
+++ b/include/nsutils/time.h
@@ -15,6 +15,8 @@
#ifndef NSUTILS_TIME_H_
#define NSUTILS_TIME_H_
+#include <inttypes.h>
+
#include <nsutils/errors.h>
/**
diff --git a/include/nsutils/unistd.h b/include/nsutils/unistd.h
index be11382..06af226 100644
--- a/include/nsutils/unistd.h
+++ b/include/nsutils/unistd.h
@@ -15,6 +15,8 @@
#ifndef NSUTILS_UNISTD_H_
#define NSUTILS_UNISTD_H_
+#include <unistd.h>
+
/**
* Perform a write operation at a specific offset
*
diff --git a/src/base64.c b/src/base64.c
index c11364f..87752da 100644
--- a/src/base64.c
+++ b/src/base64.c
@@ -21,33 +21,126 @@
#include "nsutils/base64.h"
-static uint8_t decoding_table[256];
-static uint8_t encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
- 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
- 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
- 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
- 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
- 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
- 'w', 'x', 'y', 'z', '0', '1', '2', '3',
- '4', '5', '6', '7', '8', '9', '+', '/'};
+static const uint8_t b64_decoding_table[256] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0 - 7 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 8 - F */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 10 - 17 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 18 - 1F */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 20 - 27 */
+ 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63, /* 28 - 2F */
+ 52, 53, 54, 55, 56, 57, 58, 59, /* 30 - 37 */
+ 60, 61, 0xff, 0xff, 0xff, 64, 0xff, 0xff, /* 38 - 3F */
+ 0xff, 0, 1, 2, 3, 4, 5, 6, /* 40 - 47 */
+ 7, 8, 9, 10, 11, 12, 13, 14, /* 48 - 4F */
+ 15, 16, 17, 18, 19, 20, 21, 22, /* 50 - 57 */
+ 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff, /* 58 - 5F */
+ 0xff, 26, 27, 28, 29, 30, 31, 32, /* 60 - 67 */
+ 33, 34, 35, 36, 37, 38, 39, 40, /* 68 - 6F */
+ 41, 42, 43, 44, 45, 46, 47, 48, /* 70 - 77 */
+ 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff, /* 78 - 7F */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 80 - 87 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 88 - 8F */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 90 - 97 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 98 - 9F */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* A0 - A7 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* A8 - AF */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* B0 - B7 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* B8 - BF */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* C0 - C7 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* C8 - CF */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* D0 - D7 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* D8 - DF */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* E0 - E7 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* E8 - EF */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* F0 - F7 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* F8 - FF */
+};
+static const uint8_t b64_encoding_table[] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3',
+ '4', '5', '6', '7', '8', '9', '+', '/'};
+static const uint8_t b64url_decoding_table[256] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0 - 7 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 8 - F */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 10 - 17 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 18 - 1F */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 20 - 27 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 62, 0xff, 0xff, /* 28 - 2F */
+ 52, 53, 54, 55, 56, 57, 58, 59, /* 30 - 37 */
+ 60, 61, 0xff, 0xff, 0xff, 64, 0xff, 0xff, /* 38 - 3F */
+ 0xff, 0, 1, 2, 3, 4, 5, 6, /* 40 - 47 */
+ 7, 8, 9, 10, 11, 12, 13, 14, /* 48 - 4F */
+ 15, 16, 17, 18, 19, 20, 21, 22, /* 50 - 57 */
+ 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 63, /* 58 - 5F */
+ 0xff, 26, 27, 28, 29, 30, 31, 32, /* 60 - 67 */
+ 33, 34, 35, 36, 37, 38, 39, 40, /* 68 - 6F */
+ 41, 42, 43, 44, 45, 46, 47, 48, /* 70 - 77 */
+ 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff, /* 78 - 7F */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 80 - 87 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 88 - 8F */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 90 - 97 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 98 - 9F */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* A0 - A7 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* A8 - AF */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* B0 - B7 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* B8 - BF */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* C0 - C7 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* C8 - CF */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* D0 - D7 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* D8 - DF */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* E0 - E7 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* E8 - EF */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* F0 - F7 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* F8 - FF */
+};
+static const uint8_t b64url_encoding_table[] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3',
+ '4', '5', '6', '7', '8', '9', '-', '_'};
static unsigned int mod_table[] = {0, 2, 1};
-/* exported interface documented in nsutils/base64.h */
-nsuerror nsu_base64_encode_alloc(const uint8_t *input,
- size_t input_length,
- uint8_t **output,
- size_t *output_length)
+
+
+
+/**
+ * Base 64 encode data using a given encoding table.
+ *
+ * encode source data into buffer using the Base64 encoding.
+ *
+ * \param input The source data to encode.
+ * \param input_length The length of the source data.
+ * \param output The buffer to recive data into,
+ * \param output The output buffer
+ * \param output_length The size of the \a output buffer on entry updated with
+ * length written on exit.
+ * \return NSUERROR_OK on success and \a output_length updated else error code.
+ */
+static nsuerror
+table_encode(const uint8_t *encoding_table,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *encoded,
+ size_t *output_length)
{
- uint8_t *encoded;
size_t encoded_len;
size_t i; /* input index */
size_t j; /* output index */
encoded_len = 4 * ((input_length + 2) / 3);
- encoded = malloc(encoded_len);
- if (encoded == NULL) {
- return NSUERROR_NOMEM;
+ if (encoded_len > *output_length) {
+ /* output buffer is too small */
+ return NSUERROR_NOSPACE;
}
for (i = 0, j = 0; i < input_length;) {
@@ -68,20 +161,151 @@ nsuerror nsu_base64_encode_alloc(const uint8_t *input,
encoded[encoded_len - 1 - i] = '=';
}
- *output = encoded;
*output_length = encoded_len;
return NSUERROR_OK;
}
-/* exported interface documented in nsutils/base64.h */
-nsuerror nsu_base64_decode_alloc(const uint8_t *input,
+
+/**
+ * Base 64 encode data using a given encoding table.
+ *
+ * allocate a buffer and encode source data into it using the Base64 encoding.
+ *
+ * \param input The source data to encode.
+ * \param input_length The length of the source data.
+ * \param output The buffer to recive data into, the caller must free.
+ * \param output_length The length of data placed in \a output
+ * \return NSERROR_OK on success and \a output updated else error code.
+ */
+static nsuerror
+table_encode_alloc(const uint8_t *encoding_table,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t **output,
+ size_t *output_length)
+{
+ uint8_t *encoded;
+ size_t encoded_len;
+ nsuerror res;
+
+ encoded_len = 4 * ((input_length + 2) / 3);
+
+ encoded = malloc(encoded_len);
+ if (encoded == NULL) {
+ return NSUERROR_NOMEM;
+ }
+
+ res = table_encode(encoding_table,
+ input,
+ input_length,
+ encoded,
+ &encoded_len);
+ if (res != NSUERROR_OK) {
+ free(encoded);
+ } else {
+ *output = encoded;
+ *output_length = encoded_len;
+ }
+ return res;
+}
+
+/*
+ * standard base64 encoding
+ *
+ * exported interface documented in nsutils/base64.h
+ */
+nsuerror
+nsu_base64_encode_alloc(const uint8_t *input,
+ size_t input_length,
+ uint8_t **output,
+ size_t *output_length)
+{
+ return table_encode_alloc(b64_encoding_table,
+ input,
+ input_length,
+ output,
+ output_length);
+}
+
+
+/*
+ * url base64 encoding
+ *
+ * exported interface documented in nsutils/base64.h
+ */
+nsuerror
+nsu_base64_encode_alloc_url(const uint8_t *input,
size_t input_length,
uint8_t **output,
size_t *output_length)
{
- static bool decode_initialised = false;
+ return table_encode_alloc(b64url_encoding_table,
+ input,
+ input_length,
+ output,
+ output_length);
+}
+
+
+/*
+ * standard base64 encoding
+ *
+ * exported interface documented in nsutils/base64.h
+ */
+nsuerror
+nsu_base64_encode(const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t *output_length)
+{
+ return table_encode(b64_encoding_table,
+ input,
+ input_length,
+ output,
+ output_length);
+}
+
+
+/*
+ * url base64 encoding
+ *
+ * exported interface documented in nsutils/base64.h
+ */
+nsuerror
+nsu_base64_encode_url(const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t *output_length)
+{
+ return table_encode(b64url_encoding_table,
+ input,
+ input_length,
+ output,
+ output_length);
+}
+
+
+/**
+ * Base 64 decode data with a given decoding table.
+ *
+ * Allocate a buffer and decode source data into it using the Base64 decoding
+ * table.
+ *
+ * \param input The source data to decode.
+ * \param input_length The length of the source data.
+ * \param output The buffer to recive data into, the caller must free.
+ * \param output_length The length of data placed in \a output
+ * \return NSERROR_OK on success and \a output updated else error code.
+ */
+static nsuerror
+base64_decode_alloc(const uint8_t *decoding_table,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t **output,
+ size_t *output_length)
+{
uint8_t *decoded;
size_t decoded_len;
size_t idx;
@@ -89,15 +313,6 @@ nsuerror nsu_base64_decode_alloc(const uint8_t *input,
uint8_t sextet[4];
int sextet_idx;
- if (!decode_initialised) {
- memset(decoding_table, 0xff, sizeof(decoding_table));
- for (idx = 0; idx < 64; idx++) {
- decoding_table[encoding_table[idx]] = idx;
- }
- decoding_table['='] = 64;
- decode_initialised = true;
- }
-
decoded_len = ((input_length + 3) / 4) * 3;
if (input[input_length - 1] == '=') (decoded_len)--;
if (input[input_length - 2] == '=') (decoded_len)--;
@@ -179,3 +394,41 @@ nsuerror nsu_base64_decode_alloc(const uint8_t *input,
return NSUERROR_OK;
}
+
+
+/*
+ * standard base64 decoding
+ *
+ * exported interface documented in nsutils/base64.h
+ */
+nsuerror
+nsu_base64_decode_alloc(const uint8_t *input,
+ size_t input_length,
+ uint8_t **output,
+ size_t *output_length)
+{
+ return base64_decode_alloc(b64_decoding_table,
+ input,
+ input_length,
+ output,
+ output_length);
+}
+
+
+/*
+ * standard base64 decoding
+ *
+ * exported interface documented in nsutils/base64.h
+ */
+nsuerror
+nsu_base64_decode_alloc_url(const uint8_t *input,
+ size_t input_length,
+ uint8_t **output,
+ size_t *output_length)
+{
+ return base64_decode_alloc(b64url_decoding_table,
+ input,
+ input_length,
+ output,
+ output_length);
+}
diff --git a/src/time.c b/src/time.c
index 69da504..34519a1 100644
--- a/src/time.c
+++ b/src/time.c
@@ -20,7 +20,7 @@
#include <time.h>
#elif defined(__riscos)
#include <oslib/os.h>
-#elif defined(__MACH__)
+#elif defined(__MACH__) && defined(__APPLE__)
#include <mach/mach.h>
#include <mach/clock.h>
#include <mach/mach_time.h>
@@ -51,7 +51,7 @@ nsuerror nsu_getmonotonic_ms(uint64_t *current_out)
time = os_read_monotonic_time();
current = time * 10;
-#elif defined(__MACH__)
+#elif defined(__MACH__) && defined(__APPLE__)
clock_serv_t cclock;
mach_timespec_t mts;
diff --git a/src/unistd.c b/src/unistd.c
index 8791a44..bdedad7 100644
--- a/src/unistd.c
+++ b/src/unistd.c
@@ -21,7 +21,7 @@
/* exported interface documented in nsutils/unistd.h */
ssize_t nsu_pwrite(int fd, const void *buf, size_t count, off_t offset)
{
-#if (defined(__riscos) || defined(__amiga) || defined(_WIN32))
+#if (defined(__riscos) || defined(__amiga) || defined(_WIN32) || defined(__serenity__))
off_t sk;
sk = lseek(fd, offset, SEEK_SET);
@@ -53,7 +53,7 @@ ssize_t nsu_pwrite(int fd, const void *buf, size_t count, off_t offset)
/* exported interface documented in nsutils/unistd.h */
ssize_t nsu_pread(int fd, void *buf, size_t count, off_t offset)
{
-#if (defined(__riscos) || defined(_WIN32) || (defined(__amiga) && !defined(__amigaos4__)))
+#if (defined(__riscos) || defined(_WIN32) || defined(__serenity__) || (defined(__amiga) && !defined(__amigaos4__)))
off_t sk;
sk = lseek(fd, offset, SEEK_SET);
diff --git a/test/base64.c b/test/base64.c
index 7b09205..5cb8a7c 100644
--- a/test/base64.c
+++ b/test/base64.c
@@ -16,37 +16,65 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
+#include <unistd.h>
#include <nsutils/base64.h>
int main(int argc, char**argv)
{
- uint8_t *buffer;
- size_t buffer_len=0;
- uint8_t *output;
- size_t output_len;
-
- if (scanf("%1024mc%n", &buffer, (int *)&buffer_len) < 1) {
- return 1;
- }
-
- if (argc == 1) {
- /* encode */
- nsu_base64_encode_alloc(buffer, buffer_len, &output, &output_len);
- } else if ((argv[1][0] == '-') && (argv[1][1] == 'd')) {
- /* decode */
- nsu_base64_decode_alloc(buffer, buffer_len, &output, &output_len);
- } else {
- fprintf(stderr, "Usage: %s [-d]\n", argv[0]);
- return 1;
- }
-
- if (output != NULL) {
- printf("%.*s", (int)output_len, output);
- free(output);
- }
-
- free(buffer);
-
- return 0;
+ uint8_t *buffer;
+ size_t buffer_len=0;
+ uint8_t *output;
+ size_t output_len;
+ int opt;
+ int decode = 0;
+ int url = 0;
+
+
+ while ((opt = getopt(argc, argv, "du")) != -1) {
+ switch (opt) {
+ case 'd':
+ decode = 1;
+ break;
+ case 'u':
+ url = 1;
+ break;
+
+ default: /* '?' */
+ fprintf(stderr, "Usage: %s [-d] [-u]\n", argv[0]);
+ exit(EXIT_FAILURE);
+
+ }
+ }
+
+ if (scanf("%1024mc%n", &buffer, (int *)&buffer_len) < 1) {
+ return 1;
+ }
+
+
+ if (decode) {
+ /* decode */
+ if (url) {
+ nsu_base64_decode_alloc_url(buffer, buffer_len, &output, &output_len);
+ } else {
+
+ nsu_base64_decode_alloc(buffer, buffer_len, &output, &output_len);
+ }
+ } else {
+ /* encode */
+ if (url) {
+ nsu_base64_encode_alloc_url(buffer, buffer_len, &output, &output_len);
+ } else {
+ nsu_base64_encode_alloc(buffer, buffer_len, &output, &output_len);
+ }
+ }
+
+ if (output != NULL) {
+ printf("%.*s", (int)output_len, output);
+ free(output);
+ }
+
+ free(buffer);
+
+ return 0;
}
diff --git a/test/runtest.sh b/test/runtest.sh
index efcb79f..9f02e1c 100755
--- a/test/runtest.sh
+++ b/test/runtest.sh
@@ -5,30 +5,70 @@ b64enctst()
{
ENC=$(echo -n "${1}" | ${TEST_PATH}/test_base64 )
if [ "${ENC}" != "${2}" ];then
- echo "Base64 encode error ${ENC} != ${2}"
+ echo "Base64 encode error '${ENC}' != '${2}'"
exit 2
- fi
+ fi
}
b64dectst()
{
DEC=$(echo -n "$1" | ${TEST_PATH}/test_base64 -d )
if [ "${DEC}" != "$2" ];then
- echo "Base64 decode error ${DEC} != $2"
+ echo "Base64 decode error '${DEC}' != '$2'"
exit 3
- fi
+ fi
}
-b64enctst 'f' 'Zg=='
-b64enctst 'fo' 'Zm8='
-b64enctst 'foo' 'Zm9v'
-b64enctst 'foob' 'Zm9vYg=='
-b64enctst 'fooba' 'Zm9vYmE='
+b64urlenctst()
+{
+ ENC=$(echo -n "${1}" | ${TEST_PATH}/test_base64 -u )
+ if [ "${ENC}" != "${2}" ];then
+ echo "Base64 url encode error '${ENC}' != '${2}'"
+ exit 2
+ fi
+}
+
+b64urldectst()
+{
+ DEC=$(echo -n "$1" | ${TEST_PATH}/test_base64 -d -u )
+ if [ "${DEC}" != "$2" ];then
+ echo "Base64 url decode error '${DEC}' != '$2'"
+ exit 3
+ fi
+}
+
+b64enctst 'f' 'Zg=='
+b64enctst 'fo' 'Zm8='
+b64enctst 'foo' 'Zm9v'
+b64enctst ' >' 'ICA+'
+b64enctst ' ?' 'ICA/'
+b64enctst 'foob' 'Zm9vYg=='
+b64enctst 'fooba' 'Zm9vYmE='
b64enctst 'foobar' 'Zm9vYmFy'
-b64dectst 'Zg==' 'f'
-b64dectst 'Zm8=' 'fo'
-b64dectst 'Zm9v' 'foo'
+b64dectst 'Zg==' 'f'
+b64dectst 'Zm8=' 'fo'
+b64dectst 'Zm9v' 'foo'
+b64dectst 'ICA+' ' >'
+b64dectst 'ICA/' ' ?'
b64dectst 'Zm9vYg==' 'foob'
b64dectst 'Zm9vYmE=' 'fooba'
b64dectst 'Zm9vYmFy' 'foobar'
+
+b64urlenctst 'f' 'Zg=='
+b64urlenctst 'fo' 'Zm8='
+b64urlenctst 'foo' 'Zm9v'
+b64urlenctst ' >' 'ICA-'
+b64urlenctst ' ?' 'ICA_'
+b64urlenctst 'foob' 'Zm9vYg=='
+b64urlenctst 'fooba' 'Zm9vYmE='
+b64urlenctst 'foobar' 'Zm9vYmFy'
+
+b64urldectst 'Zg==' 'f'
+b64urldectst 'Zm8=' 'fo'
+b64urldectst 'Zm9v' 'foo'
+b64urldectst 'ICA-' ' >'
+b64urldectst 'ICA_' ' ?'
+b64urldectst 'Zm9vYg==' 'foob'
+b64urldectst 'Zm9vYmE=' 'fooba'
+b64urldectst 'Zm9vYmFy' 'foobar'