summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2014-11-18 16:15:56 +0000
committerVincent Sanders <vince@kyllikki.org>2014-11-18 16:15:56 +0000
commit257deb32c83dbdd989d2021cdbd5ad7dbb28386f (patch)
tree2a29e2222196f351e62e1316ddaeefcb405fbb1a
downloadlibnsutils-257deb32c83dbdd989d2021cdbd5ad7dbb28386f.tar.gz
libnsutils-257deb32c83dbdd989d2021cdbd5ad7dbb28386f.tar.bz2
Initial nsutils library with base64 implementation an tests
-rw-r--r--.gitattributes2
-rw-r--r--.gitignore2
-rw-r--r--COPYING19
-rw-r--r--Makefile36
-rw-r--r--include/nsutils/base64.h30
-rw-r--r--include/nsutils/errors.h78
-rw-r--r--src/Makefile3
-rw-r--r--src/base64.c181
-rw-r--r--test/Makefile3
-rw-r--r--test/base64.c48
-rwxr-xr-xtest/runtest.sh34
11 files changed, 436 insertions, 0 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..de2f316
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+.gitignore export-ignore
+.gitattributes export-ignore
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..179b224
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+build-*
+
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..0bedd97
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,19 @@
+Copyright 2014 Vincent Sanders <vince@netsurf-browser.org>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..e371558
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,36 @@
+# Component settings
+COMPONENT := nsutils
+COMPONENT_VERSION := 0.0.1
+# Default to a static library
+COMPONENT_TYPE ?= lib-static
+
+# Setup the tooling
+PREFIX ?= /opt/netsurf
+NSSHARED ?= $(PREFIX)/share/netsurf-buildsystem
+include $(NSSHARED)/makefiles/Makefile.tools
+
+# Reevaluate when used, as BUILDDIR won't be defined yet
+TESTRUNNER = test/runtest.sh $(BUILDDIR) $(EXEEXT)
+
+# Toolchain flags
+WARNFLAGS := -Wall -W -Wundef -Wpointer-arith -Wcast-align \
+ -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes \
+ -Wmissing-declarations -Wnested-externs
+CFLAGS := -I$(CURDIR)/include/ -I$(CURDIR)/src $(WARNFLAGS) $(CFLAGS)
+ifneq ($(GCCVER),2)
+ CFLAGS := $(CFLAGS) -std=c99
+else
+ # __inline__ is a GCCism
+ CFLAGS := $(CFLAGS) -Dinline="__inline__"
+endif
+
+TESTCFLAGGS := -g -O2
+TESTLDFLAGS := -lm -l$(COMPONENT) $(TESTLDFLAGS)
+
+include $(NSBUILD)/Makefile.top
+
+# Extra installation rules
+I := /include/nsutils
+INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/nsutils/utils.h
+INSTALL_ITEMS := $(INSTALL_ITEMS) /$(LIBDIR)/pkgconfig:lib$(COMPONENT).pc.in
+INSTALL_ITEMS := $(INSTALL_ITEMS) /$(LIBDIR):$(OUTPUT)
diff --git a/include/nsutils/base64.h b/include/nsutils/base64.h
new file mode 100644
index 0000000..139a1b6
--- /dev/null
+++ b/include/nsutils/base64.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2014 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of libnsutils.
+ *
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+
+/**
+ * \file
+ * Base64 encoding and decoding interface.
+ */
+
+#ifndef NSUTILS_BASE64_H_
+#define NSUTILS_BASE64_H_
+
+#include <nsutils/errors.h>
+
+nserror base64_encode_alloc(const uint8_t *input,
+ size_t input_length,
+ uint8_t **output,
+ size_t *output_length);
+
+nserror base64_decode_alloc(const uint8_t *input,
+ size_t input_length,
+ uint8_t **output,
+ size_t *output_length);
+
+#endif
diff --git a/include/nsutils/errors.h b/include/nsutils/errors.h
new file mode 100644
index 0000000..0da38d9
--- /dev/null
+++ b/include/nsutils/errors.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of libnsutils.
+ *
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+
+/**
+ * \file
+ * Error codes.
+ */
+
+#ifndef NSUTILS_ERRORS_H_
+#define NSUTILS_ERRORS_H_
+
+/**
+ * Enumeration of error codes
+ */
+typedef enum {
+ NSERROR_OK, /**< No error */
+
+ NSERROR_UNKNOWN, /**< Unknown error - DO *NOT* USE */
+
+ NSERROR_NOMEM, /**< Memory exhaustion */
+
+ NSERROR_NO_FETCH_HANDLER, /**< No fetch handler for URL scheme */
+
+ NSERROR_NOT_FOUND, /**< Requested item not found */
+
+ NSERROR_NOT_DIRECTORY, /**< Missing directory */
+
+ NSERROR_SAVE_FAILED, /**< Failed to save data */
+
+ NSERROR_CLONE_FAILED, /**< Failed to clone handle */
+
+ NSERROR_INIT_FAILED, /**< Initialisation failed */
+
+ NSERROR_MNG_ERROR, /**< An MNG error occurred */
+
+ NSERROR_BAD_ENCODING, /**< The character set is unknown */
+
+ NSERROR_NEED_DATA, /**< More data needed */
+
+ NSERROR_ENCODING_CHANGE, /**< The character changed */
+
+ NSERROR_BAD_PARAMETER, /**< Bad Parameter */
+
+ NSERROR_INVALID, /**< Invalid data */
+
+ NSERROR_BOX_CONVERT, /**< Box conversion failed */
+
+ NSERROR_STOPPED, /**< Content conversion stopped */
+
+ NSERROR_DOM, /**< DOM call returned error */
+
+ NSERROR_CSS, /**< CSS call returned error */
+
+ NSERROR_CSS_BASE, /**< CSS base sheet failed */
+
+ NSERROR_BAD_URL, /**< Bad URL */
+
+ NSERROR_BAD_CONTENT, /**< Bad Content */
+
+ NSERROR_FRAME_DEPTH, /**< Exceeded frame depth */
+
+ NSERROR_PERMISSION, /**< Permission error */
+
+ NSERROR_NOSPACE, /**< Insufficient space */
+
+ NSERROR_BAD_SIZE, /**< Bad size */
+
+ NSERROR_NOT_IMPLEMENTED, /**< Functionality is not implemented */
+} nserror;
+
+#endif
+
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..c5e0cbe
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,3 @@
+DIR_SOURCES := base64.c
+
+include $(NSBUILD)/Makefile.subdir
diff --git a/src/base64.c b/src/base64.c
new file mode 100644
index 0000000..b2e020b
--- /dev/null
+++ b/src/base64.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2014 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of libnsutils.
+ *
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+
+/**
+ * \file
+ * Base64 encoding and decoding implementation.
+ *
+ * Implements RFC4648 (https://tools.ietf.org/html/rfc4648)
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+#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 unsigned int mod_table[] = {0, 2, 1};
+
+/* exported interface documented in nsutils/base64.h */
+nserror base64_encode_alloc(const uint8_t *input,
+ size_t input_length,
+ uint8_t **output,
+ 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 NSERROR_NOMEM;
+ }
+
+ for (i = 0, j = 0; i < input_length;) {
+
+ uint32_t octet_a = i < input_length ? input[i++] : 0;
+ uint32_t octet_b = i < input_length ? input[i++] : 0;
+ uint32_t octet_c = i < input_length ? input[i++] : 0;
+
+ uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
+
+ encoded[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
+ encoded[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
+ encoded[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
+ encoded[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
+ }
+
+ for (i = 0; i < mod_table[input_length % 3]; i++) {
+ encoded[encoded_len - 1 - i] = '=';
+ }
+
+ *output = encoded;
+ *output_length = encoded_len;
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface documented in nsutils/base64.h */
+nserror base64_decode_alloc(const uint8_t *input,
+ size_t input_length,
+ uint8_t **output,
+ size_t *output_length)
+{
+ static bool decode_initialised = false;
+ uint8_t *decoded;
+ size_t decoded_len;
+ size_t idx;
+ size_t opidx;
+ 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)--;
+
+ decoded = malloc(decoded_len);
+ if (decoded == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ sextet_idx = 0;
+ idx = 0;
+ opidx = 0;
+ while (idx < input_length) {
+ sextet[sextet_idx] = decoding_table[input[idx++]];
+ if (sextet[sextet_idx] >= 64) {
+ /* not in encoding set */
+ if (sextet[sextet_idx] == 64) {
+ break; /* pad recived - input complete */
+ }
+ } else {
+ sextet_idx++;
+ if (sextet_idx == 4) {
+ if (opidx >= (decoded_len - 3)) {
+ break; /* insufficient output buffer space */
+ }
+ decoded[opidx++] = (sextet[0] << 2) | (sextet[1] >> 4);
+ decoded[opidx++] = (sextet[1] << 4) | (sextet[2] >> 2);
+ decoded[opidx++] = (sextet[2] << 6) | (sextet[3]);
+
+ sextet_idx = 0;
+ }
+ }
+ }
+
+ /* deal with any remaining recived bytes ensuring output buffer is not overrun */
+ switch (sextet_idx) {
+ case 1:
+ if (opidx < decoded_len) {
+ decoded[opidx++] = (sextet[0] << 2);
+ }
+ break;
+
+ case 2:
+ if (opidx < decoded_len) {
+ decoded[opidx++] = (sextet[0] << 2) | (sextet[1] >> 4);
+ }
+ if (opidx < decoded_len) {
+ decoded[opidx++] = (sextet[1] << 4);
+ }
+ break;
+
+ case 3:
+ if (opidx < decoded_len) {
+ decoded[opidx++] = (sextet[0] << 2) | (sextet[1] >> 4);
+ }
+ if (opidx < decoded_len) {
+ decoded[opidx++] = (sextet[1] << 4) | (sextet[2] >> 2);
+ }
+ if (opidx < decoded_len) {
+ decoded[opidx++] = (sextet[2] << 6);
+ }
+ break;
+
+ case 4:
+ if (opidx < decoded_len) {
+ decoded[opidx++] = (sextet[0] << 2) | (sextet[1] >> 4);
+ }
+ if (opidx < decoded_len) {
+ decoded[opidx++] = (sextet[1] << 4) | (sextet[2] >> 2);
+ }
+ if (opidx < decoded_len) {
+ decoded[opidx++] = (sextet[2] << 6) | (sextet[3]);
+ }
+ break;
+ }
+
+ *output = decoded;
+ *output_length = opidx;
+
+ return NSERROR_OK;
+}
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 0000000..1a86ed0
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,3 @@
+DIR_TEST_ITEMS := base64:base64.c
+
+include $(NSBUILD)/Makefile.subdir
diff --git a/test/base64.c b/test/base64.c
new file mode 100644
index 0000000..f86e65e
--- /dev/null
+++ b/test/base64.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of libnsutils.
+ *
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+
+/**
+ * \file
+ *
+ * Base64 test program. Reads data from stdin and en/de codes it to/from base64
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <nsutils/base64.h>
+
+int main(int argc, char**argv)
+{
+ uint8_t *buffer;
+ size_t buffer_len;
+ uint8_t *output;
+ size_t output_len;
+
+ if (scanf("%1024mc%n", &buffer, (int *)&buffer_len) < 1) {
+ return 1;
+ }
+
+ if (argc == 1) {
+ /* encode */
+ base64_encode_alloc(buffer, buffer_len, &output, &output_len);
+ } else {
+ /* decode */
+ base64_decode_alloc(buffer, buffer_len, &output, &output_len);
+ }
+
+ if (output != NULL) {
+ printf("%.*s", (int)output_len, output);
+ free(output);
+ }
+
+ free(buffer);
+
+}
diff --git a/test/runtest.sh b/test/runtest.sh
new file mode 100755
index 0000000..efcb79f
--- /dev/null
+++ b/test/runtest.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+TEST_PATH=$1
+
+b64enctst()
+{
+ ENC=$(echo -n "${1}" | ${TEST_PATH}/test_base64 )
+ if [ "${ENC}" != "${2}" ];then
+ echo "Base64 encode error ${ENC} != ${2}"
+ exit 2
+ fi
+}
+
+b64dectst()
+{
+ DEC=$(echo -n "$1" | ${TEST_PATH}/test_base64 -d )
+ if [ "${DEC}" != "$2" ];then
+ echo "Base64 decode error ${DEC} != $2"
+ exit 3
+ fi
+}
+
+b64enctst 'f' 'Zg=='
+b64enctst 'fo' 'Zm8='
+b64enctst 'foo' 'Zm9v'
+b64enctst 'foob' 'Zm9vYg=='
+b64enctst 'fooba' 'Zm9vYmE='
+b64enctst 'foobar' 'Zm9vYmFy'
+
+b64dectst 'Zg==' 'f'
+b64dectst 'Zm8=' 'fo'
+b64dectst 'Zm9v' 'foo'
+b64dectst 'Zm9vYg==' 'foob'
+b64dectst 'Zm9vYmE=' 'fooba'
+b64dectst 'Zm9vYmFy' 'foobar'