aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/aes/src/error.c
diff options
context:
space:
mode:
Diffstat (limited to 'aes/src/error.c')
-rw-r--r--aes/src/error.c251
1 files changed, 251 insertions, 0 deletions
diff --git a/aes/src/error.c b/aes/src/error.c
new file mode 100644
index 0000000..d49c456
--- /dev/null
+++ b/aes/src/error.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+ * This file is part of the "AES tools" project.
+ * For details, see https://github.com/egor-tensin/aes-tools.
+ * Distributed under the MIT License.
+ */
+
+#include <aes/all.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+
+#include <stdarg.h>
+
+#define snprintf c99_snprintf
+#define vsnprintf c99_vsnprintf
+
+static int c99_vsnprintf(char *dest, size_t dest_size, const char *fmt, va_list ap)
+{
+ int dest_len = -1;
+
+ if (dest_size != 0)
+ dest_len = _vsnprintf_s(dest, dest_size, _TRUNCATE, fmt, ap);
+ if (dest_len == -1)
+ dest_len = _vscprintf(fmt, ap);
+
+ return dest_len;
+}
+
+static int c99_snprintf(char *dest, size_t dest_size, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+
+ int dest_len = c99_vsnprintf(dest, dest_size, fmt, ap);
+
+ va_end(ap);
+ return dest_len;
+}
+
+#endif
+
+static void aes_fill_string(char* dest, size_t dest_size, const char* src)
+{
+ strncpy(dest, src, dest_size);
+ dest[dest_size - 1] = '\0';
+}
+
+static const char* aes_strerror_messages[] =
+{
+ "Success",
+ "Invalid argument value NULL",
+ "Couldn't parse",
+ "Invalid PKCS7 padding (wrong key?)",
+ "Not implemented",
+ "Missing padding",
+ "Couldn't allocate memory",
+};
+
+const char* aes_strerror(AES_StatusCode ec)
+{
+ return aes_strerror_messages[ec];
+}
+
+static size_t aes_format_error_strerror(
+ const AES_ErrorDetails* err_details,\
+ char* dest,
+ size_t dest_size)
+{
+ const AES_StatusCode ec = aes_get_error_code(err_details);
+ const char* const msg = aes_strerror(ec);
+
+ if (dest == NULL)
+ return strlen(msg) + 1;
+
+ aes_fill_string(dest, dest_size, msg);
+ return strlen(dest);
+}
+
+static size_t aes_format_null_argument_error(
+ const AES_ErrorDetails* err_details,
+ char* dest,
+ size_t dest_size)
+{
+ static const char* const fmt = "Invalid argument value NULL for parameter '%s'";
+ const char* const param_name = err_details->params.null_arg.param_name;
+
+ if (dest == NULL && dest_size == 0)
+ return snprintf(NULL, 0, fmt, param_name) + 1;
+
+ snprintf(dest, dest_size, fmt, param_name);
+ return strlen(dest);
+}
+
+static size_t aes_format_parse_error(
+ const AES_ErrorDetails* err_details,
+ char* dest,
+ size_t dest_size)
+{
+ static const char* const fmt = "Couldn't parse '%s' (possibly not complete input) as %s";
+ const char* const src = err_details->params.parse_error.src;
+ const char* const what = err_details->params.parse_error.what;
+
+ if (dest == NULL)
+ return snprintf(NULL, 0, fmt, src, what) + 1;
+
+ snprintf(dest, dest_size, fmt, src, what);
+ return strlen(dest);
+}
+
+static size_t aes_format_not_implemented_error(
+ const AES_ErrorDetails* err_details,
+ char* dest,
+ size_t dest_size)
+{
+ static const char* const fmt = "Not implemented: %s";
+ const char* const src = err_details->params.not_implemented.what;
+
+ if (dest == NULL)
+ return snprintf(NULL, 0, fmt, src) + 1;
+
+ snprintf(dest, dest_size, fmt, src);
+ return strlen(dest);
+}
+
+typedef size_t (*AES_ErrorFormatter)(const AES_ErrorDetails*, char*, size_t);
+
+static AES_ErrorFormatter err_formatters[] =
+{
+ &aes_format_error_strerror,
+ &aes_format_null_argument_error,
+ &aes_format_parse_error,
+ &aes_format_error_strerror,
+ &aes_format_not_implemented_error,
+ &aes_format_error_strerror,
+ &aes_format_error_strerror,
+};
+
+size_t aes_format_error(
+ const AES_ErrorDetails* err_details,
+ char* dest,
+ size_t dest_size)
+{
+ assert(err_details);
+
+ return err_formatters[err_details->ec](err_details, dest, dest_size);
+}
+
+#ifdef WIN32
+#include <windows.h>
+
+static void aes_collect_call_stack(AES_ErrorDetails* err_details)
+{
+ err_details->call_stack_len = CaptureStackBackTrace(
+ 1, AES_MAX_CALL_STACK_LENGTH, err_details->call_stack, NULL);
+}
+#else
+static void aes_collect_call_stack(AES_ErrorDetails* err_details)
+{
+ err_details->call_stack_len = 0;
+}
+#endif
+
+static AES_StatusCode aes_make_error(
+ AES_ErrorDetails* err_details,
+ AES_StatusCode ec)
+{
+ if (err_details == NULL)
+ return ec;
+
+ if (aes_is_error(ec))
+ aes_collect_call_stack(err_details);
+
+ return err_details->ec = ec;
+}
+
+AES_StatusCode aes_success(
+ AES_ErrorDetails* err_details)
+{
+ return aes_make_error(err_details, AES_SUCCESS);
+}
+
+AES_StatusCode aes_error_null_argument(
+ AES_ErrorDetails* err_details,
+ const char* param_name)
+{
+ AES_StatusCode status = aes_make_error(err_details, AES_NULL_ARGUMENT_ERROR);
+
+ if (err_details != NULL)
+ aes_fill_string(
+ err_details->params.null_arg.param_name,
+ sizeof(err_details->params.null_arg.param_name), param_name);
+
+ return status;
+}
+
+AES_StatusCode aes_error_parse(
+ AES_ErrorDetails* err_details,
+ const char* src,
+ const char* what)
+{
+ AES_StatusCode status = aes_make_error(err_details, AES_PARSE_ERROR);
+
+ if (err_details != NULL)
+ {
+ aes_fill_string(
+ err_details->params.parse_error.src,
+ sizeof(err_details->params.parse_error.src), src);
+ aes_fill_string(
+ err_details->params.parse_error.what,
+ sizeof(err_details->params.parse_error.what), what);
+ }
+
+ return status;
+}
+
+AES_StatusCode aes_error_invalid_pkcs7_padding(
+ AES_ErrorDetails* err_details)
+{
+ return aes_make_error(err_details, AES_INVALID_PKCS7_PADDING_ERROR);
+}
+
+AES_StatusCode aes_error_not_implemented(
+ AES_ErrorDetails* err_details,
+ const char* what)
+{
+ AES_StatusCode status = aes_make_error(err_details, AES_NOT_IMPLEMENTED_ERROR);
+
+ if (err_details != NULL)
+ aes_fill_string(
+ err_details->params.not_implemented.what,
+ sizeof(err_details->params.not_implemented.what), what);
+
+ return status;
+}
+
+AES_StatusCode aes_error_missing_padding(
+ AES_ErrorDetails* err_details)
+{
+ return aes_make_error(err_details, AES_MISSING_PADDING_ERROR);
+}
+
+AES_StatusCode aes_error_memory_allocation(
+ AES_ErrorDetails* err_details)
+{
+ return aes_make_error(err_details, AES_MEMORY_ALLOCATION_ERROR);
+}