aboutsummaryrefslogtreecommitdiffstats
path: root/libparc/parc/algol/parc_ByteArray.c
diff options
context:
space:
mode:
Diffstat (limited to 'libparc/parc/algol/parc_ByteArray.c')
-rw-r--r--libparc/parc/algol/parc_ByteArray.c312
1 files changed, 312 insertions, 0 deletions
diff --git a/libparc/parc/algol/parc_ByteArray.c b/libparc/parc/algol/parc_ByteArray.c
new file mode 100644
index 00000000..762421bd
--- /dev/null
+++ b/libparc/parc/algol/parc_ByteArray.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_ByteArray.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+struct parc_byte_array {
+ uint8_t *array;
+ size_t length;
+ void (*freeFunction)(void **);
+};
+#define MAGIC 0x0ddba11c1a55e5
+
+static inline void
+_trapIfOutOfBounds(const PARCByteArray *array, const size_t index)
+{
+ trapOutOfBoundsIf(index >= array->length, "parcByteArray index %zd exceeds the length %zd", index, array->length);
+}
+
+static bool
+_parcByteArray_Destructor(PARCByteArray **byteArrayPtr)
+{
+ PARCByteArray *byteArray = *byteArrayPtr;
+
+ if (byteArray->freeFunction != NULL) {
+ if (byteArray->array != NULL) {
+ byteArray->freeFunction((void **) &(byteArray->array));
+ }
+ }
+ return true;
+}
+
+parcObject_Override(PARCByteArray, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcByteArray_Destructor,
+ .copy = (PARCObjectCopy *) parcByteArray_Copy,
+ .equals = (PARCObjectEquals *) parcByteArray_Equals,
+ .compare = (PARCObjectCompare *) parcByteArray_Compare,
+ .hashCode = (PARCObjectHashCode *) parcByteArray_HashCode,
+ .display = (PARCObjectDisplay *) parcByteArray_Display);
+
+void
+parcByteArray_AssertValid(const PARCByteArray *instance)
+{
+ trapInvalidValueIf(parcByteArray_IsValid(instance) == false,
+ "PARCByteArray instance is invalid.");
+}
+
+bool
+parcByteArray_IsValid(const PARCByteArray *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ if (instance->length == 0 || instance->array != NULL) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+PARCByteArray *
+parcByteArray_Allocate(const size_t length)
+{
+ uint8_t *array = NULL;
+ if (length > 0) {
+ array = parcMemory_AllocateAndClear(sizeof(uint8_t) * length);
+ if (array == NULL) {
+ return NULL;
+ }
+ }
+ PARCByteArray *result = parcObject_CreateInstance(PARCByteArray);
+
+ if (result != NULL) {
+ result->array = array;
+ result->length = length;
+ result->freeFunction = parcMemory_DeallocateImpl;
+ return result;
+ } else {
+ parcMemory_Deallocate(&array);
+ }
+ return NULL;
+}
+
+PARCByteArray *
+parcByteArray_Wrap(const size_t length, uint8_t array[length])
+{
+ if (array != NULL) {
+ PARCByteArray *result = parcObject_CreateInstance(PARCByteArray);
+ if (result != NULL) {
+ result->array = array;
+ result->length = length;
+ result->freeFunction = NULL;
+ return result;
+ }
+ }
+ return NULL;
+}
+
+parcObject_ImplementAcquire(parcByteArray, PARCByteArray);
+
+parcObject_ImplementRelease(parcByteArray, PARCByteArray);
+
+PARCByteArray *
+parcByteArray_Copy(const PARCByteArray *original)
+{
+ parcByteArray_OptionalAssertValid(original);
+
+ PARCByteArray *result = NULL;
+
+ if (original != NULL) {
+ result = parcByteArray_Allocate(original->length);
+ memcpy(result->array, original->array, result->length);
+ }
+
+ return result;
+}
+
+size_t
+parcByteArray_Capacity(const PARCByteArray *byteArray)
+{
+ parcByteArray_OptionalAssertValid(byteArray);
+ return byteArray->length;
+}
+
+PARCByteArray *
+parcByteArray_PutByte(PARCByteArray *result, size_t index, uint8_t byte)
+{
+ parcByteArray_OptionalAssertValid(result);
+ _trapIfOutOfBounds(result, index);
+
+ result->array[index] = byte;
+ return result;
+}
+
+uint8_t
+parcByteArray_GetByte(const PARCByteArray *array, size_t index)
+{
+ parcByteArray_OptionalAssertValid(array);
+ _trapIfOutOfBounds(array, index);
+
+ return array->array[index];
+}
+
+uint8_t *
+parcByteArray_Array(const PARCByteArray *byteArray)
+{
+ parcByteArray_OptionalAssertValid(byteArray);
+ return byteArray->array;
+}
+
+uint8_t *
+parcByteArray_AddressOfIndex(const PARCByteArray *array, const size_t index)
+{
+ parcByteArray_OptionalAssertValid(array);
+ _trapIfOutOfBounds(array, index);
+
+ return &array->array[index];
+}
+
+int
+parcByteArray_Compare(const PARCByteArray *x, const PARCByteArray *y)
+{
+ if (x == y) {
+ return 0;
+ }
+
+ if (x == NULL) {
+ return -1;
+ }
+
+ if (y == NULL) {
+ return +1;
+ }
+
+ if (parcByteArray_Capacity(x) > parcByteArray_Capacity(y)) {
+ return +1;
+ }
+ if (parcByteArray_Capacity(x) < parcByteArray_Capacity(y)) {
+ return -1;
+ }
+
+ return memcmp(x->array, y->array, parcByteArray_Capacity(x));
+}
+
+PARCByteArray *
+parcByteArray_PutBytes(PARCByteArray *result, size_t offset, size_t length, const uint8_t source[length])
+{
+ parcByteArray_OptionalAssertValid(result);
+ trapOutOfBoundsIf(offset > result->length,
+ "The offset (%zd) exeeds the length (%zd) of the PARCByteArray.", offset, result->length);
+
+ size_t available = result->length - offset;
+
+ trapOutOfBoundsIf(length > available, "%zd available bytes, %zd required.", available, length);
+
+ memcpy(&result->array[offset], source, length);
+ return result;
+}
+
+PARCByteArray *
+parcByteArray_GetBytes(const PARCByteArray *result, size_t offset, size_t length, uint8_t array[length])
+{
+ parcByteArray_OptionalAssertValid(result);
+
+ size_t available = result->length - offset;
+
+ trapOutOfBoundsIf(length > available, "parcByteArray_CopyOut %zd available bytes, %zd required", available, length);
+
+ memcpy(array, &result->array[offset], length);
+ return (PARCByteArray *) result;
+}
+
+PARCByteArray *
+parcByteArray_ArrayCopy(PARCByteArray *destination, size_t destOffset, const PARCByteArray *source, size_t srcOffset, size_t length)
+{
+ parcByteArray_OptionalAssertValid(destination);
+ parcByteArray_OptionalAssertValid(source);
+
+ memcpy(&destination->array[destOffset], &source->array[srcOffset], length);
+ return destination;
+}
+
+bool
+parcByteArray_Equals(const PARCByteArray *a, const PARCByteArray *b)
+{
+ if (a == b) {
+ return true;
+ }
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+ if (a->length == b->length) {
+ return memcmp(a->array, b->array, a->length) == 0;
+ }
+ return false;
+}
+
+static void
+_parcByteArray_PrettyPrintLine(const unsigned char *memory, size_t offset, size_t length)
+{
+ int bytesPerLine = 16;
+ char accumulator[bytesPerLine + 1];
+ memset(accumulator, ' ', bytesPerLine);
+ accumulator[bytesPerLine] = 0;
+
+ printf("%5zd: ", offset);
+
+ for (int i = 0; i < bytesPerLine; i++) {
+ if (offset + i >= length) {
+ printf(" ");
+ accumulator[i] = ' ';
+ } else {
+ char c = memory[offset + i];
+ printf("0x%02x, ", c & 0xFF);
+ if (isprint(c)) {
+ accumulator[i] = c;
+ } else {
+ accumulator[i] = '.';
+ }
+ }
+ }
+ printf(" %s\n", accumulator);
+}
+
+void
+parcByteArray_Display(const PARCByteArray *array, int indentation)
+{
+ int bytesPerLine = 16;
+
+ if (array->array == NULL) {
+ parcDisplayIndented_PrintLine(indentation, "PARCByteArray@NULL");
+ } else {
+ parcDisplayIndented_PrintLine(indentation, "PARCByteArray@%p = [0,%zd)", (void *) array, array->length);
+
+ for (size_t offset = 0; offset < array->length; offset += bytesPerLine) {
+ _parcByteArray_PrettyPrintLine(array->array, offset, array->length);
+ }
+ }
+}
+
+PARCHashCode
+parcByteArray_HashCode(const PARCByteArray *array)
+{
+ parcByteArray_OptionalAssertValid(array);
+ return parcHashCode_Hash(array->array, array->length);
+}