diff options
-rw-r--r-- | .gitattributes | 2 | ||||
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | COPYING | 19 | ||||
-rw-r--r-- | Makefile | 36 | ||||
-rw-r--r-- | include/nsutils/base64.h | 30 | ||||
-rw-r--r-- | include/nsutils/errors.h | 78 | ||||
-rw-r--r-- | src/Makefile | 3 | ||||
-rw-r--r-- | src/base64.c | 181 | ||||
-rw-r--r-- | test/Makefile | 3 | ||||
-rw-r--r-- | test/base64.c | 48 | ||||
-rwxr-xr-x | test/runtest.sh | 34 |
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-* + @@ -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' |