diff --git a/CMakeLists.txt b/CMakeLists.txt index 2129543..faa9459 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,10 @@ set(O_OUTPUT_DIR ${T_OUTPUT_DIR}/obj CACHE PATH "Build object output directory") endif() # Option Defaults. +option (BUILD_BYTE_ORDER "Whether or not to build the Byte Ordering code. (Defaults to yes.)" ON) option (BUILD_DYNAMIC_LIBRARY_SUBSYSTEM "Whether or not to build the Dynamic Library Subsystem. (Defaults to yes.)" ON) +option (BUILD_COMMON_ERROR_HANDLER "Whether or not to build the Common Error Handler. (Defaults to yes.)" ON) +option (BUILD_FATAL_ERROR_NOTIFY_SUPPORT "Whether or not to build the Common Error Handler's fatal error notification support. (Defaults to yes.)" ON) option (BUILD_INTERNAL_MUTEX_SUPPORT "Whether or not to build the internal mutex support library. (Defaults to yes.)" ON) option (BUILD_COMMON_ERROR_HANDLER "Whether or not to build the common error handler. (Defaults to yes.)" ON) option (BUILD_INTERNAL_MUTEX_THREAD_SUBSYS_WRAPPER "Whether or not the Threading Subsystem library will have Internal Mutex Support built in. (Defaults to yes, but is disabled currently due to changes to Thread_Utils that have not been commited yet.)" OFF) diff --git a/src/Common/Src/Byte_Order/Byte_Order.c b/src/Common/Src/Byte_Order/Byte_Order.c new file mode 100644 index 0000000..dbcb25a --- /dev/null +++ b/src/Common/Src/Byte_Order/Byte_Order.c @@ -0,0 +1,347 @@ +/*! + Multiverse Engine Project 03/6/2015 Common Byte_Order.c + + Copyright (C) 2015 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Internal includes. */ +#include "Byte_Order.h" + +/* Check for C++ compiler. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +int Byte_Order_Bit_Comparison(const char * byte, const char bitMask, const char bitValues) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result code of this function. */ + + /* 10000000 wanna check the first two bits, how? + + 11000000 <-- Bit mask of bits to actually check. + + 10 <-- What the two bits should be. + + Do two comparisons. (One for the set (1) bits and one for the unset (0) bits. + + bits should be: BINARY AND BITMASK. BITS THAT ARE ACTUALLY SET TO CHECK. + (1000000) & (11000000) = (1000000) + + BITWISE NOT bits should be: Inverted what bits should be. + ~ (1000000) = (01111111) + + Inverted what bits should be: BINARY AND BITMASK. BITS THAT ARE NOT SET TO CHECK. + (01111111) & (11000000) = (0100000) + + BITS TO CHECK. BINARY AND BITS THAT ARE SET TO CHECK. (Comparison one result) + (10000000) & (1000000) = SUCCESS. (1000000) + + Inverted BITS TO CHECK. BINARY AND BITS THAT ARE NOT SET TO CHECK. (Comparison two result) + (01111111) & (0100000) = SUCCESS. (0100000) + + (Comparison one result) BINARY INCLUSIVE OR (Comparison two result) (Result of both comparisons) + (1000000) | (0100000) = (11000000) + + BITMASK BINARY AND (Result of both comparisons) Final result + (11000000) & (11000000) = SUCCESS (11000000) + + */ + + /* Check for invalid arguments. */ + if (byte != NULL) + { + /* Check for all value comparison. */ + /*ret = (bitMask == UCHAR_MAX) ? + /* Simple equality check, we only need to check for an exact match. Otherwise continue comparison on the next line. / + (((*byte) == bitValues) ? COMMON_ERROR_COMPARISON_PASSED : COMMON_ERROR_COMPARISON_FAILED) : \ + /* HARDCODED CHECK: If both bitValues and byte are zero, + and bitMask is non-zero we need to return true. Otherwise continue on the next line. / + ((((*byte) == 0) && (bitValues == 0)) ? ((bitMask != 0) ? COMMON_ERROR_COMPARISON_PASSED : COMMON_ERROR_COMPARISON_FAILED) : \ + /* Because it's not a simple equality check, Do first comparison. (Set (1) bits.) / + ((((*byte) & (bitValues & bitMask)) && ((~(*byte)) & ((~bitValues) & bitMask))) ? + /* Do the second comparison. (Unset (0) bits.) / + COMMON_ERROR_COMPARISON_PASSED : COMMON_ERROR_COMPARISON_FAILED));*/ + if (bitMask == UCHAR_MAX) + { + ret = ((*byte) == bitValues) ? COMMON_ERROR_COMPARISON_PASSED : COMMON_ERROR_COMPARISON_FAILED; + } + else + { + if (((*byte) == 0) && (bitValues == 0)) + { + ret = (bitMask != 0) ? COMMON_ERROR_COMPARISON_PASSED : COMMON_ERROR_COMPARISON_FAILED; + } + else + { + ret = ((((*byte) & (bitValues & bitMask)) | ((~(*byte)) & ((~bitValues) & bitMask))) & bitMask) ? + COMMON_ERROR_COMPARISON_PASSED : COMMON_ERROR_COMPARISON_FAILED; + } + } + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; +} + +int Common_Byte_Swap(char * data, const size_t dataLength) +{ + /* Init ret. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + size_t x = 0; /* Counter used in the swap loop. */ + char tempByte = '\0'; /* Temporary memory storage for a byte being swapped out. */ + + /* Check for invalid arguments. */ + if ((data != NULL) && ((dataLength % 2) == 0)) + { + /* Begin swap loop. */ + for (x = 0; (x < (dataLength / 2)); x++) + { + /* + * Each bit is swapped with it's partner on the other side of the array. + * I.e. Each byte from x distance from the start of the array is swapped + * with the byte x distance from the end of the array. + */ + tempByte = data[x]; + data[x] = data[((dataLength - 1) - x)]; + data[((dataLength - 1) - x)] = tempByte; + } + + /* Done! */ + ret = COMMON_ERROR_SUCCESS; + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; +} + +int Common_Print_Bytes_To_CString(const char * data, const size_t dataLength, char ** retStr, size_t * retStrSize, const unsigned int base, const size_t width, const char fillValue, const bool spaceBetweenBytes) +{ +/* Define the size of the output values array. */ +#define MSYSOUTPUTVALUESSIZE 17 + + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + size_t x = 0; /* Counter used in the print and spacing loops. */ + size_t byteValueCount = 0; /* Used to keep track of how many bytes we have outputted for the current byte. */ + unsigned char currentByte = '\0'; /* Temporary value used to store the current byte we are working on. */ + size_t outputValue = 0; /* The value that we need to write into the output buffer. (Calculated from currentValue.) */ + char * outputBuffer = NULL; /* Pointer to the c-string that will be given back to the caller. */ + char * previousOutputBuffer = NULL; /* Temporary pointer used to copy previously generated data into the current outputBuffer. */ + const char outputValues[MSYSOUTPUTVALUESSIZE] = "0123456789ABCDEF"; /* C-String used to map a generated value to it's corresponding character. */ + size_t outputBufferSize = 1; /* Current size of the outputBuffer. Set to one by default to allow the string to be NULL terminated. */ + + /* Check for invalid arguments. */ + if ((data != NULL) && (dataLength > 0) && (retStr != NULL) && (retStrSize != NULL) && (base >= 2) && (base <= 16)) + { + /* Begin data print loop. */ + for (x = 0; ((x < dataLength) && (ret == COMMON_ERROR_UNKNOWN_ERROR)); x++) + { + /* Copy current value. */ + currentByte = (data[((dataLength - 1) - x)]); + + /* Reset byte value count. */ + byteValueCount = 0; + + /* Begin value parsing loop. */ + do + { + /* Read the current byte's value from right to left. (Mod is a reduction operation.) */ + outputValue = (currentByte % base); + + /* Copy the current buffer's pointer because we are about to create a new one. */ + previousOutputBuffer = outputBuffer; + + /* Increment the size of the new buffer. */ + outputBufferSize++; + + /* Allocate the new buffer. */ + outputBuffer = (char*)malloc(outputBufferSize); + + /* Check for successful memory allocation. */ + if (outputBuffer != NULL) + { + /* Blank out the new buffer. */ + memset(outputBuffer, '\0', outputBufferSize); + + /* Set the first value as the previous data comes after it. */ + if ((outputValue >= 0) && (outputValue < MSYSOUTPUTVALUESSIZE)) + { + outputBuffer[0] = outputValues[outputValue]; + + /* If we have any previous data we need to copy it into the new buffer and deallocate the previous one. */ + if (previousOutputBuffer != NULL) + { + memcpy((outputBuffer + 1), previousOutputBuffer, (outputBufferSize - 1)); + free(previousOutputBuffer); + previousOutputBuffer = NULL; + } + + /* Increment byte value count. */ + byteValueCount++; + + /* Get the next value by chopping off the "ones place", aka divide by the current base. */ + currentByte /= base; + } + else + { + /* Invalid byte value. */ + ret = COMMON_ERROR_RANGE_ERROR; + } + } + else + { + /* Could not allocate memory for output buffer. */ + ret = COMMON_ERROR_MEMORY_ERROR; + } + }while ((currentByte) && (ret == COMMON_ERROR_UNKNOWN_ERROR)); + + /* Check and see if the generated values used up all of the requested width. */ + if ((ret == COMMON_ERROR_UNKNOWN_ERROR) && (outputBuffer != NULL) && (byteValueCount < width)) + { + /* Copy the current buffer's pointer because we are about to create a new one. */ + previousOutputBuffer = outputBuffer; + + /* Increment the output buffer size by the remaining filler we need to add. */ + outputBufferSize += (width - byteValueCount); + + /* Allocate the new buffer. */ + outputBuffer = (char*)malloc(outputBufferSize); + + /* Check for successful memory allocation. */ + if (outputBuffer != NULL) + { + /* Blank out the new buffer. */ + memset(outputBuffer, '\0', outputBufferSize); + + /* Put in our filler. */ + memset(outputBuffer, fillValue, (width - byteValueCount)); + + /* If we have any previous data we need to copy it into the new buffer and deallocate the previous one. */ + if (previousOutputBuffer != NULL) + { + memcpy((outputBuffer + (width - byteValueCount)), previousOutputBuffer, (outputBufferSize - (width - byteValueCount))); + free(previousOutputBuffer); + previousOutputBuffer = NULL; + } + } + else + { + /* Could not allocate memory for output buffer. */ + ret = COMMON_ERROR_MEMORY_ERROR; + } + } + + /* Insert spacing if needed. */ + if ((spaceBetweenBytes) && (ret == COMMON_ERROR_UNKNOWN_ERROR) && (outputBuffer != NULL) && ((x + 1) < dataLength)) + { + /* Copy the current buffer's pointer because we are about to create a new one. */ + previousOutputBuffer = outputBuffer; + + /* Increment the output buffer size. */ + outputBufferSize++; + + /* Allocate the new buffer. */ + outputBuffer = (char*)malloc(outputBufferSize); + + /* Check for successful memory allocation. */ + if (outputBuffer != NULL) + { + /* Blank out the new buffer. */ + memset(outputBuffer, '\0', outputBufferSize); + + /* Insert our space. */ + outputBuffer[0] = ' '; + + /* Copy the original buffer. */ + memcpy((outputBuffer + 1), previousOutputBuffer, (outputBufferSize - 1)); + } + else + { + /* Could not allocate memory for output buffer. */ + ret = COMMON_ERROR_MEMORY_ERROR; + } + } + } + + /* Check for NULL output buffer. */ + if ((ret == COMMON_ERROR_UNKNOWN_ERROR) && (outputBuffer != NULL) && (outputBufferSize > 0)) + { + /* Copy the outputBuffer pointer to retStr. */ + (*retStr) = outputBuffer; + + /* Copy outputBufferSize to retStrSize. */ + (*retStrSize) = outputBufferSize; + + /* Done! */ + ret = COMMON_ERROR_SUCCESS; + } + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; + +/* Undefine the size of the output values array. */ +#undef MSYSOUTPUTVALUESSIZE +} + +void Common_Deallocate_Print_Bytes_CString(char ** str) +{ + /* Check for NULL. */ + if (str != NULL) + { + free((*str)); + (*str) = NULL; + } + + /* Exit function. */ + return; +} + +int Common_Print_Bytes_In_Hex(const char * data, const size_t dataLength, char ** retStr, size_t * retStrSize, const bool spaceBetweenBytes) +{ + return Common_Print_Bytes_To_CString(data, dataLength, retStr, retStrSize, 16, 2, '0', spaceBetweenBytes); +} + +int Common_Print_Bytes_In_Binary(const char * data, const size_t dataLength, char ** retStr, size_t * retStrSize, const bool spaceBetweenBytes) +{ + return Common_Print_Bytes_To_CString(data, dataLength, retStr, retStrSize, 2, 8, '0', spaceBetweenBytes); +} + +int Common_Print_Bytes_In_Decimal(const char * data, const size_t dataLength, char ** retStr, size_t * retStrSize, const bool spaceBetweenBytes) +{ + return Common_Print_Bytes_To_CString(data, dataLength, retStr, retStrSize, 10, 8, '0', spaceBetweenBytes); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ diff --git a/src/Common/Src/Byte_Order/Byte_Order.h b/src/Common/Src/Byte_Order/Byte_Order.h new file mode 100644 index 0000000..10a5bc1 --- /dev/null +++ b/src/Common/Src/Byte_Order/Byte_Order.h @@ -0,0 +1,215 @@ +/*! + Multiverse Engine Project 03/6/2015 Common Byte_Order.h + + Copyright (C) 2015 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Include guard. */ +#ifndef MSYS_BYTE_ORDER_H +#define MSYS_BYTE_ORDER_H + +/* Check for C++ compiler. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Define Endianness Result Values. */ +#define MSYS_BIG_ENDIAN 0 +#define MSYS_LITTLE_ENDIAN 1 +#define MSYS_UNKNOWN_ENDIANNESS 2 + +/* Pull in DLL_PORT.h */ +#include "../../../DLL_PORT.h" /* Defines MSYS_DLL_EXPORT, and MSYS_DLL_IMPORT_TEMPLATE. */ + +/* Define bool. */ +#if _MSC_FULL_VER && _MSC_FULL_VER < 180031101 +#include "../../../stdbool.h" /* Older versions of Visual C don't support the C99 stdbool header. So we have to fake one. */ +#else +#include +#endif + +/* External headers. */ +#include /* Defines NULL. */ +#include /* Defines malloc(), free(). */ +#include /* Defines memset(), memcpy(). */ + +/* Internal headers. */ +#include "../Error_Handler/Common_Error_Handler_Error_Codes.h" /* Defines the error codes. */ +#include "Byte_Order_Integers.h" +#include "Byte_Order_Floating_Points.h" + +/*! + * int Byte_Order_Bit_Comparison(const char * byte, const char bitMask, const char bitValues) + * + * Compares the given byte's bits to the given bitValues using bitMask to define what bits to compare. + * + * I.e. This function compares bits to see if they are equal, using the bitMask to determine what + * bits to actually compare. + * + * Example: If bitMask is 11000000, then only the first two bits are checked. So to make a truth table: + * + * byte: bitMask: bitValues: Result: + * 11000000 11000000 11000000 TRUE (The checked values in byte and bitValues are identical.) + * 10000000 11000000 10000000 TRUE (The checked first and second bits are identical.) + * 01110010 00110010 10110010 TRUE (The checked 3rd, 4th, and 7th bits are identical.) + * 11000100 11000000 11000000 TRUE (Extra bit in byte is not checked.) + * 11000000 11000000 11000100 TRUE (Extra bit in bitValues is not checked.) + * 01000000 11000000 11000000 FALSE (byte does not match bitValues.) + * 11000000 11000000 10000000 FALSE (bitValues does not match byte.) + * 00000000 00000000 00000000 FALSE (No bits are defined to check.) + * 00000000 00110010 00000000 TRUE (Third, forth, and 7th bits are identical. + * (Hardcoded zero check, for consistancy with other results.)) + * 00000000 11111111 00000000 TRUE (Checking all bits, byte and bitValues are both zero. + * (Hardcoded zero check, for consistancy with other results.)) + * + * A note about checking for zero bits: + * For consistancy with the other results, in the event an all zero byte and bitValues is given + * to this function, a hard coded check is inserted to return COMMON_ERROR_COMPARISON_PASSED if + * the given bitMask is not equal to zero. Otherwise it returns COMMON_ERROR_COMPARISON_FAILED. + * This contradicts what would be expected from a binary AND operation and callers of this + * function should therefore be aware of it and check for this result. + * (Normally, a binary AND operation on an all zero set of operands would give a FALSE result. + * The best antidote I can give to deal with this function's inconsistancy is: + * It checks the given bits to see if they match, if given to a non-programmer, what would they + * think the result should be? + * Answer: (0 == 0) is TRUE, so the function should return TRUE.") + * + * Returns COMMON_ERROR_COMPARISON_PASSED if the checked bits match. + * Returns COMMON_ERROR_COMPARISON_FAILED if the checked bits do NOT match. + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer to char is invalid. + * Otherwise returns the approperite error code. + */ +MSYS_DLL_EXPORT int Byte_Order_Bit_Comparison(const char * byte, const char bitMask, const char bitValues); + +/*! + * int Common_Byte_Swap(char * data, const size_t dataLength) + * + * Swaps the given bytes by swapping each byte + * with it's complement on the other end of the + * byte string. + * + * I.e. Each byte from x distance from the start of the string is swapped + * with the byte x distance from the end of the string. + * + * Note: This function expects that the amount of data given to it + * is a multiple of 2. Also this function will alter the given + * data in-place. (I.e. If an error occurs, the data WILL be altered.) + * + * Returns COMMON_ERROR_SUCCESS if swapping was successful. + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is + * NULL, or if the data length is not a multiple of 2. + * + * Otherwise returns the appropriate error code. + */ +MSYS_DLL_EXPORT int Common_Byte_Swap(char * data, const size_t dataLength); + +/*! + * int Common_Print_Bytes_To_CString(const char * data, const size_t dataLength, char ** retStr, size_t * retStrSize, const unsigned int base, + * const size_t width, const char fillValue, const bool spaceBetweenBytes) + * + * Converts a given byte string to a printable (NULL-terminated) and human-readable string in the given base. + * + * @pram data: the byte string to convert. + * @pram dataLength: the length of the byte string. + * @pram retStr: a double pointer that will point to the converted string. + * @pram retStrSize: the size of the generated string. + * @pram base: the numerical base to convert each byte to. + * + * @pram width: the minimal number of values to print for each byte. (Note the minimal keyword. The value will not be truncated if it + * requires more than width characters to represent it. This is solely to make smaller values take up more space for more uniform value + * representation.) + * + * @pram fillValue: the value printed in the converted string to take up the extra space, when a byte's value representation is smaller + * than the given width. (E.x. the byte value is 0, width is 3, and fillValue is '.': "..0" would be the result.) + * + * @pram spaceBetweenBytes: Whether or not to insert a space character after each of the converted byte values. (Readability.) + * + * WARNING: If retStr is non-NULL when this function is called, and this function returns COMMON_ERROR_SUCCESS, then the pointer will + * be overwritten without being deallocated. If you need that pointer to deallocate it later, you should copy it elsewhere before calling + * this function. + * + * Note: To deallocate the returned string from this function, pass the returned string to Common_Deallocate_Print_Bytes_CString(). + * + * Returns COMMON_ERROR_SUCCESS if the conversion is successful. + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointers are NULL, or if the given base is not a value between 2 and 16. + * Returns COMMON_ERROR_MEMORY_ERROR if a memory allocation fails. + * + * In case of error, (the returned error code is not COMMON_ERROR_SUCCESS, then the given arguments will NOT be altered by this function. + */ +MSYS_DLL_EXPORT int Common_Print_Bytes_To_CString(const char * data, const size_t dataLength, char ** retStr, size_t * retStrSize, const unsigned int base, const size_t width, const char fillValue, const bool spaceBetweenBytes); + +/*! + * void Common_Deallocate_Print_Bytes_CString(char ** str) + * + * Deallocates the given c-string and sets the given pointer to char to NULL. + * + * Note: This function is a destructor function for strings made by Common_Print_Bytes_To_CString() and + * should ONLY be used for that purpose. The behaviour for using this function to deallocate other allocations is undefined. + * + * This function has no return. If a given pointer is NULL, this function will silently fail. + */ +MSYS_DLL_EXPORT void Common_Deallocate_Print_Bytes_CString(char ** str); + +/*! + * int Common_Print_Bytes_In_Hex(const char * data, const size_t dataLength, char ** retStr, size_t * retStrSize, const bool spaceBetweenBytes) + * + * Wrapper function around Common_Print_Bytes_To_CString() for converting a byte string to a human-readable hexadecimal string. + * Example output: ("001FAC" if spacing is disabled, "00 1F AC" if spacing is enabled.) + * + * Note: This function is to make calls shorter, if you want more control over the output, call Common_Print_Bytes_To_CString() directly. + * + * All arguments and return values are identical to their Common_Print_Bytes_To_CString() counterparts. See Common_Print_Bytes_To_CString() + * for their descriptions. + */ +MSYS_DLL_EXPORT int Common_Print_Bytes_In_Hex(const char * data, const size_t dataLength, char ** retStr, size_t * retStrSize, const bool spaceBetweenBytes); + +/*! + * int Common_Print_Bytes_In_Binary(const char * data, const size_t dataLength, char ** retStr, size_t * retStrSize, + * const bool spaceBetweenBytes) + * + * Wrapper function around Common_Print_Bytes_To_CString() for converting a byte string to a human-readable binary string. + * Example output: ("00000101000001010000010100000101" if spacing is disabled, "00000101 00000101 00000101 00000101" if spacing is enabled.) + * + * Note: This function is to make calls shorter, if you want more control over the output, call Common_Print_Bytes_To_CString() directly. + * + * All arguments and return values are identical to their Common_Print_Bytes_To_CString() counterparts. See Common_Print_Bytes_To_CString() + * for their descriptions. + */ +MSYS_DLL_EXPORT int Common_Print_Bytes_In_Binary(const char * data, const size_t dataLength, char ** retStr, size_t * retStrSize, const bool spaceBetweenBytes); + +/*! +* int Common_Print_Bytes_In_Decimal(const char * data, const size_t dataLength, char ** retStr, size_t * retStrSize, +* const bool spaceBetweenBytes) +* +* Wrapper function around Common_Print_Bytes_To_CString() for converting a byte string to a human-readable decimal string. +* Example output: ("10012" if spacing is disabled, "10 0 12" if spacing is enabled.) +* +* Note: This function is to make calls shorter, if you want more control over the output, call Common_Print_Bytes_To_CString() directly. +* +* All arguments and return values are identical to their Common_Print_Bytes_To_CString() counterparts. See Common_Print_Bytes_To_CString() +* for their descriptions. +*/ +MSYS_DLL_EXPORT int Common_Print_Bytes_In_Decimal(const char * data, const size_t dataLength, char ** retStr, size_t * retStrSize, const bool spaceBetweenBytes); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* MSYS_BYTE_ORDER_H */ + +/* End of Byte_Order.h */ diff --git a/src/Common/Src/Byte_Order/Byte_Order_Floating_Points.c b/src/Common/Src/Byte_Order/Byte_Order_Floating_Points.c new file mode 100644 index 0000000..45d40f9 --- /dev/null +++ b/src/Common/Src/Byte_Order/Byte_Order_Floating_Points.c @@ -0,0 +1,281 @@ +/*! + Multiverse Engine Project 09/6/2015 Common Byte_Order_Floating_Points.c + + Copyright (C) 2015 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Internal includes. */ +#include "Byte_Order.h" + +/* Check for C++ compiler. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +int Common_Host_To_Big_Endian_Float(float * f) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_FLOAT_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (f != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)f), sizeof (float)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Big_Endian_To_Host_Float(float * f) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_FLOAT_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (f != NULL) + { + /* + * Call Common_Byte_Swap(). + * + * (We could call Common_Host_To_Big_Endian_Float() here, but + * that would just repeat the calls above. Plus we may not be able + * to do that on all systems.) + */ + ret = Common_Byte_Swap(((char*)f), sizeof (float)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Host_To_Big_Endian_Double(double * d) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_DOUBLE_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (d != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)d), sizeof (double)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Big_Endian_To_Host_Double(double * d) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_DOUBLE_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (d != NULL) + { + /* + * Call Common_Byte_Swap(). + * + * (We could call Common_Host_To_Big_Endian_Double() here, but + * that would just repeat the calls above. Plus we may not be able + * to do that on all systems.) + */ + ret = Common_Byte_Swap(((char*)d), sizeof (double)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_FLOAT_Endianness_Check() +{ + /* Init vars. */ + int ret = MSYS_UNKNOWN_ENDIANNESS; /* The result of this function. */ + float t = 1.0; /* Variable to check. */ + + /* Cast t to a char string and see if the first 2 values are 0x3F80. */ + if ((((char*)&t)[0] == 0x3F) && ((((char*)&t)[1] == 0x80))) + { + /* The first 2 bytes are 0x3F80 so it's big endian. */ + ret = MSYS_BIG_ENDIAN; + } + else + { + /* + * The first check did not pass, so check and see if the last 2 bytes are 0x803F. + * If they are, then the host is little endian. + * + * Otherwise the host is using something like middle-endian to store + * the value, but we would need more checks to determine what exact + * kind of endianness the host is using. + */ + if ((((char*)&t)[(sizeof (float) - 1)] == 0x80) && ((((char*)&t)[(sizeof (float) - 2)] == 0x3F))) + { + /* It's little endian. */ + ret = MSYS_LITTLE_ENDIAN; + } + } + + /* Return the result. */ + return ret; +} + +int Common_DOUBLE_Endianness_Check() +{ + /* Init vars. */ + int ret = MSYS_UNKNOWN_ENDIANNESS; /* The result of this function. */ + double t = 1.0; /* Variable to check. */ + + /* Cast t to a char string and see if the first 2 values are 0x3FF0. */ + if ((((char*)&t)[0] == 0x3F) && ((((char*)&t)[1] == 0xF0))) + { + /* The first 2 bytes are 0x3F80 so it's big endian. */ + ret = MSYS_BIG_ENDIAN; + } + else + { + /* + * The first check did not pass, so check and see if the last 2 bytes are 0xF03F. + * If they are, then the host is little endian. + * + * Otherwise the host is using something like middle-endian to store + * the value, but we would need more checks to determine what exact + * kind of endianness the host is using. + */ + if ((((char*)&t)[(sizeof (double) - 1)] == 0xF0) && ((((char*)&t)[(sizeof (double) - 2)] == 0x3F))) + { + /* It's little endian. */ + ret = MSYS_LITTLE_ENDIAN; + } + } + + /* Return the result. */ + return ret; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ diff --git a/src/Common/Src/Byte_Order/Byte_Order_Floating_Points.h b/src/Common/Src/Byte_Order/Byte_Order_Floating_Points.h new file mode 100644 index 0000000..8bcd0c5 --- /dev/null +++ b/src/Common/Src/Byte_Order/Byte_Order_Floating_Points.h @@ -0,0 +1,176 @@ +/*! + Multiverse Engine Project 09/6/2015 Common Byte_Order_Floating_Points.h + + Copyright (C) 2015 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Include guard. */ +#ifndef MSYS_BYTE_ORDER_FLAOTING_POINTS_H +#define MSYS_BYTE_ORDER_FLAOTING_POINTS_H + +/* Make sure we are not included directly. */ +#ifndef MSYS_BYTE_ORDER_H +#error "You should not include __FILE__ directly, it is included automatically by Byte_Order.h, remove this include. Aborting build." +#endif + +/* Check for C++ compiler. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*! + * int Common_Host_To_Big_Endian_Float(float * f) + * + * Converts a given FLOAT value from the host's endianness + * to Big Endian format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Host_To_Big_Endian_Float(float * f); + +/*! + * int Common_Big_Endian_To_Host_Float(float * f) + * + * Converts a given FLOAT value from Big Endian format + * to the host's endianness format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Big_Endian_To_Host_Float(float * f); + +/*! + * int Common_Host_To_Big_Endian_DOUBLE(double * d) + * + * Converts a given DOUBLE value from the host's endianness + * to Big Endian format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Host_To_Big_Endian_Double(double * d); + +/*! + * int Common_Big_Endian_To_Host_Double(double * d) + * + * Converts a given DOUBLE value from Big Endian format + * to the host's endianness format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Big_Endian_To_Host_Double(double * d); + +/*! + * General Definitions for the Common_*_Endianness_Check() functions: + * + * The functions below all contain the same returns, + * and purpose. + */ + +/*! + * int Common_FLOAT_Endianness_Check() + * + * Template function which checks the host's endianness for the + * FLOAT data type. + * + * Note: This function is the equivalent of calling + * DataProcess_Endianness_Check() with a signed FLOAT argument. + * This function is here for the purpose of making it easier + * to use C code. + * + * Returns MSYS_BIG_ENDIAN if the given data type is stored as big + * endian on the host machine. + * + * Returns MSYS_LITTLE_ENDIAN if the given data type stored as little + * endian on the host machine. + * + * Returns MSYS_UNKNOWN_ENDIANNESS if the given data type's byte ordering + * is unknown for the given host. + */ +MSYS_DLL_EXPORT int Common_FLOAT_Endianness_Check(); + +/*! + * int Common_DOUBLE_Endianness_Check() + * + * Template function which checks the host's endianness for the + * DOUBLE data type. + * + * Note: This function is the equivalent of calling + * DataProcess_Endianness_Check() with a signed DOUBLE argument. + * This function is here for the purpose of making it easier + * to use C code. + * + * Returns MSYS_BIG_ENDIAN if the given data type is stored as big + * endian on the host machine. + * + * Returns MSYS_LITTLE_ENDIAN if the given data type stored as little + * endian on the host machine. + * + * Returns MSYS_UNKNOWN_ENDIANNESS if the given data type's byte ordering + * is unknown for the given host. + */ +MSYS_DLL_EXPORT int Common_DOUBLE_Endianness_Check(); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* MSYS_BYTE_ORDER_FLAOTING_POINTS_H */ + +/* End of Byte_Order_Floating_Points.h */ diff --git a/src/Common/Src/Byte_Order/Byte_Order_Integers.c b/src/Common/Src/Byte_Order/Byte_Order_Integers.c new file mode 100644 index 0000000..263e952 --- /dev/null +++ b/src/Common/Src/Byte_Order/Byte_Order_Integers.c @@ -0,0 +1,1340 @@ +/*! + Multiverse Engine Project 09/6/2015 Common Byte_Order_Integers.c + + Copyright (C) 2015 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Internal includes. */ +#include "Byte_Order.h" + +/* Check for C++ compiler. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +int Common_Host_To_Big_Endian_UChar(unsigned char * uc) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_UCHAR_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (uc != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)uc), sizeof (unsigned char)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Big_Endian_To_Host_UChar(unsigned char * uc) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_UCHAR_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (uc != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)uc), sizeof (unsigned char)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Host_To_Big_Endian_Char(char * c) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_CHAR_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (c != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)c), sizeof (char)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Big_Endian_To_Host_Char(char * c) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_CHAR_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (c != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)c), sizeof (char)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Host_To_Big_Endian_UShort(unsigned short * us) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_USHORT_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (us != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)us), sizeof (unsigned short)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Big_Endian_To_Host_UShort(unsigned short * us) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_USHORT_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (us != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)us), sizeof (unsigned short)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Host_To_Big_Endian_Short(short * s) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_SHORT_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (s != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)s), sizeof (short)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Big_Endian_To_Host_Short(short * s) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_SHORT_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (s != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)s), sizeof (short)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Host_To_Big_Endian_UInt(unsigned int * ui) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_UINT_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (ui != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)ui), sizeof (unsigned int)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Big_Endian_To_Host_UInt(unsigned int * ui) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_UINT_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (ui != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)ui), sizeof (unsigned int)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Host_To_Big_Endian_Int(int * i) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_INT_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (i != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)i), sizeof (int)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Big_Endian_To_Host_Int(int * i) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_INT_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (i != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)i), sizeof (int)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Host_To_Big_Endian_ULong(unsigned long * ul) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_ULONG_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (ul != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)ul), sizeof (unsigned long)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Big_Endian_To_Host_ULong(unsigned long * ul) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_ULONG_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (ul != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)ul), sizeof (unsigned long)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Host_To_Big_Endian_Long(long * l) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_LONG_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (l != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)l), sizeof (long)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Big_Endian_To_Host_Long(long * l) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_LONG_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (l != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)l), sizeof (long)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Host_To_Big_Endian_ULong_Long(unsigned long long * ull) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_ULONG_LONG_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (ull != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)ull), sizeof (unsigned long long)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Big_Endian_To_Host_ULong_Long(unsigned long long * ull) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_ULONG_LONG_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (ull != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)ull), sizeof (unsigned long long)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Host_To_Big_Endian_Long_Long(long long * ll) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_LONG_LONG_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (ll != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)ll), sizeof (long long)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Big_Endian_To_Host_Long_Long(long long * ll) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_LONG_LONG_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (ll != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)ll), sizeof (long long)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Host_To_Big_Endian_Size_T(size_t * st) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_SIZE_T_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (st != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)st), sizeof (size_t)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_Big_Endian_To_Host_Size_T(size_t * st) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + + /* Check host's endianness. */ + ret = Common_SIZE_T_Endianness_Check(); + if (ret != MSYS_BIG_ENDIAN) + { + /* Check for valid endianness. */ + if (ret == MSYS_LITTLE_ENDIAN) + { + /* Check for invalid arguments. */ + if (st != NULL) + { + /* Call Common_Byte_Swap(). */ + ret = Common_Byte_Swap(((char*)st), sizeof (size_t)); + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + } + else + { + /* Host endianness is unknown. Cannot convert unknown endianness. */ + ret = COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED; + } + } + else + { + /* + * This value should already be in the correct byte order, + * as the host is big endian. + */ + ret = COMMON_ERROR_SUCCESS; + } + + /* Exit function. */ + return ret; +} + +int Common_UCHAR_Endianness_Check() +{ + /* Init vars. */ + int ret = MSYS_UNKNOWN_ENDIANNESS; /* The result of this function. */ + unsigned char t = '\1'; /* Variable to check. */ + + /* Cast t to a char string and see if the result is 1. */ + if (((char*)&t)[0]) + { + /* The first byte is 1 so it's little endian. */ + ret = MSYS_LITTLE_ENDIAN; + } + else + { + /* + * The first byte is 0 so, check and see if the last byte is non-zero. + * If it is, then the host is big endian. + * + * Otherwise the host is using something like middle-endian to store + * the value, but we would need more checks to determine what exact + * kind of endianness the host is using. + */ + if (((char*)&t)[((sizeof(t)) - 1)]) + { + /* It's big endian. */ + ret = MSYS_BIG_ENDIAN; + } + } + + /* Return the result. */ + return ret; +} + +int Common_CHAR_Endianness_Check() +{ + /* Init vars. */ + int ret = MSYS_UNKNOWN_ENDIANNESS; /* The result of this function. */ + char t = '\1'; /* Variable to check. */ + + /* Cast t to a char string and see if the result is 1. */ + if (((char*)&t)[0]) + { + /* The first byte is 1 so it's little endian. */ + ret = MSYS_LITTLE_ENDIAN; + } + else + { + /* + * The first byte is 0 so, check and see if the last byte is non-zero. + * If it is, then the host is big endian. + * + * Otherwise the host is using something like middle-endian to store + * the value, but we would need more checks to determine what exact + * kind of endianness the host is using. + */ + if (((char*)&t)[((sizeof(t)) - 1)]) + { + /* It's big endian. */ + ret = MSYS_BIG_ENDIAN; + } + } + + /* Return the result. */ + return ret; +} + +int Common_USHORT_Endianness_Check() +{ + /* Init vars. */ + int ret = MSYS_UNKNOWN_ENDIANNESS; /* The result of this function. */ + unsigned short t = 1; /* Variable to check. */ + + /* Cast t to a char string and see if the result is 1. */ + if (((char*)&t)[0]) + { + /* The first byte is 1 so it's little endian. */ + ret = MSYS_LITTLE_ENDIAN; + } + else + { + /* + * The first byte is 0 so, check and see if the last byte is non-zero. + * If it is, then the host is big endian. + * + * Otherwise the host is using something like middle-endian to store + * the value, but we would need more checks to determine what exact + * kind of endianness the host is using. + */ + if (((char*)&t)[((sizeof(t)) - 1)]) + { + /* It's big endian. */ + ret = MSYS_BIG_ENDIAN; + } + } + + /* Return the result. */ + return ret; +} + +int Common_SHORT_Endianness_Check() +{ + /* Init vars. */ + int ret = MSYS_UNKNOWN_ENDIANNESS; /* The result of this function. */ + short t = 1; /* Variable to check. */ + + /* Cast t to a char string and see if the result is 1. */ + if (((char*)&t)[0]) + { + /* The first byte is 1 so it's little endian. */ + ret = MSYS_LITTLE_ENDIAN; + } + else + { + /* + * The first byte is 0 so, check and see if the last byte is non-zero. + * If it is, then the host is big endian. + * + * Otherwise the host is using something like middle-endian to store + * the value, but we would need more checks to determine what exact + * kind of endianness the host is using. + */ + if (((char*)&t)[((sizeof(t)) - 1)]) + { + /* It's big endian. */ + ret = MSYS_BIG_ENDIAN; + } + } + + /* Return the result. */ + return ret; +} + +int Common_UINT_Endianness_Check() +{ + /* Init vars. */ + int ret = MSYS_UNKNOWN_ENDIANNESS; /* The result of this function. */ + unsigned int t = 1; /* Variable to check. */ + + /* Cast t to a char string and see if the result is 1. */ + if (((char*)&t)[0]) + { + /* The first byte is 1 so it's little endian. */ + ret = MSYS_LITTLE_ENDIAN; + } + else + { + /* + * The first byte is 0 so, check and see if the last byte is non-zero. + * If it is, then the host is big endian. + * + * Otherwise the host is using something like middle-endian to store + * the value, but we would need more checks to determine what exact + * kind of endianness the host is using. + */ + if (((char*)&t)[((sizeof(t)) - 1)]) + { + /* It's big endian. */ + ret = MSYS_BIG_ENDIAN; + } + } + + /* Return the result. */ + return ret; +} + +int Common_INT_Endianness_Check() +{ + /* Init vars. */ + int ret = MSYS_UNKNOWN_ENDIANNESS; /* The result of this function. */ + int t = 1; /* Variable to check. */ + + /* Cast t to a char string and see if the result is 1. */ + if (((char*)&t)[0]) + { + /* The first byte is 1 so it's little endian. */ + ret = MSYS_LITTLE_ENDIAN; + } + else + { + /* + * The first byte is 0 so, check and see if the last byte is non-zero. + * If it is, then the host is big endian. + * + * Otherwise the host is using something like middle-endian to store + * the value, but we would need more checks to determine what exact + * kind of endianness the host is using. + */ + if (((char*)&t)[((sizeof(t)) - 1)]) + { + /* It's big endian. */ + ret = MSYS_BIG_ENDIAN; + } + } + + /* Return the result. */ + return ret; +} + +int Common_ULONG_Endianness_Check() +{ + /* Init vars. */ + int ret = MSYS_UNKNOWN_ENDIANNESS; /* The result of this function. */ + unsigned long t = 1; /* Variable to check. */ + + /* Cast t to a char string and see if the result is 1. */ + if (((char*)&t)[0]) + { + /* The first byte is 1 so it's little endian. */ + ret = MSYS_LITTLE_ENDIAN; + } + else + { + /* + * The first byte is 0 so, check and see if the last byte is non-zero. + * If it is, then the host is big endian. + * + * Otherwise the host is using something like middle-endian to store + * the value, but we would need more checks to determine what exact + * kind of endianness the host is using. + */ + if (((char*)&t)[((sizeof(t)) - 1)]) + { + /* It's big endian. */ + ret = MSYS_BIG_ENDIAN; + } + } + + /* Return the result. */ + return ret; +} + +int Common_LONG_Endianness_Check() +{ + /* Init vars. */ + int ret = MSYS_UNKNOWN_ENDIANNESS; /* The result of this function. */ + long t = 1; /* Variable to check. */ + + /* Cast t to a char string and see if the result is 1. */ + if (((char*)&t)[0]) + { + /* The first byte is 1 so it's little endian. */ + ret = MSYS_LITTLE_ENDIAN; + } + else + { + /* + * The first byte is 0 so, check and see if the last byte is non-zero. + * If it is, then the host is big endian. + * + * Otherwise the host is using something like middle-endian to store + * the value, but we would need more checks to determine what exact + * kind of endianness the host is using. + */ + if (((char*)&t)[((sizeof(t)) - 1)]) + { + /* It's big endian. */ + ret = MSYS_BIG_ENDIAN; + } + } + + /* Return the result. */ + return ret; +} + +int Common_ULONG_LONG_Endianness_Check() +{ + /* Init vars. */ + int ret = MSYS_UNKNOWN_ENDIANNESS; /* The result of this function. */ + unsigned long long t = 1; /* Variable to check. */ + + /* Cast t to a char string and see if the result is 1. */ + if (((char*)&t)[0]) + { + /* The first byte is 1 so it's little endian. */ + ret = MSYS_LITTLE_ENDIAN; + } + else + { + /* + * The first byte is 0 so, check and see if the last byte is non-zero. + * If it is, then the host is big endian. + * + * Otherwise the host is using something like middle-endian to store + * the value, but we would need more checks to determine what exact + * kind of endianness the host is using. + */ + if (((char*)&t)[((sizeof(t)) - 1)]) + { + /* It's big endian. */ + ret = MSYS_BIG_ENDIAN; + } + } + + /* Return the result. */ + return ret; +} + +int Common_LONG_LONG_Endianness_Check() +{ + /* Init vars. */ + int ret = MSYS_UNKNOWN_ENDIANNESS; /* The result of this function. */ + long long t = 1; /* Variable to check. */ + + /* Cast t to a char string and see if the result is 1. */ + if (((char*)&t)[0]) + { + /* The first byte is 1 so it's little endian. */ + ret = MSYS_LITTLE_ENDIAN; + } + else + { + /* + * The first byte is 0 so, check and see if the last byte is non-zero. + * If it is, then the host is big endian. + * + * Otherwise the host is using something like middle-endian to store + * the value, but we would need more checks to determine what exact + * kind of endianness the host is using. + */ + if (((char*)&t)[((sizeof(t)) - 1)]) + { + /* It's big endian. */ + ret = MSYS_BIG_ENDIAN; + } + } + + /* Return the result. */ + return ret; +} + +int Common_SIZE_T_Endianness_Check() +{ + /* Init vars. */ + int ret = MSYS_UNKNOWN_ENDIANNESS; /* The result of this function. */ + size_t t = 1; /* Variable to check. */ + + /* Cast t to a char string and see if the result is 1. */ + if (((char*)&t)[0]) + { + /* The first byte is 1 so it's little endian. */ + ret = MSYS_LITTLE_ENDIAN; + } + else + { + /* + * The first byte is 0 so, check and see if the last byte is non-zero. + * If it is, then the host is big endian. + * + * Otherwise the host is using something like middle-endian to store + * the value, but we would need more checks to determine what exact + * kind of endianness the host is using. + */ + if (((char*)&t)[((sizeof(t)) - 1)]) + { + /* It's big endian. */ + ret = MSYS_BIG_ENDIAN; + } + } + + /* Return the result. */ + return ret; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ diff --git a/src/Common/Src/Byte_Order/Byte_Order_Integers.h b/src/Common/Src/Byte_Order/Byte_Order_Integers.h new file mode 100644 index 0000000..551f883 --- /dev/null +++ b/src/Common/Src/Byte_Order/Byte_Order_Integers.h @@ -0,0 +1,752 @@ +/*! + Multiverse Engine Project 09/6/2015 Common Byte_Order_Integers.h + + Copyright (C) 2015 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Include guard. */ +#ifndef MSYS_BYTE_ORDER_INTEGERS_H +#define MSYS_BYTE_ORDER_INTEGERS_H + +/* Make sure we are not included directly. */ +#ifndef MSYS_BYTE_ORDER_H +#error "You should not include __FILE__ directly, it is included automaticly by Byte_Order.h, remove this include. Aborting build." +#endif + +/* Check for C++ compiler. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*! + * int Common_Host_To_Big_Endian_UChar(unsigned char * uc) + * + * Converts a given unsigned CHAR value from the host's endianness + * to Big Endian format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Host_To_Big_Endian_UChar(unsigned char * uc); + +/*! + * int Common_Big_Endian_To_Host_UChar(unsigned char * uc) + * + * Converts a given unsigned CHAR value from the Big Endian format + * to the host's endianness format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Big_Endian_To_Host_UChar(unsigned char * uc); + +/*! + * int Common_Host_To_Big_Endian_Char(char * c) + * + * Converts a given CHAR value from the host's endianness + * to Big Endian format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Host_To_Big_Endian_Char(char * c); + +/*! + * int Common_Big_Endian_To_Host_Char(char * c) + * + * Converts a given CHAR value from the Big Endian format + * to the host's endianness format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Big_Endian_To_Host_Char(char * c); + +/*! + * int Common_Host_To_Big_Endian_UShort(unsigned short * us) + * + * Converts a given unsigned SHORT value from the host's endianness + * to Big Endian format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Host_To_Big_Endian_UShort(unsigned short * us); + +/*! + * int Common_Big_Endian_To_Host_UShort(unsigned short * us) + * + * Converts a given unsigned SHORT value from the Big Endian format + * to the host's endianness format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Big_Endian_To_Host_UShort(unsigned short * us); + +/*! + * int Common_Host_To_Big_Endian_Short(short * s) + * + * Converts a given SHORT value from the host's endianness + * to Big Endian format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Host_To_Big_Endian_Short(short * s); + +/*! + * int Common_Big_Endian_To_Host_Short(short * s) + * + * Converts a given SHORT value from the Big Endian format + * to the host's endianness format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Big_Endian_To_Host_Short(short * s); + +/*! + * int Common_Host_To_Big_Endian_UInt(unsigned int * ui) + * + * Converts a given unsigned INT value from the host's endianness + * to Big Endian format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Host_To_Big_Endian_UInt(unsigned int * ui); + +/*! + * int Common_Big_Endian_To_Host_UInt(unsigned int * ui) + * + * Converts a given unsigned INT value from the Big Endian format + * to the host's endianness format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Big_Endian_To_Host_UInt(unsigned int * ui); + +/*! + * int Common_Host_To_Big_Endian_Int(int * i) + * + * Converts a given INT value from the host's endianness + * to Big Endian format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Host_To_Big_Endian_Int(int * i); + +/*! + * int Common_Big_Endian_To_Host_Int(int * i) + * + * Converts a given INT value from the Big Endian format + * to the host's endianness format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Big_Endian_To_Host_Int(int * i); + +/*! + * int Common_Host_To_Big_Endian_ULong(unsigned long * ul) + * + * Converts a given unsigned LONG value from the host's endianness + * to Big Endian format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Host_To_Big_Endian_ULong(unsigned long * ul); + +/*! + * int Common_Big_Endian_To_Host_ULong(unsigned long * ul) + * + * Converts a given unsigned LONG value from the Big Endian format + * to the host's endianness format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Big_Endian_To_Host_ULong(unsigned long * ul); + +/*! + * int Common_Host_To_Big_Endian_Long(long * l) + * + * Converts a given LONG value from the host's endianness + * to Big Endian format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Host_To_Big_Endian_Long(long * l); + +/*! + * int Common_Big_Endian_To_Host_Long(long * l) + * + * Converts a given LONG value from the Big Endian format + * to the host's endianness format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Big_Endian_To_Host_Long(long * l); + +/*! + * int Common_Host_To_Big_Endian_ULong_Long(unsigned long long * ull) + * + * Converts a given unsigned LONG LONG value from the host's endianness + * to Big Endian format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Host_To_Big_Endian_ULong_Long(unsigned long long * ull); + +/*! + * int Common_Big_Endian_To_Host_ULong_Long(unsigned long long * ull) + * + * Converts a given unsigned LONG LONG value from the Big Endian format + * to the host's endianness format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Big_Endian_To_Host_ULong_Long(unsigned long long * ull); + +/*! + * int Common_Host_To_Big_Endian_Long_Long(long long * ull) + * + * Converts a given LONG LONG value from the host's endianness + * to Big Endian format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Host_To_Big_Endian_Long_Long(long long * ll); + +/*! + * int Common_Big_Endian_To_Host_Long_Long(long long * ll) + * + * Converts a given LONG LONG value from the Big Endian format + * to the host's endianness format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Big_Endian_To_Host_Long_Long(long long * ll); + +/*! + * int Common_Host_To_Big_Endian_Size_T(size_t * st) + * + * Converts a given SIZE_T value from the host's endianness + * to Big Endian format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Host_To_Big_Endian_Size_T(size_t * st); + +/*! + * int Common_Big_Endian_To_Host_Size_T(size_t * st) + * + * Converts a given SIZE_T value from the Big Endian format + * to the host's endianness format. + * + * Returns COMMON_ERROR_SUCCESS, if the conversion is successful, + * (data will be converted after call returns), + * or if the host is a Big Endian host. (In such case no data alteration + * is performed.) + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * + * Returns COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED if the given data type's + * byte ordering is unknown for the given host. + * + * In case of error, (returned error code is not COMMON_ERROR_SUCCESS), + * all arguments will be left unaltered. + */ +MSYS_DLL_EXPORT int Common_Big_Endian_To_Host_Size_T(size_t * st); + +/*! + * General Definitions for the Common_*_Endianness_Check() functions: + * + * The functions below all contain the same returns, + * and purpose. + */ + +/*! + * int Common_UCHAR_Endianness_Check() + * + * Template function which checks the host's endianness for the + * UCHAR data type. + * + * Note: This function is the equivalent of calling + * DataProcess_Endianness_Check() with a unsigned CHAR argument. + * This function is here for the purpose of making it easier + * to use C code. + * + * Returns MSYS_BIG_ENDIAN if the given data type is stored as big + * endian on the host machine. + * + * Returns MSYS_LITTLE_ENDIAN if the given data type stored as little + * endian on the host machine. + * + * Returns MSYS_UNKNOWN_ENDIANNESS if the given data type's byte ordering + * is unknown for the given host. + */ +MSYS_DLL_EXPORT int Common_UCHAR_Endianness_Check(); + +/*! + * int Common_CHAR_Endianness_Check() + * + * Template function which checks the host's endianness for the + * UCHAR data type. + * + * Note: This function is the equivalent of calling + * DataProcess_Endianness_Check() with a CHAR argument. + * This function is here for the purpose of making it easier + * to use C code. + * + * Returns MSYS_BIG_ENDIAN if the given data type is stored as big + * endian on the host machine. + * + * Returns MSYS_LITTLE_ENDIAN if the given data type stored as little + * endian on the host machine. + * + * Returns MSYS_UNKNOWN_ENDIANNESS if the given data type's byte ordering + * is unknown for the given host. + */ +MSYS_DLL_EXPORT int Common_CHAR_Endianness_Check(); + +/*! + * int Common_USHORT_Endianness_Check() + * + * Template function which checks the host's endianness for the + * UCHAR data type. + * + * Note: This function is the equivalent of calling + * DataProcess_Endianness_Check() with a unsigned SHORT argument. + * This function is here for the purpose of making it easier + * to use C code. + * + * Returns MSYS_BIG_ENDIAN if the given data type is stored as big + * endian on the host machine. + * + * Returns MSYS_LITTLE_ENDIAN if the given data type stored as little + * endian on the host machine. + * + * Returns MSYS_UNKNOWN_ENDIANNESS if the given data type's byte ordering + * is unknown for the given host. + */ +MSYS_DLL_EXPORT int Common_USHORT_Endianness_Check(); + +/*! + * int Common_SHORT_Endianness_Check() + * + * Template function which checks the host's endianness for the + * UCHAR data type. + * + * Note: This function is the equivalent of calling + * DataProcess_Endianness_Check() with a SHORT argument. + * This function is here for the purpose of making it easier + * to use C code. + * + * Returns MSYS_BIG_ENDIAN if the given data type is stored as big + * endian on the host machine. + * + * Returns MSYS_LITTLE_ENDIAN if the given data type stored as little + * endian on the host machine. + * + * Returns MSYS_UNKNOWN_ENDIANNESS if the given data type's byte ordering + * is unknown for the given host. + */ +MSYS_DLL_EXPORT int Common_SHORT_Endianness_Check(); + +/*! + * int Common_UINT_Endianness_Check() + * + * Template function which checks the host's endianness for the + * UCHAR data type. + * + * Note: This function is the equivalent of calling + * DataProcess_Endianness_Check() with a unsigned INT argument. + * This function is here for the purpose of making it easier + * to use C code. + * + * Returns MSYS_BIG_ENDIAN if the given data type is stored as big + * endian on the host machine. + * + * Returns MSYS_LITTLE_ENDIAN if the given data type stored as little + * endian on the host machine. + * + * Returns MSYS_UNKNOWN_ENDIANNESS if the given data type's byte ordering + * is unknown for the given host. + */ +MSYS_DLL_EXPORT int Common_UINT_Endianness_Check(); + +/*! + * int Common_INT_Endianness_Check() + * + * Template function which checks the host's endianness for the + * UCHAR data type. + * + * Note: This function is the equivalent of calling + * DataProcess_Endianness_Check() with a INT argument. + * This function is here for the purpose of making it easier + * to use C code. + * + * Returns MSYS_BIG_ENDIAN if the given data type is stored as big + * endian on the host machine. + * + * Returns MSYS_LITTLE_ENDIAN if the given data type stored as little + * endian on the host machine. + * + * Returns MSYS_UNKNOWN_ENDIANNESS if the given data type's byte ordering + * is unknown for the given host. + */ +MSYS_DLL_EXPORT int Common_INT_Endianness_Check(); + +/*! + * int Common_ULONG_Endianness_Check() + * + * Template function which checks the host's endianness for the + * UCHAR data type. + * + * Note: This function is the equivalent of calling + * DataProcess_Endianness_Check() with a unsigned LONG argument. + * This function is here for the purpose of making it easier + * to use C code. + * + * Returns MSYS_BIG_ENDIAN if the given data type is stored as big + * endian on the host machine. + * + * Returns MSYS_LITTLE_ENDIAN if the given data type stored as little + * endian on the host machine. + * + * Returns MSYS_UNKNOWN_ENDIANNESS if the given data type's byte ordering + * is unknown for the given host. + */ +MSYS_DLL_EXPORT int Common_ULONG_Endianness_Check(); + +/*! + * int Common_LONG_Endianness_Check() + * + * Template function which checks the host's endianness for the + * UCHAR data type. + * + * Note: This function is the equivalent of calling + * DataProcess_Endianness_Check() with a LONG argument. + * This function is here for the purpose of making it easier + * to use C code. + * + * Returns MSYS_BIG_ENDIAN if the given data type is stored as big + * endian on the host machine. + * + * Returns MSYS_LITTLE_ENDIAN if the given data type stored as little + * endian on the host machine. + * + * Returns MSYS_UNKNOWN_ENDIANNESS if the given data type's byte ordering + * is unknown for the given host. + */ +MSYS_DLL_EXPORT int Common_LONG_Endianness_Check(); + +/*! + * int Common_ULONG_LONG_Endianness_Check() + * + * Template function which checks the host's endianness for the + * UCHAR data type. + * + * Note: This function is the equivalent of calling + * DataProcess_Endianness_Check() with a unsigned LONG LONG argument. + * This function is here for the purpose of making it easier + * to use C code. + * + * Returns MSYS_BIG_ENDIAN if the given data type is stored as big + * endian on the host machine. + * + * Returns MSYS_LITTLE_ENDIAN if the given data type stored as little + * endian on the host machine. + * + * Returns MSYS_UNKNOWN_ENDIANNESS if the given data type's byte ordering + * is unknown for the given host. + */ +MSYS_DLL_EXPORT int Common_ULONG_LONG_Endianness_Check(); + +/*! + * int Common_LONG_LONG_Endianness_Check() + * + * Template function which checks the host's endianness for the + * UCHAR data type. + * + * Note: This function is the equivalent of calling + * DataProcess_Endianness_Check() with a LONG LONG argument. + * This function is here for the purpose of making it easier + * to use C code. + * + * Returns MSYS_BIG_ENDIAN if the given data type is stored as big + * endian on the host machine. + * + * Returns MSYS_LITTLE_ENDIAN if the given data type stored as little + * endian on the host machine. + * + * Returns MSYS_UNKNOWN_ENDIANNESS if the given data type's byte ordering + * is unknown for the given host. + */ +MSYS_DLL_EXPORT int Common_LONG_LONG_Endianness_Check(); + +/*! + * int Common_SIZE_T_Endianness_Check() + * + * Template function which checks the host's endianness for the + * UCHAR data type. + * + * Note: This function is the equivalent of calling + * DataProcess_Endianness_Check() with a SIZE_T argument. + * This function is here for the purpose of making it easier + * to use C code. + * + * Returns MSYS_BIG_ENDIAN if the given data type is stored as big + * endian on the host machine. + * + * Returns MSYS_LITTLE_ENDIAN if the given data type stored as little + * endian on the host machine. + * + * Returns MSYS_UNKNOWN_ENDIANNESS if the given data type's byte ordering + * is unknown for the given host. + */ +MSYS_DLL_EXPORT int Common_SIZE_T_Endianness_Check(); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* MSYS_BYTE_ORDER_INTEGERS_H */ + +/* End of Byte_Order_Integers.h */ diff --git a/src/Common/Src/Byte_Order/CMakeLists.txt b/src/Common/Src/Byte_Order/CMakeLists.txt new file mode 100644 index 0000000..d97141a --- /dev/null +++ b/src/Common/Src/Byte_Order/CMakeLists.txt @@ -0,0 +1,14 @@ +# Set output directories. +set(LIBRARY_OUTPUT_PATH ${L_OUTPUT_DIR}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${O_OUTPUT_DIR}) + +# Define includes. +set (BYTE_ORDER_INCLUDES Byte_Order.c +Byte_Order_Floating_Points.c +Byte_Order_Integers.c) + +# Define static library. +add_library (Common_Byte_Order_Multiverse_Engine_Static STATIC ${BYTE_ORDER_INCLUDES}) + +# Define shared library. +add_library (Common_Byte_Order_Multiverse_Engine SHARED ${BYTE_ORDER_INCLUDES}) diff --git a/src/Common/Src/CMakeLists.txt b/src/Common/Src/CMakeLists.txt index 15d9c0b..7ba4e04 100644 --- a/src/Common/Src/CMakeLists.txt +++ b/src/Common/Src/CMakeLists.txt @@ -2,6 +2,12 @@ set(LIBRARY_OUTPUT_PATH ${L_OUTPUT_DIR}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${O_OUTPUT_DIR}) +# Create the Byte_Order library. +if (BUILD_BYTE_ORDER) + add_subdirectory(Byte_Order) + set (COMMON_BUILT_SHARED_LIBRARY_LIST ${COMMON_BUILT_SHARED_LIBRARY_LIST} Common_Byte_Order_Multiverse_Engine) + set (COMMON_BUILT_STATIC_LIBRARY_LIST ${COMMON_BUILT_STATIC_LIBRARY_LIST} Common_Byte_Order_Multiverse_Engine_Static) +endif (BUILD_BYTE_ORDER) # Create the mutexes library. if (BUILD_INTERNAL_MUTEX_SUPPORT) diff --git a/src/Common/Src/Dynamic_Library_Subsystem/CMakeLists.txt b/src/Common/Src/Dynamic_Library_Subsystem/CMakeLists.txt index 56eb522..3391a8b 100644 --- a/src/Common/Src/Dynamic_Library_Subsystem/CMakeLists.txt +++ b/src/Common/Src/Dynamic_Library_Subsystem/CMakeLists.txt @@ -7,12 +7,16 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${O_OUTPUT_DIR}) IF(${CMAKE_SYSTEM_NAME} MATCHES "Windows") # Building on windows. set(DYNAMIC_LIBRARY_SUBSYSTEM_INCLUDES Dynamic_Library_Subsystem_Data_Structures.c + Dynamic_Library_Subsystem_Data_Structures_Private_API.c + Dynamic_Library_Subsystem.c Dynamic_Library_Subsystem_Windows.c) unset(DYNAMIC_LIBRARY_SUBSYSTEM_LINK_LIBS) ELSEIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") # Building on Linux. set(DYNAMIC_LIBRARY_SUBSYSTEM_INCLUDES Dynamic_Library_Subsystem_Data_Structures.c + Dynamic_Library_Subsystem_Data_Structures_Private_API.c + Dynamic_Library_Subsystem.c Dynamic_Library_Subsystem_POSIX.c) set(DYNAMIC_LIBRARY_SUBSYSTEM_LINK_LIBS dl) @@ -25,8 +29,10 @@ ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Windows") # Actually build it. add_library(Dynamic_Library_Subsystem_Multiverse_Engine_Static STATIC ${DYNAMIC_LIBRARY_SUBSYSTEM_INCLUDES}) target_link_libraries(Dynamic_Library_Subsystem_Multiverse_Engine_Static ${DYNAMIC_LIBRARY_SUBSYSTEM_LINK_LIBS} -Common_Error_Handler_Multiverse_Engine_Static) +Common_Error_Handler_Multiverse_Engine_Static +Core_Multiverse_Engine_Static) add_library(Dynamic_Library_Subsystem_Multiverse_Engine SHARED ${DYNAMIC_LIBRARY_SUBSYSTEM_INCLUDES}) target_link_libraries(Dynamic_Library_Subsystem_Multiverse_Engine ${DYNAMIC_LIBRARY_SUBSYSTEM_LINK_LIBS} -Common_Error_Handler_Multiverse_Engine) +Common_Error_Handler_Multiverse_Engine +Core_Multiverse_Engine) diff --git a/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem.c b/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem.c new file mode 100644 index 0000000..d15b44e --- /dev/null +++ b/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem.c @@ -0,0 +1,622 @@ +/*! + Multiverse Engine Project 23/1/2016 Dynamic_Library_Subsystem Dynamic_Library_Subsystem.c + + Copyright (C) 2016 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Internal includes. */ +#include "Dynamic_Library_Subsystem.h" +#include "Dynamic_Library_Subsystem_Syscall.h" +#include "../Error_Handler/Common_Error_Handler_Structures.h" +#include "../Error_Handler/Common_Error_Handler_Error_Codes.h" +#include "../Error_Handler/Common_Error_Handler_Log_Channel_Defs.h" +#include "../../../Core/Src/DataProcess.h" + +/* Define the MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID macro. */ +#define MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID MSYS_ERROR_LOG_CHANNEL_DYNLIB + +/* Check for C++ Compiler. */ +#ifdef __cplusplus +/* Define extern C. */ +extern "C" { +#endif /* __cplusplus */ + + int Common_Dynamic_Library_Subsystem_Load_Library(const char * pathToLibrary, const size_t pathToLibraryLength, const bool reloadLibrary, Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; /* The result of calls to other engine functions. */ + char * tempPath = NULL; /* Used to verifiy that the path was stored in the management structure. */ + size_t tempPathLength = 0; /* Used to store the length of the tempPath string in bytes. */ + char * copiedPathFromStruct = NULL; /* Used to copy the path from the management structure during a reload. */ + size_t copiedPathLengthFromStruct = 0; /* Used to store the length of the tempPath string in bytes. */ + void * callResult = NULL; /* The result of the call the engine's syscall function. */ + + /* Check to see if the pointer to the management structure is valid. */ + if (lib != NULL) + { + /* Check to see if pathToLibrary is NULL. */ + if ((pathToLibrary != NULL) && (pathToLibraryLength > 0)) + { + /* Check to see if the library is loaded. */ + retFromCall = Common_Dynamic_Library_Subsystem_Get_IsLoaded_Loaded_Dynamic_Library(lib); + if ((retFromCall == COMMON_ERROR_FALSE) || (reloadLibrary)) + { + /* Check and see if the library is loaded. */ + if (retFromCall == COMMON_ERROR_TRUE) + { + /* Get the pathToLibrary pointer from the management structure. */ + retFromCall = Common_Dynamic_Library_Subsystem_Get_PathToLibrary_Loaded_Dynamic_Library(lib, &tempPath, &tempPathLength); + if (retFromCall == COMMON_ERROR_SUCCESS) + { + /* Check and see if the given pathToLibrary is from the lib structure. */ + if (tempPath == pathToLibrary) + { + /* Copy the length data. */ + copiedPathLengthFromStruct = tempPathLength; + + /* We need to copy the pathToLibrary data. */ + retFromCall = DataProcess_Reallocate_C_String(&copiedPathFromStruct, 0, copiedPathLengthFromStruct); + if ((retFromCall == COMMON_ERROR_SUCCESS) && (copiedPathFromStruct != NULL)) + { + /* Copy the path string. */ + memcpy(copiedPathFromStruct, tempPath, copiedPathLengthFromStruct); + } + else + { + /* Could not allocate memory for tempPath. */ + ret = ((retFromCall != COMMON_ERROR_SUCCESS) ? (retFromCall) : (COMMON_ERROR_INTERNAL_ERROR)); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Load_Library(): Memory allocation function returned: "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + } + + /* Reset tempPath and tempPathLength. */ + tempPath = NULL; + tempPathLength = 0; + } + + /* Call Unload_Library. */ + retFromCall = Common_Dynamic_Library_Subsystem_Unload_Library(lib); + } + else + { + /* Could not get the pathToLibrary pointer from the data structure. */ + ret = ((retFromCall != COMMON_ERROR_SUCCESS) ? (retFromCall) : (COMMON_ERROR_INTERNAL_ERROR)); + retFromCall = Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(lib, true); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Load_Library(): Unable to get the pathToLibrary pointer from the data structure."); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Engine call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(ret)); + if (retFromCall != COMMON_ERROR_SUCCESS) + { + /* Log additional error. */ + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Additionally, we could not set the error flag for the internal library structure. Engine Call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + } + } + } + else + { + /* Reset retFromCall. */ + retFromCall = COMMON_ERROR_UNKNOWN_ERROR; + } + + /* Only continue if the library was unloaded, or if we did not need to unload the library. */ + if ((retFromCall == COMMON_ERROR_UNKNOWN_ERROR) || (retFromCall == COMMON_ERROR_SUCCESS)) + { + /* Blank the values in lib. */ + Common_Dynamic_Library_Subsystem_Blank_Loaded_Dynamic_Library(lib); + + /* Copy the path string into lib. */ + retFromCall = Common_Dynamic_Library_Subsystem_Set_PathToLibrary_Loaded_Dynamic_Library(lib, ((copiedPathFromStruct == NULL) ? (pathToLibrary) : (copiedPathFromStruct)), ((copiedPathLengthFromStruct == 0) ? (pathToLibraryLength) : (copiedPathLengthFromStruct))); + if (retFromCall == COMMON_ERROR_SUCCESS) + { + /* Get the path back. */ + retFromCall = Common_Dynamic_Library_Subsystem_Get_PathToLibrary_Loaded_Dynamic_Library(lib, &tempPath, &tempPathLength); + if ((retFromCall == COMMON_ERROR_SUCCESS) && (tempPath != NULL) && (tempPathLength > 0)) + { + /* Call Syscall. */ + retFromCall = Common_Dynamic_Library_Subsystem_Load_Library_Syscall(tempPath, tempPathLength, &callResult); + if (retFromCall == COMMON_ERROR_SUCCESS) + { + /* Copy returned osSpecificPointerData to the management structure. */ + retFromCall = Common_Dynamic_Library_Subsystem_Set_OsSpecificPointerData_Loaded_Dynamic_Library(lib, callResult); + if (retFromCall == COMMON_ERROR_SUCCESS) + { + /* Set bIsLoaded. */ + retFromCall = Common_Dynamic_Library_Subsystem_Set_IsLoaded_Loaded_Dynamic_Library(lib, true); + if (retFromCall == COMMON_ERROR_SUCCESS) + { + /* Success. */ + ret = COMMON_ERROR_SUCCESS; + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Load_Library(): <"); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, tempPath); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "> loaded."); + } + else + { + /* Could not set is loaded flag. */ + ret = ((retFromCall != COMMON_ERROR_SUCCESS) ? (retFromCall) : (COMMON_ERROR_INTERNAL_ERROR)); + } + } + else + { + /* Could not set os specific pointer data. */ + ret = ((retFromCall != COMMON_ERROR_SUCCESS) ? (retFromCall) : (COMMON_ERROR_INTERNAL_ERROR)); + } + } + else + { + /* Could not get osSpecificPointerData. Syscall failed. Set bLastCallEncounteredAnError flag in management structure. */ + ret = retFromCall; + retFromCall = Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(lib, true); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Load_Library_Syscall(): Could not load <"); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, pathToLibrary); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "> Host function returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(ret)); + if (retFromCall != COMMON_ERROR_SUCCESS) + { + /* Log additional error. */ + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Additionally, we could not set the error flag for the internal library structure. Engine Call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + } + } + } + else + { + /* Could not retrive path from lib structure. */ + ret = ((retFromCall != COMMON_ERROR_SUCCESS) ? (retFromCall) : (COMMON_ERROR_INTERNAL_ERROR)); + } + } + else + { + /* Could not copy path data. */ + ret = ((retFromCall != COMMON_ERROR_SUCCESS) ? (retFromCall) : (COMMON_ERROR_INTERNAL_ERROR)); + } + } + else + { + /* Encountered an error during the unload. */ + ret = ((retFromCall != COMMON_ERROR_SUCCESS) ? (retFromCall) : (COMMON_ERROR_INTERNAL_ERROR)); + retFromCall = Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(lib, true); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Load_Library(): Unable to reload library."); + if (retFromCall != COMMON_ERROR_SUCCESS) + { + /* Log additional error. */ + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Additionally, we could not set the error flag for the internal library structure. Engine Call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + } + } + } + else + { + /* Check and see if the library was already loaded. */ + if (retFromCall == COMMON_ERROR_TRUE) + { + /* Library is already loaded. */ + ret = DYNLIB_ERROR_LIBRARY_ALREADY_LOADED; + } + else + { + /* An error occured. */ + ret = ((retFromCall != COMMON_ERROR_SUCCESS) ? (retFromCall) : (COMMON_ERROR_INTERNAL_ERROR)); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Load_Library(): Could not get loaded library flag from management structure. Engine call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + } + } + } + else + { + /* pathToLibrary is NULL. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + retFromCall = Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(lib, true); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Load_Library(): No path to the library was given. Unable to load a library without the path to it."); + if (retFromCall != COMMON_ERROR_SUCCESS) + { + /* Log additional error. */ + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Additionally, we could not set the error flag for the internal library structure. Engine Call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + } + } + } + else + { + /* Management structure is invalid. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Load_Library(): The engine's library structure for the given library is invalid. Unable to load a library without a valid library structure."); + } + + /* Check for an allocated copiedPathFromStruct and deallocate it if needed. */ + if (copiedPathFromStruct != NULL) + { + DataProcess_Deallocate_CString(&copiedPathFromStruct); + copiedPathLengthFromStruct = 0; + } + + /* Exit function. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Unload_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; /* The result of calls to other engine functions. */ + void * osData = NULL; /* The osSpecificPointerData from the management structure. */ + char * pSym = NULL; /* Used to log the library path to the error log. */ + size_t pSymLength = 0; /* The length of pSym in bytes. */ + + /* Check to see if the pointer to the management structure is valid. */ + if (lib != NULL) + { + /* Check for a loaded library. */ + retFromCall = Common_Dynamic_Library_Subsystem_Get_IsLoaded_Loaded_Dynamic_Library(lib); + if (retFromCall == COMMON_ERROR_TRUE) + { + /* Reset bLastCallEncounteredAnError. */ + retFromCall = Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(lib, false); + if (retFromCall == COMMON_ERROR_SUCCESS) + { + /* Get the osSpecificPointerData from the management structure. */ + retFromCall = Common_Dynamic_Library_Subsystem_Get_OsSpecificPointerData_Loaded_Dynamic_Library(lib, &osData); + if ((retFromCall == COMMON_ERROR_SUCCESS) && (osData != NULL)) + { + /* Call the syscall. */ + retFromCall = Common_Dynamic_Library_Subsystem_Unload_Library_Syscall(osData); + if (retFromCall == COMMON_ERROR_SUCCESS) + { + /* The library was unloaded successfully. */ + retFromCall = Common_Dynamic_Library_Subsystem_Set_IsLoaded_Loaded_Dynamic_Library(lib, false); + if (retFromCall == COMMON_ERROR_SUCCESS) + { + retFromCall = Common_Dynamic_Library_Subsystem_Set_OsSpecificPointerData_Loaded_Dynamic_Library(lib, NULL); + if (retFromCall == COMMON_ERROR_SUCCESS) + { + /* Success. */ + ret = COMMON_ERROR_SUCCESS; + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Unload_Library(): <"); + + /* Attempt to get the library path for the error log. */ + if ((Common_Dynamic_Library_Subsystem_Get_PathToLibrary_Loaded_Dynamic_Library(lib, &pSym, &pSymLength) == COMMON_ERROR_SUCCESS) && + (pSym != NULL)) + { + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, pSym); + } + else + { + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "[ERROR: COULD NOT FETCH PATH TO LIBRARY FROM MANAGEMENT STRUCTURE.]"); + } + pSym = NULL; /* Clear abused pSym. */ + + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "> unloaded."); + } + else + { + /* Could not clear os specific pointer data in management structure. */ + ret = ((retFromCall != COMMON_ERROR_SUCCESS) ? (retFromCall) : (COMMON_ERROR_INTERNAL_ERROR)); + retFromCall = Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(lib, true); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Unload_Library(): Could not clear os specific pointer data in management structure. Call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(ret)); + if (retFromCall != COMMON_ERROR_SUCCESS) + { + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Additionally, could not set the error flag in the management structure. Call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + } + } + } + else + { + /* Could not clear is loaded flag in management structure. */ + ret = ((retFromCall != COMMON_ERROR_SUCCESS) ? (retFromCall) : (COMMON_ERROR_INTERNAL_ERROR)); + retFromCall = Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(lib, true); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Unload_Library(): Could not clear is loaded flag in management structure. Call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(ret)); + if (retFromCall != COMMON_ERROR_SUCCESS) + { + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Additionally, could not set the error flag in the management structure. Call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + } + } + } + else + { + /* Could not unload the library. */ + ret = retFromCall; + retFromCall = Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(lib, true); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Unload_Library(): Could not unload <"); + + /* Attempt to get the library path for the error log. */ + if ((Common_Dynamic_Library_Subsystem_Get_PathToLibrary_Loaded_Dynamic_Library(lib, &pSym, &pSymLength) == COMMON_ERROR_SUCCESS) && + (pSym != NULL)) + { + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, pSym); + } + else + { + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "[ERROR: COULD NOT FETCH PATH TO LIBRARY FROM MANAGEMENT STRUCTURE.]"); + } + pSym = NULL; /* Clear abused pSym. */ + + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "> Host function returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(ret)); + if (retFromCall != COMMON_ERROR_SUCCESS) + { + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Additionally, could not set the error flag in the management structure. Call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + } + } + } + else + { + /* Could not get osSpecificPointerData from management structure. */ + ret = ((retFromCall != COMMON_ERROR_SUCCESS) ? (retFromCall) : (COMMON_ERROR_INTERNAL_ERROR)); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Unload_Library(): Could not get os specific data pointer from management structure. Call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + } + } + else + { + /* Could not reset last call incountered an error flag. */ + ret = ((retFromCall != COMMON_ERROR_SUCCESS) ? (retFromCall) : (COMMON_ERROR_INTERNAL_ERROR)); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Unload_Library(): Could not reset management structure's error flag. Call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + } + } + else + { + /* Library is not loaded. */ + ret = DYNLIB_ERROR_LIBRARY_NOT_LOADED; + retFromCall = Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(lib, true); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Unload_Library(): The given library <"); + + /* Attempt to get the library path for the error log. */ + if ((Common_Dynamic_Library_Subsystem_Get_PathToLibrary_Loaded_Dynamic_Library(lib, &pSym, &pSymLength) == COMMON_ERROR_SUCCESS) && + (pSym != NULL)) + { + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, pSym); + } + else + { + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "[ERROR: COULD NOT FETCH PATH TO LIBRARY FROM MANAGEMENT STRUCTURE.]"); + } + pSym = NULL; /* Clear abused pSym. */ + + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "> is not loaded."); + if (retFromCall != COMMON_ERROR_SUCCESS) + { + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Additionally, could not set the error flag in the management structure. Call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + } + } + } + else + { + /* Management structure is invalid. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Unload_Library(): The engine's library structure for the given library is invalid. Unable to unload a library without a valid library structure."); + } + + /* Return result. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Reload_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; /* The result of calls to other engine functions. */ + char * tempPath = NULL; /* Used to verifiy that the path was stored in the management structure. */ + size_t tempPathLength = 0; /* Used to store the length of the tempPath string in bytes. */ + + /* Check for invalid arguments. */ + if (lib != NULL) + { + /* Get the pathToLibrary pointer from the management structure. */ + retFromCall = Common_Dynamic_Library_Subsystem_Get_PathToLibrary_Loaded_Dynamic_Library(lib, &tempPath, &tempPathLength); + if (retFromCall == COMMON_ERROR_SUCCESS) + { + /* Check for valid path data */ + if ((tempPath != NULL) && (tempPathLength > 0)) + { + /* Call Common_Dynamic_Library_Subsystem_Load_Library(). */ + ret = Common_Dynamic_Library_Subsystem_Load_Library(tempPath, tempPathLength, true, lib); + } + else + { + /* The given library structure does not define a path. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Reload_Library(): The given library structure does not define a path."); + } + } + else + { + /* Could not get the pathToLibrary pointer from the data structure. */ + ret = ((retFromCall != COMMON_ERROR_SUCCESS) ? (retFromCall) : (COMMON_ERROR_INTERNAL_ERROR)); + retFromCall = Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(lib, true); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Reload_Library(): Unable to get the pathToLibrary pointer from the data structure."); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Engine call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(ret)); + if (retFromCall != COMMON_ERROR_SUCCESS) + { + /* Log additional error. */ + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Additionally, we could not set the error flag for the internal library structure. Engine Call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + } + } + } + else + { + /* Library structure is invalid. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Reload_Library(): The engine's library structure for the given library is invalid."); + } + + /* Exit function. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Get_Symbol(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib, const char * symbolName, const size_t symbolNameLength, void ** retSym) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; /* The result of calls to other engine functions. */ + void * pSym = NULL; /* The returned symbol pointer. */ + size_t pSymLength = 0; /* The length of pSym (When being abused as a path string) in bytes. */ + void * osData = NULL; /* The osSpecificPointerData from the management structure. */ + + /* Check to see if the pointer to the management structure is valid. */ + if (lib != NULL) + { + /* Check and see if retSym is valid. */ + if (retSym != NULL) + { + /* Check to see if symbolName is NULL, or symbolNameLength is less than or equal to zero. */ + if ((symbolName != NULL) && (symbolNameLength > 0)) + { + /* Check for a loaded library. */ + retFromCall = Common_Dynamic_Library_Subsystem_Get_IsLoaded_Loaded_Dynamic_Library(lib); + if (retFromCall == COMMON_ERROR_TRUE) + { + /* Reset bLastCallEncounteredAnError. */ + retFromCall = Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(lib, false); + if (retFromCall == COMMON_ERROR_SUCCESS) + { + /* Get the osSpecificPointerData from the management structure. */ + retFromCall = Common_Dynamic_Library_Subsystem_Get_OsSpecificPointerData_Loaded_Dynamic_Library(lib, &osData); + if ((retFromCall == COMMON_ERROR_SUCCESS) && (osData != NULL)) + { + /* Call syscall. */ + retFromCall = Common_Dynamic_Library_Subsystem_Get_Symbol_Syscall(osData, symbolName, symbolNameLength, &pSym); + if (retFromCall == COMMON_ERROR_SUCCESS) + { + /* Copy pSym to retSym. */ + (*retSym) = pSym; + + /* Success. */ + ret = COMMON_ERROR_SUCCESS; + } + else + { + /* An error occured fetching the symbol. */ + ret = retFromCall; + retFromCall = Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(lib, true); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Get_Symbol(): Could not fetch symbol in <"); + + /* Attempt to get the library path for the error log. */ + if ((Common_Dynamic_Library_Subsystem_Get_PathToLibrary_Loaded_Dynamic_Library(lib, (char**)&pSym, &pSymLength) == COMMON_ERROR_SUCCESS) && + (pSym != NULL)) + { + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, (char*)pSym); + } + else + { + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "[ERROR: COULD NOT FETCH PATH TO LIBRARY FROM MANAGEMENT STRUCTURE.]"); + } + pSym = NULL; /* Clear abused pSym. */ + + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "> Host function returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(ret)); + if (retFromCall != COMMON_ERROR_SUCCESS) + { + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Additionally, could not set the error flag in the management structure. Call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + } + } + } + else + { + /* Could not get osSpecificPointerData from management structure. */ + ret = ((retFromCall != COMMON_ERROR_SUCCESS) ? (retFromCall) : (COMMON_ERROR_INTERNAL_ERROR)); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Get_Symbol(): Could not get os specific data pointer from management structure. Call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + } + } + else + { + /* Could not reset last call incountered an error flag. */ + ret = ((retFromCall != COMMON_ERROR_SUCCESS) ? (retFromCall) : (COMMON_ERROR_INTERNAL_ERROR)); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Get_Symbol(): Could not reset management structure's error flag. Call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + } + } + else + { + /* Library is not loaded. */ + ret = DYNLIB_ERROR_LIBRARY_NOT_LOADED; + retFromCall = Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(lib, true); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Get_Symbol(): The given library <"); + + /* Attempt to get the library path for the error log. */ + if ((Common_Dynamic_Library_Subsystem_Get_PathToLibrary_Loaded_Dynamic_Library(lib, (char**)&pSym, &pSymLength) == COMMON_ERROR_SUCCESS) && + (pSym != NULL)) + { + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, (char*)pSym); + } + else + { + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "[ERROR: COULD NOT FETCH PATH TO LIBRARY FROM MANAGEMENT STRUCTURE.]"); + } + pSym = NULL; /* Clear abused pSym. */ + + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "> is not loaded."); + if (retFromCall != COMMON_ERROR_SUCCESS) + { + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Additionally, could not set the error flag in the management structure. Call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + } + } + } + else + { + /* symbolName is NULL. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + retFromCall = Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(lib, true); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Get_Symbol(): No symbol name was given, cannot load a symbol without a name to identifiy it."); + if (retFromCall != COMMON_ERROR_SUCCESS) + { + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Additionally, could not set the error flag in the management structure. Call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + } + } + } + else + { + /* retSym is NULL. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + retFromCall = Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(lib, true); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Get_Symbol(): "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(COMMON_ERROR_INVALID_ARGUMENT)); + if (retFromCall != COMMON_ERROR_SUCCESS) + { + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Additionally, could not set the error flag in the management structure. Call returned: "); + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + } + } + } + else + { + /* Library structure is invalid. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + COMMON_LOG_VERBOSE(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Get_Symbol(): The engine's library structure for the given library is invalid. Unable to lookup function without a valid library structure."); + } + + /* Return result. */ + return ret; + } + +#ifdef __cplusplus +} /* End of extern C. */ +#endif /* __cplusplus */ diff --git a/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem.h b/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem.h index 7042a1e..e82500c 100644 --- a/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem.h +++ b/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem.h @@ -18,24 +18,32 @@ https://github.com/codebase7/mengine */ -// Include guard. +/* Include guard. */ #ifndef MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_H #define MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_H -#include // bool. -#include // NULL. -#include // Malloc. +/* Internal includes. */ +#include "../../../DLL_PORT.h" /* Defines MSYS_DLL_EXPORT, and MSYS_DLL_IMPORT_TEMPLATE. */ -// Internal includes. -#include "Dynamic_Library_Subsystem_Data_Structures.h" // Contains data structures used internally. +/* Check for MSVC. */ +#ifdef _MSC_FULL_VER +#include "..\..\..\stdbool.h" /* bool. (MSVC is special.) */ +#else +#include /* bool. */ +#endif /* _MSC_FULL_VER */ +#include /* NULL. */ +#include /* Malloc. */ + +/* Internal includes. */ +#include "Dynamic_Library_Subsystem_Data_Structures.h" /* Contains data structures used internally. */ #ifdef __win32 -#include "..\Error_Handler\Common_Error_Handler_Internal.h" // Contains the function defintions for calling the common error handler. +#include "..\Error_Handler\Common_Error_Handler_Internal.h" /* Contains the function defintions for calling the common error handler. */ #else -#include "../Error_Handler/Common_Error_Handler_Internal.h" // Contains the function defintions for calling the common error handler. -#endif // __win32 +#include "../Error_Handler/Common_Error_Handler_Internal.h" /* Contains the function defintions for calling the common error handler. */ +#endif /* __win32 */ -// Defines for the default library extension. +/* Defines for the default library extension. */ #ifdef __win32 #define DL_EXTENSION ".dll" #elif __linux__ @@ -43,41 +51,36 @@ #endif #ifdef __cplusplus -// Define extern C. +/* Define extern C. */ extern "C" { #endif /*! - * int Common_Dynamic_Library_Subsystem_Load_Library(const char * pathToLibrary, const bool reloadLibrary, + * int Common_Dynamic_Library_Subsystem_Load_Library(const char * pathToLibrary, const size_t pathToLibraryLength, const bool reloadLibrary, * Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib) * * This function calls the system specific dynamic library handler and attempts to load the requested library. * - * Note: Due to the nature of the Dynamic_Library_Subsystem being a generic wrapper over the system specific calls, - * we cannot return more informative error messages. (Not without a generic error lookup table anyway....) - * * Pram: const char * pathToLibrary, a pointer to the c-string that contains the path to the library on disk. + * Pram: const size_t pathToLibraryLength, length of the pathToLibrary c-string in bytes. * Pram: const bool reloadLibrary, whether or not to reload the library if it is already loaded. * Pram: Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib, A pointer to a properly constructed * management data structure used internally. * - * Returns 0 if the library was successfully loaded. (The value of lib.bLastCallEncounteredAnError will be false in this case as well.) - * Returns -1 if the library could not be loaded. (The value of lib.bLastCallEncounteredAnError will be true in this case as well.) - * Returns -2 if the attempt to unload the library failed. (Only possible if reloadLibrary is true.) (The value of lib.bLastCallEncounteredAnError will be true in this case as well.) - * Returns -3 if the pathToLibrary pointer was NULL. (The value of lib.bLastCallEncounteredAnError will be true in this case as well.) - * Returns -4 if the given Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library pointer was NULL. - * Returns 1 if the library was already loaded. (Only possible if reloadLibrary is false.) (The value of lib.bLastCallEncounteredAnError will be false in this case as well.) + * Returns COMMON_ERROR_SUCCESS if the library was successfully loaded. (The value of lib.bLastCallEncounteredAnError will be false in this case as well.) + * Returns Translated host system error code if the library could not be loaded. (The value of lib.bLastCallEncounteredAnError will be true in this case as well.) + * Returns All errors returned by Common_Dynamic_Library_Subsystem_Unload_Library() if the attempt to unload the library failed. (Only possible if reloadLibrary is true.) (The value of lib.bLastCallEncounteredAnError will be true in this case as well.) + * Returns COMMON_ERROR_INVALID_ARGUMENT if the pathToLibrary pointer was NULL. (The value of lib.bLastCallEncounteredAnError will be true in this case as well.) + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library pointer was NULL. + * Returns DYNLIB_ERROR_LIBRARY_ALREADY_LOADED if the library was already loaded. (Only possible if reloadLibrary is false.) (The value of lib.bLastCallEncounteredAnError will be false in this case as well.) */ - int Common_Dynamic_Library_Subsystem_Load_Library(const char * pathToLibrary, const bool reloadLibrary, - Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib); + MSYS_DLL_EXPORT int Common_Dynamic_Library_Subsystem_Load_Library(const char * pathToLibrary, const size_t pathToLibraryLength, const bool reloadLibrary, + Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib); /*! * int Common_Dynamic_Library_Subsystem_Unload_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib) * * This function calls the system specific dynamic library handler and attempts to unload the requested library. * - * Note: Due to the nature of the Dynamic_Library_Subsystem being a generic wrapper over the system specific calls, - * we cannot return more informative error messages. (Not without a generic error lookup table anyway....) - * * Note: Due to the underlying system, even if this call is successful, the library may still be loaded in memory. * Internally, the Dynamic_Library_Subsystem blocks attempts to load the library multiple times via calls to Common_Dynamic_Library_Subsystem_Load_Library(). * (I.e. Load a library that is already loaded.) This is to try and prevent specific systems that use reference counts @@ -91,41 +94,58 @@ extern "C" { * Pram: Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib, A pointer to a properly constructed * management data structure used internally. * - * Returns 0 if the library unload call returned successful. - * Returns -1 if the library was not loaded according to the given management data structure. - * Returns -2 if the library unload call returned unsuccessful. - * Returns -4 if the given Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library pointer was NULL. + * Returns COMMON_ERROR_SUCCESS if the library unload call returned successful. + * Returns DYNLIB_ERROR_LIBRARY_NOT_LOADED if the library was not loaded according to the given management data structure. + * Returns Translated host system error code if the library unload call returned unsuccessful. + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library pointer was NULL. */ - int Common_Dynamic_Library_Subsystem_Unload_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib); + MSYS_DLL_EXPORT int Common_Dynamic_Library_Subsystem_Unload_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib); /*! - * void * Common_Dynamic_Library_Subsystem_Get_Symbol(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib, - * const char * symbolName) + * int Common_Dynamic_Library_Subsystem_Reload_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib) * - * This function calls the system specific dynamic library handler and attempts to fetch a pointer to the first byte - * of the given symbol. + * This function reloads the given library. + * + * (Effectively this function is a wrapper around Common_Dynamic_Library_Subsystem_Load_Library(), setting it's + * reloadLibrary argument to true, and using the given management structure's path.) + * + * Returns COMMON_ERROR_SUCCESS if the library is reloaded successfully. * - * Note: Due to the nature of the Dynamic_Library_Subsystem being a generic wrapper over the system specific calls, - * we cannot return more informative error messages. (Not without a generic error lookup table anyway....) + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL, or if the given management structure + * does not define a path. (Such as when it's first created or if it was cleared by a call to + * Common_Dynamic_Library_Subsystem_Blank_Loaded_Dynamic_Library().) * - * Note: To check for an error result from this function, check the value of lib.bLastCallEncounteredAnError. - * If lib.bLastCallEncounteredAnError is false, no error occured during this function. Otherwise an error occured. + * Otherwise returns any error given by Common_Dynamic_Library_Subsystem_Load_Library(). + */ + MSYS_DLL_EXPORT int Common_Dynamic_Library_Subsystem_Reload_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib); + + /*! + * int Common_Dynamic_Library_Subsystem_Get_Symbol(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib, + * const char * symbolName, const size_t symbolNameLength, void ** retSym) + * + * This function calls the system specific dynamic library handler and attempts to fetch a pointer to the first byte + * of the given symbol. * * Pram: Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, A pointer to a properly constructed * management data structure used internally. * Pram: const char * symbolName, A pointer to a c-string that contains the name of the requested symbol to * search for. + * Pram: const size_t symbolNameLength, the length of symbolName in bytes. + * Pram: void ** retSym, A double pointer that will hold the address to the first byte of the requested symbol if the function succeeds. + * (retSym will NOT be modified if this function returns an error.) * - * Returns a valid pointer if the resulting lookup returned a valid pointer. (The value of lib.bLastCallEncounteredAnError will be false in this case.) + * Returns COMMON_ERROR_SUCCESS if the resulting lookup returned a valid pointer. (The value of lib.bLastCallEncounteredAnError will be false in this case.) * Returns a NULL pointer if the resulting lookup returned a NULL pointer. (The value of lib.bLastCallEncounteredAnError will be false in this case as well.) - * Returns a NULL pointer if the lookup failed for some reason. (The value of lib.bLastCallEncounteredAnError will be true in this case.) - * Returns a NULL pointer if the given Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library pointer was NULL. + * (Note: Some systems may not support NULL symbols, in this case the result is the same as if the lookup failed, see below.) + * Returns Translated host system error code if the lookup failed for some reason. (The value of lib.bLastCallEncounteredAnError will be true in this case.) + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library, symbolName, or retSym pointer(s) was / were set to NULL. + * Returns DYNLIB_ERROR_LIBRARY_NOT_LOADED if the library was not loaded according to the given management data structure. */ - void * Common_Dynamic_Library_Subsystem_Get_Symbol(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib, const char * symbolName); + MSYS_DLL_EXPORT int Common_Dynamic_Library_Subsystem_Get_Symbol(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib, const char * symbolName, const size_t symbolNameLength, void ** retSym); #ifdef __cplusplus -} // End of extern C. -#endif +} /* End of extern C. */ +#endif /* __cplusplus */ -#endif +#endif /* MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_H */ -// End of Dynamic_Library_Subsystem.h +/* End of Dynamic_Library_Subsystem.h */ diff --git a/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Data_Structures.c b/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Data_Structures.c index 7b1dc8c..beeff11 100644 --- a/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Data_Structures.c +++ b/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Data_Structures.c @@ -18,44 +18,359 @@ https://github.com/codebase7/mengine */ +/* Internal includes */ #include "Dynamic_Library_Subsystem.h" +#include "Dynamic_Library_Subsystem_Data_Structures_Private_API.h" +#include "../../../Core/Src/DataProcess.h" +#include "../Error_Handler/Common_Error_Handler_Error_Codes.h" +#include "../Error_Handler/Common_Error_Handler_Internal.h" +#include "../Error_Handler/Common_Error_Handler_Structures.h" +#include "../Error_Handler/Common_Error_Handler_Log_Channel_Defs.h" +/* Define the MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID macro. */ +#define MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID MSYS_ERROR_LOG_CHANNEL_DYNLIB + +/* Check for C++ Compiler. */ #ifdef __cplusplus -// Define extern C. +/* Define extern C. */ extern "C" { -#endif - Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * Common_Dynamic_Library_Subsystem_Create_Loaded_Dynamic_Library() +#endif /* __cplusplus */ + int Common_Dynamic_Library_Subsystem_Get_API_Major_Version_Number() + { + /* Return the API Version number. */ + return MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_API_MAJOR_VER; + } + + int Common_Dynamic_Library_Subsystem_Get_API_Minor_Version_Number() + { + /* Return the API Version number. */ + return MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_API_MINOR_VER; + } + + int Common_Dynamic_Library_Subsystem_Get_API_Revision_Version_Number() { - // Create the referece. + /* Return the API Version number. */ + return MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_API_REVISION_VER; + } + + int Common_Dynamic_Library_Subsystem_Create_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library ** lib) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * result = NULL; - result = ((Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library*)(malloc(sizeof(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library)))); - // Check for a valid result. - if (result != NULL) + /* Check for valid arguments. */ + if (lib != NULL) { - // Initilize the vars. - result->bIsLoaded = false; - result->bLastCallEncounteredAnError = false; - result->osSpecificPointerData = NULL; - result->pathToLibrary = NULL; + /* Create the referece. */ + retFromCall = DataProcess_Reallocate_C_String(((char**)(&result)), 0, sizeof(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library)); + + /* Check for a valid result. */ + if ((retFromCall == COMMON_ERROR_SUCCESS) && (result != NULL)) + { + /* Set the pointer to NULL. */ + result->pointer = NULL; + + /* Call the real function. */ + ret = Common_Dynamic_Library_Subsystem_Create_Loaded_Dynamic_Library_Private(((Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private **)(&(result->pointer)))); + } + else + { + /* Could not init structure. */ + ret = ((retFromCall != COMMON_ERROR_SUCCESS) ? (retFromCall) : (COMMON_ERROR_INTERNAL_ERROR)); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Create_Loaded_Dynamic_Library(): Memory allocation function returned: "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Could not allocate memory for management structure."); + } + } + else + { + /* Invalid lib pointer. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Create_Loaded_Dynamic_Library(): "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(COMMON_ERROR_INVALID_ARGUMENT)); } - // Return result. - return result; + /* Return result. */ + return ret; } - void Common_Dynamic_Library_Subsystem_Destroy_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib) + void Common_Dynamic_Library_Subsystem_Destroy_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library ** lib) { - // Check for valid pointer. - if (lib != NULL) + /* Check for valid pointer. */ + if ((lib != NULL) && ((*lib) != NULL)) + { + /* Check for allocated pointer. */ + if ((*lib)->pointer != NULL) + { + /* Deallocate the pointer. */ + Common_Dynamic_Library_Subsystem_Destroy_Loaded_Dynamic_Library_Private(((Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private **)(&((*lib)->pointer)))); + } + + /* Free the structure. */ + DataProcess_Deallocate_CString(((char **)(lib))); + } + + /* Exit function. */ + return; + } + + void Common_Dynamic_Library_Subsystem_Blank_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib) + { + /* Check for valid pointers. */ + if ((lib != NULL) && (lib->pointer != NULL)) { - // Free the structure. - free(lib); + /* Call real function. */ + Common_Dynamic_Library_Subsystem_Blank_Loaded_Dynamic_Library_Private(((Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private *)(lib->pointer))); } - // Exit function. + /* Exit function. */ return; } + + int Common_Dynamic_Library_Subsystem_Get_IsLoaded_Loaded_Dynamic_Library(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; + + /* Check for valid pointers. */ + if ((lib != NULL) && (lib->pointer != NULL)) + { + /* Call real function. */ + ret = Common_Dynamic_Library_Subsystem_Get_IsLoaded_Loaded_Dynamic_Library_Private(((Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private *)(lib->pointer))); + if (ret == COMMON_ERROR_INVALID_ARGUMENT) + { + /* That's an error, we didn't set up the private data structure correctly or it's been corrupted. */ + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Get_IsLoaded_Loaded_Dynamic_Library(): "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(COMMON_ERROR_INVALID_ARGUMENT)); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Private API data structure pointer is invalid."); + } + } + else + { + /* Invalid lib pointer. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Get_IsLoaded_Loaded_Dynamic_Library(): "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(COMMON_ERROR_INVALID_ARGUMENT)); + } + + /* Exit function. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Set_IsLoaded_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, const bool value) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; + + /* Check for valid pointers. */ + if ((lib != NULL) && (lib->pointer != NULL)) + { + /* Call real function. */ + ret = Common_Dynamic_Library_Subsystem_Set_IsLoaded_Loaded_Dynamic_Library_Private(((Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private *)(lib->pointer)), value); + if (ret == COMMON_ERROR_INVALID_ARGUMENT) + { + /* That's an error, we didn't set up the private data structure correctly or it's been corrupted. */ + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Set_IsLoaded_Loaded_Dynamic_Library(): "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(COMMON_ERROR_INVALID_ARGUMENT)); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Private API data structure pointer is invalid."); + } + } + else + { + /* Invalid lib pointer. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Set_IsLoaded_Loaded_Dynamic_Library(): "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(COMMON_ERROR_INVALID_ARGUMENT)); + } + + /* Exit function. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Get_LastCallEncounteredError_Loaded_Dynamic_Library(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; + + /* Check for valid pointers. */ + if ((lib != NULL) && (lib->pointer != NULL)) + { + /* Call real function. */ + ret = Common_Dynamic_Library_Subsystem_Get_LastCallEncounteredError_Loaded_Dynamic_Library_Private(((Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private *)(lib->pointer))); + if (ret == COMMON_ERROR_INVALID_ARGUMENT) + { + /* That's an error, we didn't set up the private data structure correctly or it's been corrupted. */ + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Get_LastCallEncounteredError_Loaded_Dynamic_Library(): "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(COMMON_ERROR_INVALID_ARGUMENT)); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Private API data structure pointer is invalid."); + } + } + else + { + /* Invalid lib pointer. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Get_LastCallEncounteredError_Loaded_Dynamic_Library(): "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(COMMON_ERROR_INVALID_ARGUMENT)); + } + + /* Exit function. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, const bool value) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; + + /* Check for valid pointers. */ + if ((lib != NULL) && (lib->pointer != NULL)) + { + /* Call real function. */ + ret = Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library_Private(((Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private *)(lib->pointer)), value); + if (ret == COMMON_ERROR_INVALID_ARGUMENT) + { + /* That's an error, we didn't set up the private data structure correctly or it's been corrupted. */ + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(): "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(COMMON_ERROR_INVALID_ARGUMENT)); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Private API data structure pointer is invalid."); + } + } + else + { + /* Invalid lib pointer. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(): "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(COMMON_ERROR_INVALID_ARGUMENT)); + } + + /* Exit function. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Get_OsSpecificPointerData_Loaded_Dynamic_Library(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, void ** retVar) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; + + /* Check for valid pointers. */ + if ((lib != NULL) && (lib->pointer != NULL) && (retVar != NULL)) + { + /* Call real function. */ + ret = Common_Dynamic_Library_Subsystem_Get_OsSpecificPointerData_Loaded_Dynamic_Library_Private(((Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private *)(lib->pointer)), retVar); + if (ret == COMMON_ERROR_INVALID_ARGUMENT) + { + /* That's an error, we didn't set up the private data structure correctly or it's been corrupted. */ + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Get_OsSpecificPointerData_Loaded_Dynamic_Library(): "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(COMMON_ERROR_INVALID_ARGUMENT)); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Private API data structure pointer is invalid."); + } + } + else + { + /* Invalid lib pointer. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Get_OsSpecificPointerData_Loaded_Dynamic_Library(): "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(COMMON_ERROR_INVALID_ARGUMENT)); + } + + /* Exit function. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Set_OsSpecificPointerData_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, void * value) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; + + /* Check for valid pointers. */ + if ((lib != NULL) && (lib->pointer != NULL)) + { + /* Call real function. */ + ret = Common_Dynamic_Library_Subsystem_Set_OsSpecificPointerData_Loaded_Dynamic_Library_Private(((Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private *)(lib->pointer)), value); + if (ret == COMMON_ERROR_INVALID_ARGUMENT) + { + /* That's an error, we didn't set up the private data structure correctly or it's been corrupted. */ + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Set_OsSpecificPointerData_Loaded_Dynamic_Library(): "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(COMMON_ERROR_INVALID_ARGUMENT)); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Private API data structure pointer is invalid."); + } + } + else + { + /* Invalid lib pointer. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Set_OsSpecificPointerData_Loaded_Dynamic_Library(): "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(COMMON_ERROR_INVALID_ARGUMENT)); + } + + /* Exit function. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Get_PathToLibrary_Loaded_Dynamic_Library(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, const char ** retVar, size_t * retVarLength) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; + + /* Check for valid pointers. */ + if ((lib != NULL) && (lib->pointer != NULL) && (retVar != NULL) && (retVarLength != NULL)) + { + /* Call real function. */ + ret = Common_Dynamic_Library_Subsystem_Get_PathToLibrary_Loaded_Dynamic_Library_Private(((Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private *)(lib->pointer)), retVar, retVarLength); + if (ret == COMMON_ERROR_INVALID_ARGUMENT) + { + /* That's an error, we didn't set up the private data structure correctly or it's been corrupted. */ + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Get_PathToLibrary_Loaded_Dynamic_Library(): "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(COMMON_ERROR_INVALID_ARGUMENT)); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Private API data structure pointer is invalid."); + } + } + else + { + /* Invalid lib pointer. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Get_PathToLibrary_Loaded_Dynamic_Library(): "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(COMMON_ERROR_INVALID_ARGUMENT)); + } + + /* Exit function. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Set_PathToLibrary_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, const char * value, const size_t valueLength) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; + char * tempPath = NULL; + + /* Check for valid pointers. */ + if ((lib != NULL) && (lib->pointer != NULL) && (((value == NULL) && (valueLength == 0)) || ((value != NULL) && (valueLength > 0)))) + { + /* Call real function. */ + ret = Common_Dynamic_Library_Subsystem_Set_PathToLibrary_Loaded_Dynamic_Library_Private(((Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private *)(lib->pointer)), value, valueLength); + if (ret == COMMON_ERROR_INVALID_ARGUMENT) + { + /* That's an error, we didn't set up the private data structure correctly or it's been corrupted. */ + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Set_PathToLibrary_Loaded_Dynamic_Library(): "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(COMMON_ERROR_INVALID_ARGUMENT)); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Private API data structure pointer is invalid."); + } + } + else + { + /* Invalid lib pointer. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Set_PathToLibrary_Loaded_Dynamic_Library(): "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(COMMON_ERROR_INVALID_ARGUMENT)); + } + + /* Exit function. */ + return ret; + } + #ifdef __cplusplus -} // End of extern C. -#endif +} /* End of extern C. */ +#endif /* __cplusplus */ diff --git a/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Data_Structures.h b/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Data_Structures.h index f5beb16..45fb749 100644 --- a/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Data_Structures.h +++ b/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Data_Structures.h @@ -18,71 +18,239 @@ https://github.com/codebase7/mengine */ -// Include guard. +/* Include guard. */ #ifndef MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_H #error "You must include the Dynamic_Library_Subsystem.h header file. It will include all of the other needed headers." #else #ifndef MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_DATA_STRUCTURES_H #define MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_DATA_STRUCTURES_H -// Define the supported API level. -#define MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_API_LEVEL 0 +/* Define the supported API version numbers. */ +#define MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_API_MAJOR_VER 0 +#define MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_API_MINOR_VER 0 +#define MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_API_REVISION_VER 0 +/* Internal includes. */ +#include "../../../DLL_PORT.h" + +/* Check for C++ Compiler. */ #ifdef __cplusplus -// Define extern C. +/* Define extern C. */ extern "C" { -#endif - // Define Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library. +#endif /* __cplusplus */ + /* Define Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library. */ struct Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library { - bool bIsLoaded; // Whether or not this library is loaded. - bool bLastCallEncounteredAnError; /* - Whether or not this library has encountered an error in the last call. - (Should reset to false when a new call is made and no error occurs.) - */ - - void * osSpecificPointerData; /* - Pointer to an OS specific data structure. - (For example, Windows defines loaded libraries with an HMODULE pointer, - which is needed to unload the library or to search it.) - */ - const char * pathToLibrary; // Path to the dynamic library file on disk. + void * pointer; }; + /* Create user defined data type for Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library structure. */ typedef struct Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library; /*! - * Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * Common_Dynamic_Library_Subsystem_Create_Loaded_Dynamic_Library() + * int Common_Dynamic_Library_Subsystem_Get_API_Major_Version_Number() + * + * Returns the API major version number for the Dynamic Library Subsystem. + */ + MSYS_DLL_EXPORT int Common_Dynamic_Library_Subsystem_Get_API_Major_Version_Number(); + + /*! + * int Common_Dynamic_Library_Subsystem_Get_API_Minor_Version_Number() + * + * Returns the API minor version number for the Dynamic Library Subsystem. + */ + MSYS_DLL_EXPORT int Common_Dynamic_Library_Subsystem_Get_API_Minor_Version_Number(); + + /*! + * int Common_Dynamic_Library_Subsystem_Get_API_Revision_Version_Number() + * + * Returns the API revision version number for the Dynamic Library Subsystem. + */ + MSYS_DLL_EXPORT int Common_Dynamic_Library_Subsystem_Get_API_Revision_Version_Number(); + + /*! + * int Common_Dynamic_Library_Subsystem_Create_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library ** lib) * * Creates a Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library data structure in a neutral state. * * This function should be called when constructing a Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library object. * As it will correctly setup said object. * - * WARNING: The caller is responsible for calling free() or - * Destroy_Loaded_Dynamic_Library() on the successfully created structure. + * WARNING: The caller is responsible for calling + * Common_Dynamic_Library_Subsystem_Destroy_Loaded_Dynamic_Library() on the successfully created structure. + * + * WARNING: This function will NOT deallocate a preexisting structure, and will overwrite the given pointer if it is + * non-NULL if this function succeeds. Therefore if you need to keep the pointer, copy it elsewhere before calling this + * function. + * + * Returns COMMON_ERROR_SUCCESS if successful. (The created structure will be pointed to by lib.) + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given double pointer is NULL. + * Returns COMMON_ERROR_MEMORY_ERROR if the data structure could not be allocated. + * Otherwise returns the appropriate error code. * - * Returns a pointer to a Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library data structure if successful. - * Otherwise returns NULL. + * No-alteration clause: + * - In case of error, this function will not modify it's arguments. */ - Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * Common_Dynamic_Library_Subsystem_Create_Loaded_Dynamic_Library(); + MSYS_DLL_EXPORT int Common_Dynamic_Library_Subsystem_Create_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library ** lib); /*! - * void Common_Dynamic_Library_Subsystem_Destroy_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib) + * void Common_Dynamic_Library_Subsystem_Destroy_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library ** lib) * - * Destroys (frees) a created Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library data structure. + * Destroys (frees) a created Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library data structure and set's it's pointer to NULL. * - * Pram: Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, a pointer to - * a successfully created Loaded_Dynamic_Library data structure. + * Pram: Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library ** lib, a double pointer to + * a successfully created Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library data structure. * * This function has no return. */ - void Common_Dynamic_Library_Subsystem_Destroy_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib); + MSYS_DLL_EXPORT void Common_Dynamic_Library_Subsystem_Destroy_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library ** lib); + + /*! + * void Common_Dynamic_Library_Subsystem_Blank_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib) + * + * Blanks the given Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library data structure's members. (Deallocating memory for them if needed.) + * + * If given an invalid pointer this function will silently fail. + * + * This function has no return. + */ + MSYS_DLL_EXPORT void Common_Dynamic_Library_Subsystem_Blank_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib); + + /*! + * int Common_Dynamic_Library_Subsystem_Get_IsLoaded_Loaded_Dynamic_Library(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib) + * + * ACCESSOR FUNCTION. + * + * Returns the status of the bIsLoaded member variable. + * + * Returns COMMON_ERROR_TRUE if the library is loaded. + * Returns COMMON_ERROR_FALSE if the library is NOT loaded. + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * Otherwise returns the appropriate error code. + */ + MSYS_DLL_EXPORT int Common_Dynamic_Library_Subsystem_Get_IsLoaded_Loaded_Dynamic_Library(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib); + + /*! + * int Common_Dynamic_Library_Subsystem_Set_IsLoaded_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, const bool value) + * + * ACCESSOR FUNCTION. + * + * Sets the status of the bIsLoaded member variable to the given value. + * + * Returns COMMON_ERROR_SUCCESS if the status was set to the given value successfully. + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * Otherwise returns the appropriate error code. + */ + MSYS_DLL_EXPORT int Common_Dynamic_Library_Subsystem_Set_IsLoaded_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, const bool value); + + /*! + * int Common_Dynamic_Library_Subsystem_Get_LastCallEncounteredError_Loaded_Dynamic_Library(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib) + * + * ACCESSOR FUNCTION. + * + * Returns the status of the bLastCallEncounteredAnError member variable. + * + * Returns COMMON_ERROR_TRUE if the last operation on this library encountered an error. + * Returns COMMON_ERROR_FALSE if the last operation on this library did NOT encounter an error. + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * Otherwise returns the appropriate error code. + */ + MSYS_DLL_EXPORT int Common_Dynamic_Library_Subsystem_Get_LastCallEncounteredError_Loaded_Dynamic_Library(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib); + + /*! + * int Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, const bool value) + * + * ACCESSOR FUNCTION. + * + * Sets the status of the bLastCallEncounteredAnError member variable to the given value. + * + * Returns COMMON_ERROR_SUCCESS if the status was set to the given value successfully. + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * Otherwise returns the appropriate error code. + */ + MSYS_DLL_EXPORT int Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, const bool value); + + /*! + * int Common_Dynamic_Library_Subsystem_Get_OsSpecificPointerData_Loaded_Dynamic_Library(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, void ** retVar) + * + * ACCESSOR FUNCTION. + * + * Returns the pointer for the osSpecificPointerData member variable. + * + * WARNING: This function will NOT deallocate a preexisting structure, and will overwrite the given pointer if it is + * non-NULL if this function succeeds. Therefore if you need to keep the pointer, copy it elsewhere before calling this + * function. + * + * WARNING: The caller should NOT deallocate the returned pointer. + * + * Returns COMMON_ERROR_SUCCESS if the data was returned successfully. (retVar will point to the pointer value in this case.) + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * Otherwise returns the appropriate error code. + */ + MSYS_DLL_EXPORT int Common_Dynamic_Library_Subsystem_Get_OsSpecificPointerData_Loaded_Dynamic_Library(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, void ** retVar); + + /*! + * int Common_Dynamic_Library_Subsystem_Set_OsSpecificPointerData_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, const void * value) + * + * ACCESSOR FUNCTION. + * + * Sets the pointer for the osSpecificPointerData member variable to the given value. + * + * Returns COMMON_ERROR_SUCCESS if the status was set to the given value successfully. + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * Otherwise returns the appropriate error code. + */ + MSYS_DLL_EXPORT int Common_Dynamic_Library_Subsystem_Set_OsSpecificPointerData_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, const void * value); + + /*! + * int Common_Dynamic_Library_Subsystem_Get_PathToLibrary_Loaded_Dynamic_Library(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, const char ** retVar, size_t * retVarLength) + * + * ACCESSOR FUNCTION. + * + * Returns the pointer for the pathToLibrary member variable, and the value of the pathToLibraryLength member variable. + * + * WARNING: This function will NOT deallocate a preexisting structure, and will overwrite the given pointer if it is + * non-NULL if this function succeeds. Therefore if you need to keep the pointer, copy it elsewhere before calling this + * function. + * + * WARNING: The caller should NOT deallocate the returned pointer. + * + * Returns COMMON_ERROR_SUCCESS if the data was returned successfully. (retVar will point to the pointer value in this case.) + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * Otherwise returns the appropriate error code. + */ + MSYS_DLL_EXPORT int Common_Dynamic_Library_Subsystem_Get_PathToLibrary_Loaded_Dynamic_Library(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, const char ** retVar, size_t * retVarLength); + + /*! + * int Common_Dynamic_Library_Subsystem_Set_PathToLibrary_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, const char * value, const size_t valueLength) + * + * ACCESSOR FUNCTION. + * + * Sets the pointer for the pathToLibrary member variable to the given value. + * + * Note this function serves two purposes, to allocate and copy the needed path string into the structure, + * and to deallocate a pre-existing path string in the structure. The mode that is chosen is dependant on the + * arguments given to the function. + * + * I.e. If value is non-NULL and valueLength is greater than zero, then the given path string will be copied. + * If value is NULL, and valueLength is equal to zero, then any pre-existing path string in the structure will be + * deallocated. Any other combination will generate a COMMON_ERROR_INVALID_ARGUMENT error code and the structure + * will not be modified. + * + * Returns COMMON_ERROR_SUCCESS if the status was set to the given value successfully. + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointers or length is NULL. + * Otherwise returns the appropriate error code. + * + * No-alteration clause: + * - In case of error, this function will not modify it's arguments. + */ + MSYS_DLL_EXPORT int Common_Dynamic_Library_Subsystem_Set_PathToLibrary_Loaded_Dynamic_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library * lib, const char * value, const size_t valueLength); + #ifdef __cplusplus -} // End of extern C. -#endif +} /* End of extern C. */ +#endif /* __cplusplus */ -#endif -#endif +#endif /* MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_DATA_STRUCTURES_H */ +#endif /* MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_H */ -// End of Dynamic_Library_Subsystem_Data_Structures.h +/* End of Dynamic_Library_Subsystem_Data_Structures.h */ diff --git a/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Data_Structures_Private_API.c b/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Data_Structures_Private_API.c new file mode 100644 index 0000000..6daa6e4 --- /dev/null +++ b/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Data_Structures_Private_API.c @@ -0,0 +1,354 @@ +/*! + Multiverse Engine Project 22/1/2016 Dynamic_Library_Subsystem Dynamic_Library_Subsystem_Data_Structures_Private_API.c + + Copyright (C) 2016 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Internal includes */ +#include "Dynamic_Library_Subsystem.h" +#include "Dynamic_Library_Subsystem_Data_Structures_Private_API.h" +#include "../../../Core/Src/DataProcess.h" +#include "../Error_Handler/Common_Error_Handler_Error_Codes.h" +#include "../Error_Handler/Common_Error_Handler_Internal.h" +#include "../Error_Handler/Common_Error_Handler_Structures.h" +#include "../Error_Handler/Common_Error_Handler_Log_Channel_Defs.h" + +/* Define the MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID macro. */ +#define MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID MSYS_ERROR_LOG_CHANNEL_DYNLIB + +/* Check for C++ Compiler. */ +#ifdef __cplusplus +/* Define extern C. */ +extern "C" { +#endif /* __cplusplus */ + int Common_Dynamic_Library_Subsystem_Create_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private ** lib) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; + Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * result = NULL; + + /* Check for valid arguments. */ + if (lib != NULL) + { + /* Create the referece. */ + retFromCall = DataProcess_Reallocate_C_String(((char**)(&result)), 0, sizeof(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private)); + + /* Check for a valid result. */ + if ((retFromCall == COMMON_ERROR_SUCCESS) && (result != NULL)) + { + /* Initilize the vars. */ + result->pathToLibrary = NULL; /* Avoid potential non-NULL causing a memory deallocation attempt for a pointer that is not allocated. */ + Common_Dynamic_Library_Subsystem_Blank_Loaded_Dynamic_Library_Private(result); + + /* Copy the pointer to lib. */ + (*lib) = result; + + /* Success. */ + ret = COMMON_ERROR_SUCCESS; + } + else + { + /* Could not init structure. */ + ret = ((retFromCall != COMMON_ERROR_SUCCESS) ? (retFromCall) : (COMMON_ERROR_INTERNAL_ERROR)); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Create_Loaded_Dynamic_Library_Private(): Memory allocation function returned: "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Could not allocate memory for management structure."); + } + } + else + { + /* Invalid lib pointer. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Return result. */ + return ret; + } + + void Common_Dynamic_Library_Subsystem_Destroy_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private ** lib) + { + /* Check for valid pointer. */ + if ((lib != NULL) && ((*lib) != NULL)) + { + /* Free the structure. */ + DataProcess_Deallocate_CString(((char **)(lib))); + } + + /* Exit function. */ + return; + } + + void Common_Dynamic_Library_Subsystem_Blank_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib) + { + /* Check for valid pointer. */ + if (lib != NULL) + { + /* Clear the data. */ + lib->bIsLoaded = false; + lib->bLastCallEncounteredAnError = false; + lib->osSpecificPointerData = NULL; + lib->pathToLibraryLength = 0; + + /* Check for set pathToLibrary. */ + if (lib->pathToLibrary != NULL) + { + /* Deallocate memory for the pathToLibrary variable. */ + DataProcess_Deallocate_CString(&(lib->pathToLibrary)); + } + } + + /* Exit function. */ + return; + } + + int Common_Dynamic_Library_Subsystem_Get_IsLoaded_Loaded_Dynamic_Library_Private(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; + + /* Check for valid pointer. */ + if (lib != NULL) + { + /* Check bIsLoaded. */ + ret = ((lib->bIsLoaded) ? (COMMON_ERROR_TRUE) : (COMMON_ERROR_FALSE)); + } + else + { + /* Invalid lib pointer. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Set_IsLoaded_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib, const bool value) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; + + /* Check for valid pointer. */ + if (lib != NULL) + { + /* Set bIsLoaded. */ + lib->bIsLoaded = value; + + /* Success. */ + ret = COMMON_ERROR_SUCCESS; + } + else + { + /* Invalid lib pointer. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Get_LastCallEncounteredError_Loaded_Dynamic_Library_Private(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; + + /* Check for valid pointer. */ + if (lib != NULL) + { + /* Check bLastCallEncounteredAnError. */ + ret = ((lib->bLastCallEncounteredAnError) ? (COMMON_ERROR_TRUE) : (COMMON_ERROR_FALSE)); + } + else + { + /* Invalid lib pointer. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib, const bool value) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; + + /* Check for valid pointer. */ + if (lib != NULL) + { + /* Set bLastCallEncounteredAnError. */ + lib->bLastCallEncounteredAnError = value; + + /* Success. */ + ret = COMMON_ERROR_SUCCESS; + } + else + { + /* Invalid lib pointer. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Get_OsSpecificPointerData_Loaded_Dynamic_Library_Private(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib, void ** retVar) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; + + /* Check for valid pointer. */ + if ((lib != NULL) && (retVar != NULL)) + { + /* Get the osSpecificPointerData and copy it to retVar. */ + (*retVar) = lib->osSpecificPointerData; + + /* Success. */ + ret = COMMON_ERROR_SUCCESS; + } + else + { + /* Invalid lib pointer. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Set_OsSpecificPointerData_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib, void * value) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; + + /* Check for valid pointer. */ + if (lib != NULL) + { + /* Copy the pointer value to osSpecificPointerData. */ + lib->osSpecificPointerData = value; + + /* Success. */ + ret = COMMON_ERROR_SUCCESS; + } + else + { + /* Invalid lib pointer. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Get_PathToLibrary_Loaded_Dynamic_Library_Private(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib, const char ** retVar, size_t * retVarLength) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; + + /* Check for valid pointer. */ + if ((lib != NULL) && (retVar != NULL) && (retVarLength != NULL)) + { + /* Get the pathToLibrary pointer and copy it to retVar. */ + (*retVar) = lib->pathToLibrary; + + /* Get the length of pathToLibrary and copy it to retVarLength. */ + (*retVarLength) = lib->pathToLibraryLength; + + /* Success. */ + ret = COMMON_ERROR_SUCCESS; + } + else + { + /* Invalid lib pointer. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Set_PathToLibrary_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib, const char * value, const size_t valueLength) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; + char * tempPath = NULL; + + /* Check for valid pointer. */ + if ((lib != NULL) && (((value == NULL) && (valueLength == 0)) || ((value != NULL) && (valueLength > 0)))) + { + /* OK, allocate memory. If needed. */ + if ((value != NULL) && (valueLength > 0)) + { + /* Allocate memory. */ + retFromCall = DataProcess_Reallocate_C_String(&tempPath, 0, valueLength); + if ((retFromCall == COMMON_ERROR_SUCCESS) && (tempPath != NULL)) + { + /* Copy the path string. */ + memcpy(tempPath, value, valueLength); + } + else + { + /* Could not allocate memory for path string. */ + ret = ((retFromCall != COMMON_ERROR_SUCCESS) ? (retFromCall) : (COMMON_ERROR_INTERNAL_ERROR)); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common_Dynamic_Library_Subsystem_Set_PathToLibrary_Loaded_Dynamic_Library_Private(): Memory allocation function returned: "); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, Common_Get_Error_Message(retFromCall)); + COMMON_LOG_DEBUG(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, " Could not allocate memory for library path."); + } + } + + /* Check for unknown error. */ + if (ret == COMMON_ERROR_UNKNOWN_ERROR) + { + /* Check for allocated pathToLibrary. */ + if (lib->pathToLibrary != NULL) + { + /* Deallocate the path string. */ + DataProcess_Deallocate_CString(&(lib->pathToLibrary)); + + /* Reset the path string's length. */ + lib->pathToLibraryLength = 0; + } + + /* Check and see if we need to copy the tempPath pointer and length. */ + if (tempPath != NULL) + { + /* Copy the tempPath pointer to the structure. */ + lib->pathToLibrary = tempPath; + } + if (valueLength > 0) + { + lib->pathToLibraryLength = valueLength; + } + + /* Success. */ + ret = COMMON_ERROR_SUCCESS; + } + } + else + { + /* Invalid lib pointer. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; + } + +#ifdef __cplusplus +} /* End of extern C. */ +#endif /* __cplusplus */ diff --git a/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Data_Structures_Private_API.h b/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Data_Structures_Private_API.h new file mode 100644 index 0000000..21c5a7d --- /dev/null +++ b/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Data_Structures_Private_API.h @@ -0,0 +1,248 @@ +/*! + Multiverse Engine Project 17/1/2016 Dynamic_Library_Subsystem Dynamic_Library_Subsystem_Data_Structures_Private_API.h + + Copyright (C) 2016 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Include guard. */ +#ifndef MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_H +#error "You must include the Dynamic_Library_Subsystem.h header file. It will include all of the other needed headers." +#else +#ifndef MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_DATA_STRUCTURES_PRIVATE_API_H +#define MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_DATA_STRUCTURES_PRIVATE_API_H + +/* Check for C++ Compiler. */ +#ifdef __cplusplus +/* Define extern C. */ +extern "C" { +#endif /* __cplusplus */ + /*! + struct Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private + + This structure is an internal engine structure used to manage dynamicly + loaded libraries that were loaded at runtime via the Dynamic Library Subsystem. + + This structure should NOT be accessed directly as it is subject to change without + warning. You should use the Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library + wrapper instead. + */ + struct Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private + { + bool bIsLoaded; /* Whether or not this library is loaded. */ + bool bLastCallEncounteredAnError; /* + Whether or not this library has encountered an error in the last call. + (Should reset to false when a new call is made and no error occurs.) + */ + + void * osSpecificPointerData; /* + Pointer to an OS specific data structure. + (For example, Windows defines loaded libraries with an HMODULE pointer, + which is needed to unload the library or to search it.) + */ + char * pathToLibrary; /* Path to the dynamic library file on disk. */ + size_t pathToLibraryLength; /* Length of the pathToLibrary c-string in bytes. */ + }; + + /* Create user defined data type for Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private structure. */ + typedef struct Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private; + + /*! + * int Common_Dynamic_Library_Subsystem_Create_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private ** lib) + * + * Creates a Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private data structure in a neutral state. + * + * This function should be called when constructing a Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private object. + * As it will correctly setup said object. + * + * WARNING: The caller is responsible for calling + * Common_Dynamic_Library_Subsystem_Destroy_Loaded_Dynamic_Library_Private() on the successfully created structure. + * + * WARNING: This function will NOT deallocate a preexisting structure, and will overwrite the given pointer if it is + * non-NULL if this function succeeds. Therefore if you need to keep the pointer, copy it elsewhere before calling this + * function. + * + * Returns COMMON_ERROR_SUCCESS if successful. (The created structure will be pointed to by lib.) + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given double pointer is NULL. + * Returns COMMON_ERROR_MEMORY_ERROR if the data structure could not be allocated. + * Otherwise returns the appropriate error code. + * + * No-alteration clause: + * - In case of error, this function will not modify it's arguments. + */ + int Common_Dynamic_Library_Subsystem_Create_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private ** lib); + + /*! + * void Common_Dynamic_Library_Subsystem_Destroy_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private ** lib) + * + * Destroys (frees) a created Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private data structure and set's it's pointer to NULL. + * + * Pram: Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private ** lib, a double pointer to + * a successfully created Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private data structure. + * + * This function has no return. + */ + void Common_Dynamic_Library_Subsystem_Destroy_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private ** lib); + + /*! + * void Common_Dynamic_Library_Subsystem_Blank_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib) + * + * Blanks the given Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private data structure's members. (Deallocating memory for them if needed.) + * + * If given an invalid pointer this function will silently fail. + * + * This function has no return. + */ + void Common_Dynamic_Library_Subsystem_Blank_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib); + + /*! + * int Common_Dynamic_Library_Subsystem_Get_IsLoaded_Loaded_Dynamic_Library_Private(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib) + * + * ACCESSOR FUNCTION. + * + * Returns the status of the bIsLoaded member variable. + * + * Returns COMMON_ERROR_TRUE if the library is loaded. + * Returns COMMON_ERROR_FALSE if the library is NOT loaded. + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * Otherwise returns the appropriate error code. + */ + int Common_Dynamic_Library_Subsystem_Get_IsLoaded_Loaded_Dynamic_Library_Private(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib); + + /*! + * int Common_Dynamic_Library_Subsystem_Set_IsLoaded_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib, const bool value) + * + * ACCESSOR FUNCTION. + * + * Sets the status of the bIsLoaded member variable to the given value. + * + * Returns COMMON_ERROR_SUCCESS if the status was set to the given value successfully. + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * Otherwise returns the appropriate error code. + */ + int Common_Dynamic_Library_Subsystem_Set_IsLoaded_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib, const bool value); + + /*! + * int Common_Dynamic_Library_Subsystem_Get_LastCallEncounteredError_Loaded_Dynamic_Library_Private(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib) + * + * ACCESSOR FUNCTION. + * + * Returns the status of the bLastCallEncounteredAnError member variable. + * + * Returns COMMON_ERROR_TRUE if the last operation on this library encountered an error. + * Returns COMMON_ERROR_FALSE if the last operation on this library did NOT encounter an error. + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * Otherwise returns the appropriate error code. + */ + int Common_Dynamic_Library_Subsystem_Get_LastCallEncounteredError_Loaded_Dynamic_Library_Private(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib); + + /*! + * int Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib, const bool value) + * + * ACCESSOR FUNCTION. + * + * Sets the status of the bLastCallEncounteredAnError member variable to the given value. + * + * Returns COMMON_ERROR_SUCCESS if the status was set to the given value successfully. + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * Otherwise returns the appropriate error code. + */ + int Common_Dynamic_Library_Subsystem_Set_LastCallEncounteredError_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib, const bool value); + + /*! + * int Common_Dynamic_Library_Subsystem_Get_OsSpecificPointerData_Loaded_Dynamic_Library_Private(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib, void ** retVar) + * + * ACCESSOR FUNCTION. + * + * Returns the pointer for the osSpecificPointerData member variable. + * + * WARNING: This function will NOT deallocate a preexisting structure, and will overwrite the given pointer if it is + * non-NULL if this function succeeds. Therefore if you need to keep the pointer, copy it elsewhere before calling this + * function. + * + * WARNING: The caller should NOT deallocate the returned pointer. + * + * Returns COMMON_ERROR_SUCCESS if the data was returned successfully. (retVar will point to the pointer value in this case.) + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * Otherwise returns the appropriate error code. + */ + int Common_Dynamic_Library_Subsystem_Get_OsSpecificPointerData_Loaded_Dynamic_Library_Private(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib, void ** retVar); + + /*! + * int Common_Dynamic_Library_Subsystem_Set_OsSpecificPointerData_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib, void * value) + * + * ACCESSOR FUNCTION. + * + * Sets the pointer for the osSpecificPointerData member variable to the given value. + * + * Returns COMMON_ERROR_SUCCESS if the status was set to the given value successfully. + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * Otherwise returns the appropriate error code. + */ + int Common_Dynamic_Library_Subsystem_Set_OsSpecificPointerData_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib, void * value); + + /*! + * int Common_Dynamic_Library_Subsystem_Get_PathToLibrary_Loaded_Dynamic_Library_Private(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib, const char ** retVar, size_t * retVarLength) + * + * ACCESSOR FUNCTION. + * + * Returns the pointer for the pathToLibrary member variable, and the value of the pathToLibraryLength member variable. + * + * WARNING: This function will NOT deallocate a preexisting structure, and will overwrite the given pointer if it is + * non-NULL if this function succeeds. Therefore if you need to keep the pointer, copy it elsewhere before calling this + * function. + * + * WARNING: The caller should NOT deallocate the returned pointer. + * + * Returns COMMON_ERROR_SUCCESS if the data was returned successfully. (retVar will point to the pointer value in this case.) + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + * Otherwise returns the appropriate error code. + */ + int Common_Dynamic_Library_Subsystem_Get_PathToLibrary_Loaded_Dynamic_Library_Private(const Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib, const char ** retVar, size_t * retVarLength); + + /*! + * int Common_Dynamic_Library_Subsystem_Set_PathToLibrary_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib, const char * value, const size_t valueLength) + * + * ACCESSOR FUNCTION. + * + * Sets the pointer for the pathToLibrary member variable to the given value. + * + * Note this function serves two purposes, to allocate and copy the needed path string into the structure, + * and to deallocate a pre-existing path string in the structure. The mode that is chosen is dependant on the + * arguments given to the function. + * + * I.e. If value is non-NULL and valueLength is greater than zero, then the given path string will be copied. + * If value is NULL, and valueLength is equal to zero, then any pre-existing path string in the structure will be + * deallocated. Any other combination will generate a COMMON_ERROR_INVALID_ARGUMENT error code and the structure + * will not be modified. + * + * Returns COMMON_ERROR_SUCCESS if the status was set to the given value successfully. + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointers or length is NULL. + * Otherwise returns the appropriate error code. + * + * No-alteration clause: + * - In case of error, this function will not modify it's arguments. + */ + int Common_Dynamic_Library_Subsystem_Set_PathToLibrary_Loaded_Dynamic_Library_Private(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library_Private * lib, const char * value, const size_t valueLength); + +#ifdef __cplusplus +} /* End of extern C. */ +#endif /* __cplusplus */ + +#endif /* MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_DATA_STRUCTURES_PRIVATE_API_H */ +#endif /* MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_H */ + +/* End of Dynamic_Library_Subsystem_Data_Structures.h */ diff --git a/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_POSIX.c b/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_POSIX.c index d5fe56f..cb6f4ff 100644 --- a/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_POSIX.c +++ b/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_POSIX.c @@ -17,186 +17,172 @@ Official source repository and project information can be found at https://github.com/codebase7/mengine */ - + +/* Check for linux. */ #ifdef __linux__ -#include "Dynamic_Library_Subsystem.h" -#include // dlopen, dlclose, dlsym, dlerror. +/* Internal includes */ +#include "Dynamic_Library_Subsystem_Syscall.h" +#include "../Error_Handler/Common_Error_Handler_Structures.h" +#include "../Error_Handler/Common_Error_Handler_Error_Codes.h" + +/* External includes. */ +#include /* dlopen, dlclose, dlsym, dlerror. */ + +/* Check for C++ Compiler. */ #ifdef __cplusplus -// Define extern C. +/* Define extern C. */ extern "C" { -#endif - int Common_Dynamic_Library_Subsystem_Load_Library(const char * pathToLibrary, const bool reloadLibrary, Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib) +#endif /* __cplusplus */ + int Common_Dynamic_Library_Subsystem_Load_Library_Syscall(const char * pathToLibrary, const size_t pathToLibraryLength, void ** osSpecificPointerData) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; /* The result of calls to other engine functions. */ + void * callResult = NULL; /* The result of the call to dlopen(). */ + char * hostErr = NULL; /* The result returned from dlerror(). */ + + /* Check for invalid arguments. */ + if ((pathToLibrary != NULL) && (pathToLibraryLength > 0) && (osSpecificPointerData != NULL)) { - // Init vars. - int result = 0; // The result of this function. - void * callResult = NULL; // The result of the call to dlopen(). - - // Check to see if the pointer to the management structure is valid. - if (lib != NULL) - { - // Check to see if pathToLibrary is NULL. - if (pathToLibrary != NULL) - { - // Check to see if the library is loaded. - if ((!lib->bIsLoaded) || (reloadLibrary)) - { - // Check and see if the library is loaded. - if (lib->bIsLoaded) - { - // Call Unload_Library. - result = Common_Dynamic_Library_Subsystem_Unload_Library(lib); - } - - // Only continue if the library was unloaded, or if we did not need to unload the library. - if (result == 0) - { - // Set the values in lib. - lib->bIsLoaded = false; - lib->bLastCallEncounteredAnError = false; - lib->osSpecificPointerData = NULL; - lib->pathToLibrary = pathToLibrary; - - // Call dlopen(). - callResult = dlopen(lib->pathToLibrary, RTLD_LAZY | RTLD_LOCAL); - - // Check the callResult. - if (callResult == NULL) - { - // Could not load the library. - result = -1; - lib->bLastCallEncounteredAnError = true; - } - else - { - // Cast the OS specific data structure pointer to void*. - lib->osSpecificPointerData = callResult; - - // Set bIsLoaded. - lib->bIsLoaded = true; - } - } - else - { - // Encountered an error during the unload. - result = -2; - lib->bLastCallEncounteredAnError = true; - } - } - else - { - // Library is already loaded. - result = 1; - } - } - else - { - // pathToLibrary is NULL. - result = -3; - lib->bLastCallEncounteredAnError = true; - } - } - else - { - // Management structure is invalid. - result = -4; - } - - // Return result. - return result; + /* Call dlopen(). */ + callResult = dlopen(pathToLibrary, RTLD_LAZY | RTLD_LOCAL); + + /* Check the callResult. */ + if (callResult == NULL) + { + /* An error occured. + There is no clean way to check the error given here, as dlerror() returns a human-readable string. + In addition, dlopen() does not have any defined error codes in the POSIX standard. + As such we have no way of returning the specific error encountered to the caller, + so we must return COMMON_ERROR_SYSTEM_SPECIFIC. + */ + ret = COMMON_ERROR_SYSTEM_SPECIFIC; + + /* Could not load the library. */ + hostErr = dlerror(); + COMMON_LOG_VERBOSE("Common_Dynamic_Library_Subsystem_Load_Library_Syscall(): Could not load <"); + COMMON_LOG_VERBOSE(pathToLibrary); + COMMON_LOG_VERBOSE("> Host function returned: "); + COMMON_LOG_VERBOSE(hostErr); + } + else + { + /* Cast the OS specific data structure pointer to void*. */ + (*osSpecificPointerData) = (void*)callResult; + + /* Success. */ + ret = COMMON_ERROR_SUCCESS; + } } + else + { + /* Invalid argument. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Unload_Library_Syscall(void * osData) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; /* The result of calls to other engine functions. */ + char * hostErr = NULL; /* The result returned from dlerror(). */ - int Common_Dynamic_Library_Subsystem_Unload_Library(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib) + /* Check for invalid arguments. */ + if (osData != NULL) { - // Init vars. - int result = 0; // The result of this function. - - // Check to see if the pointer to the management structure is valid. - if (lib != NULL) - { - // Reset bLastCallEncounteredAnError. - lib->bLastCallEncounteredAnError = false; - - // Check for a valid handle. - if ((lib->bIsLoaded) && (lib->osSpecificPointerData != NULL)) - { - // Call dlclose(). - result = dlclose(lib->osSpecificPointerData); - - // Check result. - if (result != 0) - { - // An error occured. - result = -2; - lib->bLastCallEncounteredAnError = true; - } - else - { - // Library unloaded successfully. - lib->osSpecificPointerData = NULL; - lib->bIsLoaded = false; - } - } - else - { - // Library is not loaded. - result = -1; - lib->bLastCallEncounteredAnError = true; - } - } - else - { - // Management structure is invalid. - result = -4; - } - - // Return result. - return result; + /* Call dlclose(). */ + retFromCall = dlclose(osData); + if (retFromCall == 0) + { + /* The library was unloaded successfully. */ + ret = COMMON_ERROR_SUCCESS; + } + else + { + /* An error occured. + There is no clean way to check the error given here, as dlerror() returns a human-readable string. + In addition, dlclose() does not have any defined error codes in the POSIX standard. + As such we have no way of returning the specific error encountered to the caller, + so we must return COMMON_ERROR_SYSTEM_SPECIFIC. + */ + ret = COMMON_ERROR_SYSTEM_SPECIFIC; + + /* Could not load the library. */ + hostErr = dlerror(); + COMMON_LOG_VERBOSE("Common_Dynamic_Library_Subsystem_Unload_Library_Syscall(): Could not unload given library."); + COMMON_LOG_VERBOSE(" Host function returned: "); + COMMON_LOG_VERBOSE(hostErr); + } } + else + { + /* Invalid argument. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Return result. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Get_Symbol_Syscall(void * osData, const char * symbolName, const size_t symbolNameLength, void ** retSym) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; /* The result of calls to other engine functions. */ + void * pSym = NULL; /* The returned symbol pointer. */ + char * hostErr = NULL; /* The result returned from dlerror(). */ - void * Common_Dynamic_Library_Subsystem_Get_Symbol(Common_Dynamic_Library_Subsystem_Loaded_Dynamic_Library *const lib, const char * symbolName) + /* Check for invalid arguments. */ + if ((osData != NULL) && (symbolName != NULL) && (retSym != NULL)) { - // Init vars. - void * result = NULL; // The result of this function. - - // Check to see if the pointer to the management structure is valid. - if (lib != NULL) - { - // Reset bLastCallEncounteredAnError. - lib->bLastCallEncounteredAnError = false; - - // Check to see if symbolName is NULL. - if (symbolName != NULL) - { - // Check to see if we have a valid handle. - if ((lib->bIsLoaded) && (lib->osSpecificPointerData != NULL)) - { - // Call dlerror to clear the error state. - dlerror(); - - // Call dlsym. - result = dlsym(lib->osSpecificPointerData, symbolName); - - // Call dlerror again to check for an error. - if (dlerror() != NULL) - { - // An error occured. - result = NULL; - lib->bLastCallEncounteredAnError = true; - } - } - } - else - { - // symbolName is NULL. - lib->bLastCallEncounteredAnError = true; - } - } - - // Return result. - return result; + /* Call dlerror to clear the error state. */ + dlerror(); + + /* Call dlsym. */ + pSym = dlsym(osData, symbolName); + + /* Call dlerror again to check for an error. */ + hostErr = dlerror(); + if (hostErr != NULL) + { + /* An error occured. + There is no clean way to check the error given here, as dlerror() returns a human-readable string. + In addition, dlsym() does not have any defined error codes in the POSIX standard. + As such we have no way of returning the specific error encountered to the caller, + so we must return COMMON_ERROR_SYSTEM_SPECIFIC. + */ + ret = COMMON_ERROR_SYSTEM_SPECIFIC; + + /* An error occured fetching the symbol. */ + COMMON_LOG_VERBOSE("Common_Dynamic_Library_Subsystem_Get_Symbol_Syscall(): Could not fetch symbol."); + COMMON_LOG_VERBOSE(" Host function returned: "); + COMMON_LOG_VERBOSE(hostErr); + } + else + { + /* Copy pSym to retSym. */ + (*retSym) = pSym; + + /* Success. */ + ret = COMMON_ERROR_SUCCESS; + } } + else + { + /* Invalid argument. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Return result. */ + return ret; + } + #ifdef __cplusplus -} // End of extern C. -#endif -#endif +} /* End of extern C. */ +#endif /* __cplusplus */ +#endif /* __linux__ */ diff --git a/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Syscall.h b/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Syscall.h new file mode 100644 index 0000000..da9f930 --- /dev/null +++ b/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Syscall.h @@ -0,0 +1,121 @@ +/*! + Multiverse Engine Project 23/1/2016 Dynamic_Library_Subsystem Dynamic_Library_Subsystem_Syscall.h + + Copyright (C) 2016 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Include guard. */ +#ifndef MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_SYSCALL_H +#define MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_SYSCALL_H + +/*! + int Common_Dynamic_Library_Subsystem_Load_Library_Syscall( const char * pathToLibrary, + const size_t pathToLibraryLength, + void ** osSpecificPointerData) + + Issues the system call that performs the actual loading of a library. + + NOTE: This function should NOT be called directly by anything except + Common_Dynamic_Library_Subsystem_Load_Library(). Use that function + if you want to load a given library. + + Any reference / data structure returned by the host system call that is required to + reference the loaded library in the future will be pointed to by osSpecificPointerData. + (Memory allocation may be performed here, but any allocation must be deallocated by the + Unload Library syscall function if an allocation is performed.) + + This function also translates any error code given by the host system into a + Common Namespace Error Code before returning it. + + ---General result code list--- + Note: Due to translation of host error codes, ANY Common Namespace Error Code + is possible here: + Returns COMMON_ERROR_SUCCESS if the library was loaded successfully. + + Returns COMMON_ERROR_INVALID_ARGUMENT if one of the given pointers is NULL, + or the length argument is less than or equal to zero. + + Otherwise returns the appropriate error code. + + No-alteration clause: + - In case of error, this function will not modify it's arguments. + */ +int Common_Dynamic_Library_Subsystem_Load_Library_Syscall(const char * pathToLibrary, const size_t pathToLibraryLength, void ** osSpecificPointerData); + +/*! + int Common_Dynamic_Library_Subsystem_Unload_Library_Syscall(void * osData) + + Issues the system call that performs the actual unloading of a library. + + NOTE: This function should NOT be called directly by anything except + Common_Dynamic_Library_Subsystem_Unload_Library(). Use that function + if you want to unload a given library. + + Any allocation made by the Load Library syscall must be deallocated by this function, + if an allocation was performed. + + This function also translates any error code given by the host system into a + Common Namespace Error Code before returning it. + + ---General result code list--- + Note: Due to translation of host error codes, ANY Common Namespace Error Code + is possible here: + Returns COMMON_ERROR_SUCCESS if the library was unloaded successfully. + + Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer is NULL. + + Otherwise returns the appropriate error code. + + No-alteration clause: + - In case of error, this function will not modify it's arguments. + */ +int Common_Dynamic_Library_Subsystem_Unload_Library_Syscall(void * osData); + +/*! + int Common_Dynamic_Library_Subsystem_Get_Symbol_Syscall(void * osData, + const char * symbolName, + const size_t symbolNameLength, + void ** retSym) + + Issues the system call that performs the actual lookup of a given symbol in a given library. + + NOTE: This function should NOT be called directly by anything except + Common_Dynamic_Library_Subsystem_Get_Symbol(). Use that function + if you want to lookup a given symbol. + + This function also translates any error code given by the host system into a + Common Namespace Error Code before returning it. + + ---General result code list--- + Note: Due to translation of host error codes, ANY Common Namespace Error Code + is possible here: + Returns COMMON_ERROR_SUCCESS if the given symbol was found successfully. + (The given symbol will be pointed to by retSym.) + + Returns COMMON_ERROR_INVALID_ARGUMENT if one of the given pointers is NULL, + or the length argument is less than or equal to zero. + + Otherwise returns the appropriate error code. + + No-alteration clause: + - In case of error, this function will not modify it's arguments. + */ +int Common_Dynamic_Library_Subsystem_Get_Symbol_Syscall(void * osData, const char * symbolName, const size_t symbolNameLength, void ** retSym); + +#endif MSYS_DYNAMIC_LIBRARY_SUBSYSTEM_SYSCALL_H + +/* End of Dynamic_Library_Subsystem_Syscall.h. */ diff --git a/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Windows.c b/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Windows.c new file mode 100644 index 0000000..a7ab9ce --- /dev/null +++ b/src/Common/Src/Dynamic_Library_Subsystem/Dynamic_Library_Subsystem_Windows.c @@ -0,0 +1,150 @@ +/*! + Multiverse Engine Project 28/3/2014 Dynamic_Library_Subsystem Dynamic_Library_Subsystem_Windows.c + + Copyright (C) 2014 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Internal includes. */ +#include "Dynamic_Library_Subsystem_Syscall.h" +#include "../Error_Handler/Common_Error_Handler_Structures.h" +#include "../Error_Handler/Common_Error_Handler_Error_Codes.h" +#include "../Error_Handler/Windows_Error_Translation_Table.h" + +/* External includes. */ +#include + +/* Check for C++ Compiler. */ +#ifdef __cplusplus +/* Define extern C. */ +extern "C" { +#endif /* __cplusplus */ + + int Common_Dynamic_Library_Subsystem_Load_Library_Syscall(const char * pathToLibrary, const size_t pathToLibraryLength, void ** osSpecificPointerData) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; /* The result of calls to other engine functions. */ + HMODULE callResult = NULL; /* The result of the call to LoadLibraryEx(). */ + DWORD retLLEX = 0; /* Error code from LoadLibraryEx(). */ + + /* Check for invalid arguments. */ + if ((pathToLibrary != NULL) && (pathToLibraryLength > 0) && (osSpecificPointerData != NULL)) + { + /* Call LoadLibraryEx(). */ + callResult = LoadLibraryEx(pathToLibrary, NULL, 0); + + /* Check the callResult. */ + if (callResult == NULL) + { + /* Get the last error. */ + retLLEX = GetLastError(); + ret = Common_Translate_Windows_Error_Code_To_Common_Error_Code(retLLEX); + } + else + { + /* Cast the OS specific data structure pointer to void*. */ + (*osSpecificPointerData) = ((void*)callResult); + + /* Success. */ + ret = COMMON_ERROR_SUCCESS; + } + } + else + { + /* Invalid argument. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Unload_Library_Syscall(void * osData) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; /* The result of calls to other engine functions. */ + DWORD retFL = 0; /* Error code from FreeLibrary(). */ + + /* Check for invalid arguments. */ + if (osData != NULL) + { + /* Call FreeLibrary. */ + if (FreeLibrary((HMODULE)osData)) + { + /* The library was unloaded successfully. */ + ret = COMMON_ERROR_SUCCESS; + } + else + { + /* Get the last error. */ + retFL = GetLastError(); + ret = Common_Translate_Windows_Error_Code_To_Common_Error_Code(retFL); + } + } + else + { + /* Invalid argument. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; + } + + int Common_Dynamic_Library_Subsystem_Get_Symbol_Syscall(void * osData, const char * symbolName, const size_t symbolNameLength, void ** retSym) + { + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; /* The result of calls to other engine functions. */ + DWORD retGPA = 0; /* Error code from GetProcAddress(). */ + void * pSym = NULL; /* The returned symbol pointer. */ + + /* Check for invalid arguments. */ + if ((osData != NULL) && (symbolName != NULL) && (retSym != NULL)) + { + /* Get the address. */ + pSym = (void*)GetProcAddress((HMODULE)osData, symbolName); + if (pSym == NULL) + { + /* Get the last error. */ + retGPA = GetLastError(); + ret = Common_Translate_Windows_Error_Code_To_Common_Error_Code(retGPA); + } + else + { + /* Copy pSym to retSym. */ + (*retSym) = pSym; + + /* Success. */ + ret = COMMON_ERROR_SUCCESS; + } + } + else + { + /* Invalid argument. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; + } + +#ifdef __cplusplus +} /* End of extern C. */ +#endif /* __cplusplus */ + diff --git a/src/Common/Src/Error_Handler/CMakeLists.txt b/src/Common/Src/Error_Handler/CMakeLists.txt index d3d993d..30642ed 100644 --- a/src/Common/Src/Error_Handler/CMakeLists.txt +++ b/src/Common/Src/Error_Handler/CMakeLists.txt @@ -2,16 +2,56 @@ set(LIBRARY_OUTPUT_PATH ${L_OUTPUT_DIR}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${O_OUTPUT_DIR}) -# Create the error handler. -set (COMMON_ERROR_HANDLER_INCLUDES_BASE Common_Error_Handler.cpp) +# Check for internal mutex support as the error handler uses it. +if (BUILD_FATAL_ERROR_NOTIFY_SUPPORT) + if (BUILD_INTERNAL_MUTEX_SUPPORT) + # Enable the needed flags. + set (COMMON_ERROR_HANDLER_DEFINES MSYS_BUILD_FATAL_ERROR_SUPPORT) + + # Define the link libraries. + set(COMMON_ERROR_HANDLER_LINK_LIBS Common_Mutexes_Multiverse_Engine) + set(COMMON_ERROR_HANDLER_STATIC_LINK_LIBS Common_Mutexes_Multiverse_Engine_Static) + else(BUILD_INTERNAL_MUTEX_SUPPORT) + # No internal mutex support, so skip building the error handler's fatal error notification support. + message(SEND_ERROR "ERROR: Internal mutex support is disabled, and is REQUIRED to build the Common Error Handler's fatal error notification support. Skipping.") + endif(BUILD_INTERNAL_MUTEX_SUPPORT) +endif (BUILD_FATAL_ERROR_NOTIFY_SUPPORT) + +# Create the error handler. (Nasty hack to avoid a warning from GCC about invalid -std:gnu99 flag below....) +set (COMMON_ERROR_HANDLER_C_INCLUDES_BASE Common_Error_Handler.c + Common_Error_Handler_Log_Channel_Defs.c + Common_Error_Handler_Structures.c) +set (COMMON_ERROR_HANDLER_CXX_INCLUDES_BASE Common_Error_Handler_Structures_CPP_Bindings.cpp + Common_Error_Handler_CPP_Bindings.cpp) # Build the posix error translation table if we are running under posix. if (${CMAKE_SYSTEM_NAME} EQUAL "Linux") - set (COMMON_ERROR_HANDLER_INCLUDES ${COMMON_ERROR_HANDLER_INCLUDES_BASE} - Posix_Error_Translation_Table.cpp) + set (COMMON_ERROR_HANDLER_C_INCLUDES ${COMMON_ERROR_HANDLER_C_INCLUDES_BASE} + Posix_Error_Translation_Table.c) + set (COMMON_ERROR_HANDLER_CXX_INCLUDES ${COMMON_ERROR_HANDLER_CXX_INCLUDES_BASE} + Posix_Error_Translation_Table_CPP_Bindings.cpp) +else (${CMAKE_SYSTEM_NAME} EQUAL "Windows") + set (COMMON_ERROR_HANDLER_C_INCLUDES ${COMMON_ERROR_HANDLER_C_INCLUDES_BASE} + Windows_Error_Translation_Table.c) + set (COMMON_ERROR_HANDLER_CXX_INCLUDES ${COMMON_ERROR_HANDLER_CXX_INCLUDES_BASE} + Windows_Error_Translation_Table_CPP_Bindings.cpp) else (${CMAKE_SYSTEM_NAME} EQUAL "Linux") - set (COMMON_ERROR_HANDLER_INCLUDES ${COMMON_ERROR_HANDLER_INCLUDES_BASE}) + set (COMMON_ERROR_HANDLER_C_INCLUDES ${COMMON_ERROR_HANDLER_C_INCLUDES_BASE}) + set (COMMON_ERROR_HANDLER_CXX_INCLUDES ${COMMON_ERROR_HANDLER_CXX_INCLUDES_BASE}) endif (${CMAKE_SYSTEM_NAME} EQUAL "Linux") -add_library(Common_Error_Handler_Multiverse_Engine SHARED ${COMMON_ERROR_HANDLER_INCLUDES}) -add_library(Common_Error_Handler_Multiverse_Engine_Static STATIC ${COMMON_ERROR_HANDLER_INCLUDES}) +# Check for gcc and enable gnu99 extensions if needed. +if (${CMAKE_COMPILER_IS_GNUCC}) + message (STATUS "GCC compiler detected, enabling gnu99 extensions for Common Error Handler.") + set (COMMON_ERROR_HANDLER_C_FLAGS ${COMMON_ERROR_HANDLER_C_FLAGS} -std=gnu99) +endif(${CMAKE_COMPILER_IS_GNUCC}) + +# Create the static library. +add_library(Common_Error_Handler_Multiverse_Engine_Static STATIC ${COMMON_ERROR_HANDLER_C_INCLUDES} ${COMMON_ERROR_HANDLER_CXX_INCLUDES}) +set_property(TARGET Common_Error_Handler_Multiverse_Engine_Static APPEND PROPERTY COMPILE_DEFINITIONS ${COMMON_ERROR_HANDLER_DEFINES}) +target_link_libraries(Common_Error_Handler_Multiverse_Engine_Static ${COMMON_ERROR_HANDLER_STATIC_LINK_LIBS}) + +# Now the shared library. +add_library(Common_Error_Handler_Multiverse_Engine SHARED ${COMMON_ERROR_HANDLER_C_INCLUDES} ${COMMON_ERROR_HANDLER_CXX_INCLUDES}) +set_property(TARGET Common_Error_Handler_Multiverse_Engine_Static APPEND PROPERTY COMPILE_DEFINITIONS ${COMMON_ERROR_HANDLER_DEFINES}) +target_link_libraries(Common_Error_Handler_Multiverse_Engine ${COMMON_ERROR_HANDLER_LINK_LIBS}) diff --git a/src/Common/Src/Error_Handler/Common_Error_Handler.c b/src/Common/Src/Error_Handler/Common_Error_Handler.c new file mode 100644 index 0000000..a71a35f --- /dev/null +++ b/src/Common/Src/Error_Handler/Common_Error_Handler.c @@ -0,0 +1,412 @@ +/*! + Multiverse Engine Project 23/6/2014 Common Common_Error_Handler.c + + Copyright (C) 2014 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Internal includes. */ +#include "Common_Error_Handler.h" /* Main header. */ +#include "Common_Error_Handler_Internal.h" /* Private internal header that defines the structure used for error logging. */ + +/* Only include the mutex header if needed by the fatal error handler. */ +#ifdef MSYS_BUILD_FATAL_ERROR_SUPPORT +#ifdef _WIN32 +#include "..\Mutexes\MSYS_Mutexes.h" /* Internal mutex support. */ +#else +#include "../Mutexes/MSYS_Mutexes.h" /* Internal mutex support. */ +#endif /* _WIN32 */ +#endif /* MSYS_BUILD_FATAL_ERROR_SUPPORT */ + +/* Enable C linkage if needed. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * struct CommonErrorLogData + * + * Private data struct to contain the registered error + * log callback pointer and current log level for the + * Common namespace functions. + * + * Note: We declare this here as the structure + * and it's definition is supposed to be private + * to the engine. DO NOT USE THIS STRUCTURE DIRECTLY! + * This structure is NOT a part of the public API, and + * is subject to change at anytime. + */ +struct CommonErrorLogData { + unsigned int errorLogLevel; // Current log level. + void (*loggingFunct)(const int channelID, const unsigned int logLevel, const char * errorMsg); // Pointer to current callback function. +}; + +/* + * static struct CommonErrorLogData commonErrorLoggingData + * + * The actual data structure that contains the error + * logging data for the Common namespace functions. + * + * Once again, DO NOT USE THIS STRUCTURE DIRECTLY! + * This structure is NOT a part of the public API, and + * is subject to change at anytime. + */ +static struct CommonErrorLogData commonErrorLoggingData = {ERROR_DISABLE, NULL}; + +int Common_Error_Handler_Get_API_Major_Version_Number() +{ + /* Return the API Version number. */ + return MSYS_COMMON_ERROR_HANDLER_API_MAJOR_VER; +} + +int Common_Error_Handler_Get_API_Minor_Version_Number() +{ + /* Return the API Version number. */ + return MSYS_COMMON_ERROR_HANDLER_API_MINOR_VER; +} + +int Common_Error_Handler_Get_API_Revision_Version_Number() +{ + /* Return the API Version number. */ + return MSYS_COMMON_ERROR_HANDLER_API_REVISION_VER; +} + +void Common_Set_Error_Log_Level(const unsigned int logLevel) +{ + /* Set the log level. */ + commonErrorLoggingData.errorLogLevel = logLevel; + + /* Exit function. */ + return; +} + +unsigned int Common_Get_Error_Log_Level() +{ + /* Return the current log level. */ + return commonErrorLoggingData.errorLogLevel; +} + +void Common_Register_Error_Log_Callback(void (*loggingFunction)(const int channelID, const unsigned int logLevel, const char * errorMsg)) +{ + /* Check and see if the pointer is NULL. */ + if (loggingFunction == NULL) + { + /* Set the log level to ERROR_DISABLE. */ + commonErrorLoggingData.errorLogLevel = ERROR_DISABLE; + commonErrorLoggingData.loggingFunct = NULL; + } + else + { + /* Set the pointer. */ + commonErrorLoggingData.loggingFunct = loggingFunction; + } + + /* Exit function. */ + return; +} + +/* Build the Fatal Error Handler if needed. */ +#ifdef MSYS_BUILD_FATAL_ERROR_SUPPORT +/*! + * static size_t registeredFatalErrorCallbackFunctionsSize + * + * This size_t is used to remember the allocated size of the registeredFatalErrorCallbackFunctions array. + */ +static size_t registeredFatalErrorCallbackFunctionsSize = 0; + +/* + * static Common_pErrorCallBackFunction * registeredFatalErrorCallbackFunctions + * + * This pointer to an array contains the callback functions (registered with Common::Register_Fatal_Error_Callback()) + * used to notify the engine's subsystems and the application that a fatal error has occured and the engine's + * process is about to be terminated by the host system. + */ +static Common_pErrorCallBackFunction * registeredFatalErrorCallbackFunctions = NULL; + +/*! + * static MSYS_Mutex * fatalErrorHandlerMutex + * + * This pointer is to an MSYS_Mutex object that is used to control access to the registered fatal error handler + * function pointer list and it's size value. + */ +static MSYS_Mutex * fatalErrorHandlerMutex = NULL; + +bool Common_Register_Fatal_Error_Callback(const Common_pErrorCallBackFunction fatalErrorNotifyFunction) +{ + /* Init vars. */ + bool ret = false; /* The result of this function. */ + size_t previousErrorListSize = registeredFatalErrorCallbackFunctionsSize; /* The size of the previous error list. */ + size_t newErrorListSize = 0; /* The size of the new error list we are creating. */ + size_t x = 0; /* Counter used in for loops. */ + Common_pErrorCallBackFunction * previousErrorList = registeredFatalErrorCallbackFunctions; /* The previous error list. */ + Common_pErrorCallBackFunction * newErrorList = NULL; /* The new error list we are creating. */ + MSYS_Mutex * retFromLockMutex = NULL; /* The result from the call to MSYS_Lock_Mutex(). */ + + /* Check for a valid mutex. */ + if (fatalErrorHandlerMutex == NULL) + { + /* Allocate the mutex. */ + fatalErrorHandlerMutex = MSYS_Create_Mutex(); + } + + /* Lock the error handler mutex. */ + retFromLockMutex = MSYS_Lock_Mutex(fatalErrorHandlerMutex); + if ((retFromLockMutex != NULL) && (retFromLockMutex == fatalErrorHandlerMutex)) + { + /* Check for valid function pointer. */ + if (fatalErrorNotifyFunction != NULL) + { + /* Check for a error function list. */ + if ((previousErrorList != NULL) && (previousErrorListSize > 0)) + { + /* Re-allocate the error list. */ + newErrorList = (Common_pErrorCallBackFunction *)malloc((sizeof(Common_pErrorCallBackFunction) * (previousErrorListSize + 1))); + if (newErrorList != NULL) + { + /* Update the size info. */ + newErrorListSize = (previousErrorListSize + 1); + + /* Copy the data. */ + for (x = 0; x < previousErrorListSize; x++) + { + newErrorList[x] = previousErrorList[x]; + } + } + } + else + { + /* Allocate the error list. */ + newErrorList = (Common_pErrorCallBackFunction *)malloc(sizeof(Common_pErrorCallBackFunction)); + if (newErrorList != NULL) + { + /* Update the size info. */ + newErrorListSize = 1; + } + } + + /* Check for a valid list. */ + if ((previousErrorListSize + 1) == newErrorListSize) + { + /* Register the function. */ + newErrorList[(previousErrorListSize)] = fatalErrorNotifyFunction; + + /* Copy the new list pointer, and size info. */ + registeredFatalErrorCallbackFunctions = newErrorList; + registeredFatalErrorCallbackFunctionsSize = newErrorListSize; + + /* Check and see if we need to deallocate the previousErrorList. */ + if ((previousErrorList != NULL) && (previousErrorList != newErrorList) && (previousErrorListSize > 0)) + { + /* Null out the old pointer list. */ + for (x = 0; x < previousErrorListSize; x++) + { + previousErrorList[x] = NULL; + } + + /* Deallocate the old array. */ + free(previousErrorList); + previousErrorList = NULL; + previousErrorListSize = 0; + } + + /* We are done. */ + ret = true; + } + } + + /* Release the error handler mutex. */ + MSYS_Unlock_Mutex(fatalErrorHandlerMutex); + } + + /* Return the result. */ + return ret; +} + +bool Common_Unregister_Fatal_Error_Callback(const Common_pErrorCallBackFunction fatalErrorNotifyFunction) +{ + /* Init vars. */ + bool ret = false; /* The result of this function. */ + size_t previousErrorListSize = registeredFatalErrorCallbackFunctionsSize; /* The size of the previous error list. */ + size_t newErrorListSize = 0; /* The size of the new error list we are creating. */ + size_t x = 0; /* Counter used in top level for loops. */ + size_t y = 0; /* Counter used in sub level 1 for loops. */ + Common_pErrorCallBackFunction * previousErrorList = registeredFatalErrorCallbackFunctions; /* The previous error list. */ + Common_pErrorCallBackFunction * newErrorList = NULL; /* The new error list we are creating. */ + MSYS_Mutex * retFromLockMutex = NULL; /* The result from the call to MSYS_Lock_Mutex(). */ + + /* Lock the error handler mutex. */ + retFromLockMutex = MSYS_Lock_Mutex(fatalErrorHandlerMutex); + if ((retFromLockMutex != NULL) && (retFromLockMutex == fatalErrorHandlerMutex)) + { + /* Check for valid function pointer. */ + if (fatalErrorNotifyFunction != NULL) + { + /* Check for a error function list. */ + if ((previousErrorList != NULL) && (previousErrorListSize > 0)) + { + /* Check the existing list for that function. */ + for (x = 0; ((newErrorList == NULL) && (x < previousErrorListSize)); x++) + { + /* Check for the correct function, to see if the function was registered previously. */ + if (previousErrorList[x] == fatalErrorNotifyFunction) + { + /* Found the function, so re-allocate the error list so we can remove it. */ + newErrorList = (Common_pErrorCallBackFunction *)malloc((sizeof(Common_pErrorCallBackFunction) * (previousErrorListSize - 1))); + if (newErrorList != NULL) + { + /* Update the size info. */ + newErrorListSize = (previousErrorListSize - 1); + } + } + } + + /* Only continue if the list was reallocated due to us finding the function to remove. */ + if ((newErrorList != NULL) && (newErrorListSize == (previousErrorListSize - 1))) + { + /* Copy the data. */ + for (x = 0, y = 0; ((x < previousErrorListSize) && (y < newErrorListSize)); x++) + { + /* Make sure we don't copy the pointer we are removing. */ + if (previousErrorList[x] != fatalErrorNotifyFunction) + { + /* Copy the pointer, and increment y. (Yes, y can be different than x, because it will not contain every pointer.) */ + newErrorList[y] = previousErrorList[x]; + y++; + } + } + + /* Now that the data is copied, copy the pointers. */ + registeredFatalErrorCallbackFunctions = newErrorList; + registeredFatalErrorCallbackFunctionsSize = newErrorListSize; + + /* Deallocate the old list. */ + if ((previousErrorList != NULL) && (previousErrorList != newErrorList) && (previousErrorListSize > 0)) + { + /* Null out the old pointer list. */ + for (x = 0; x < previousErrorListSize; x++) + { + previousErrorList[x] = NULL; + } + + free(previousErrorList); + previousErrorList = NULL; + previousErrorListSize = 0; + } + + /* Done. */ + ret = true; + } + } + } + + /* Release the error handler mutex. */ + MSYS_Unlock_Mutex(fatalErrorHandlerMutex); + } + + /* Return the result. */ + return ret; +} + +void Common_Fatal_Error_Notify() +{ + /* Init vars. */ + MSYS_Mutex * retFromLockMutex = NULL; /* The result from the call to MSYS_Lock_Mutex(). */ + size_t x = 0; /* Counter used in loops. */ + + /* Lock the error handler mutex. */ + retFromLockMutex = MSYS_Lock_Mutex(fatalErrorHandlerMutex); + if ((retFromLockMutex != NULL) && (retFromLockMutex == fatalErrorHandlerMutex)) + { + /* Check for registered fatal error callbacks. */ + if (registeredFatalErrorCallbackFunctionsSize > 0) + { + /* Begin vector iteration loop. */ + for (x = 0; (x < registeredFatalErrorCallbackFunctionsSize); x++) + { + /* Trigger each function. */ + if (registeredFatalErrorCallbackFunctions[x] != NULL) + { + registeredFatalErrorCallbackFunctions[x](); + } + } + } + + /* Release the error handler mutex. */ + MSYS_Unlock_Mutex(fatalErrorHandlerMutex); + } + + /* Exit function. */ + return; +} + +#endif /* MSYS_BUILD_FATAL_ERROR_SUPPORT */ + +void COMMON_LOG_ERROR(const int channelID, const unsigned int loggingLevel, const char * errorMsg) +{ + /* + * Only do something if the log is enabled, + * the error is at or below our current log level, + * and the logging callback function is defined. + * + * Note: The lower the log level, the higher severity of the error. + */ + if ((commonErrorLoggingData.errorLogLevel != ERROR_DISABLE) && + (commonErrorLoggingData.loggingFunct != NULL) && + (loggingLevel <= commonErrorLoggingData.errorLogLevel) && + (Common_Error_Get_Logging_Channel_Status_By_ID_Number(channelID) == COMMON_ERROR_TRUE)) + { + /* Call the callback. (Hope it returns....) */ + commonErrorLoggingData.loggingFunct(channelID, loggingLevel, errorMsg); + } + + /* Exit function. */ + return; +} + +void COMMON_LOG_CRITICAL(const int channelID, const char * errorMsg) +{ + COMMON_LOG_ERROR(channelID, ERROR_CRITICAL, errorMsg); + return; +} + +void COMMON_LOG_WARNING(const int channelID, const char * errorMsg) +{ + COMMON_LOG_ERROR(channelID, ERROR_WARNING, errorMsg); + return; +} + +void COMMON_LOG_INFO(const int channelID, const char * errorMsg) +{ + COMMON_LOG_ERROR(channelID, ERROR_INFO, errorMsg); + return; +} + +void COMMON_LOG_DEBUG(const int channelID, const char * errorMsg) +{ + COMMON_LOG_ERROR(channelID, ERROR_DEBUG, errorMsg); + return; +} + +void COMMON_LOG_VERBOSE(const int channelID, const char * errorMsg) +{ + COMMON_LOG_ERROR(channelID, ERROR_VERBOSE, errorMsg); + return; +} + +/* End C Linkage if needed. */ +#ifdef __cplusplus +} +#endif /* __cplusplus */ diff --git a/src/Common/Src/Error_Handler/Common_Error_Handler.cpp b/src/Common/Src/Error_Handler/Common_Error_Handler.cpp deleted file mode 100644 index 1ea3719..0000000 --- a/src/Common/Src/Error_Handler/Common_Error_Handler.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/*! - Multiverse Engine Project 23/6/2014 Common Common_Error_Handler.cpp - - Copyright (C) 2014 Multiverse Engine Project - - This program is free software; - you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; - either version 2 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with this program; - if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - Official source repository and project information can be found at - https://github.com/codebase7/mengine -*/ - -#include "Common_Error_Handler.h" // Main header. -#include "Common_Error_Handler_Internal.h" // Private internal header that defines the structure used for error logging. - -const unsigned int Common::Get_Error_Table_Size() -{ - return (sizeof(Common::commonErrorTable) / sizeof(Common_Error_Object)); -} - -const char * Common::Get_Error_Message(const int & errorCode) -{ - // Init vars. - const char * result = NULL; // Result of this function. - const size_t errorTableSize = Common::Get_Error_Table_Size(); // Size of the Common error lookup table. - - // Begin lookup loop. - for (size_t x = 0; ((x < errorTableSize) && (result == NULL)); x++) - { - // Check for the correct error code. - if (Common::commonErrorTable[x].errorCode == errorCode) - { - // Found the correct error code. - result = Common::commonErrorTable[x].error; - } - } - - // If we still can't find the error message to return, use COMMON_UNKNOWN_ERROR - if (result == NULL) - { - result = Common::UNKNOWN_ERROR_MSG; - } - - // Return the result. - return result; -} - -void Common::Set_Error_Log_Level(const unsigned int & logLevel) -{ - // Set the log level. - commonErrorLoggingData.errorLogLevel = logLevel; - - // Exit function. - return; -} - -unsigned int Common::Get_Error_Log_Level() -{ - // Return the current log level. - return commonErrorLoggingData.errorLogLevel; -} - -void Common::Register_Error_Log_Callback(void (*loggingFunction)(const unsigned int logLevel, const char * errorMsg)) -{ - // Check and see if the pointer is NULL. - if (loggingFunction == NULL) - { - // Set the log level to ERROR_DISABLE. - commonErrorLoggingData.errorLogLevel = ERROR_DISABLE; - } - - // Set the pointer. - commonErrorLoggingData.loggingFunct = loggingFunction; - - // Exit function. - return; -} - -void COMMON_LOG_ERROR(const unsigned int loggingLevel, const char * errorMsg) -{ - /* - * Only do something if the log is enabled, - * the error is at or below our current log level, - * and the logging callback function is defined. - * - * Note: The lower the log level, the higher severity of the error. - */ - if ((commonErrorLoggingData.errorLogLevel != ERROR_DISABLE) && - (commonErrorLoggingData.loggingFunct != NULL) && - (loggingLevel <= commonErrorLoggingData.errorLogLevel)) - { - // Call the callback. (Hope it returns....) - commonErrorLoggingData.loggingFunct(loggingLevel, errorMsg); - } - - // Exit function. - return; -} - -void COMMON_LOG_CRITICAL(const char * errorMsg) -{ - COMMON_LOG_ERROR(ERROR_CRITICAL, errorMsg); - return; -} - -void COMMON_LOG_WARNING(const char * errorMsg) -{ - COMMON_LOG_ERROR(ERROR_WARNING, errorMsg); - return; -} - -void COMMON_LOG_INFO(const char * errorMsg) -{ - COMMON_LOG_ERROR(ERROR_INFO, errorMsg); - return; -} - -void COMMON_LOG_DEBUG(const char * errorMsg) -{ - COMMON_LOG_ERROR(ERROR_DEBUG, errorMsg); - return; -} - -void COMMON_LOG_VERBOSE(const char * errorMsg) -{ - COMMON_LOG_ERROR(ERROR_VERBOSE, errorMsg); - return; -} diff --git a/src/Common/Src/Error_Handler/Common_Error_Handler.h b/src/Common/Src/Error_Handler/Common_Error_Handler.h index 3b348b2..fd130e8 100644 --- a/src/Common/Src/Error_Handler/Common_Error_Handler.h +++ b/src/Common/Src/Error_Handler/Common_Error_Handler.h @@ -18,50 +18,201 @@ https://github.com/codebase7/mengine */ -// Include guard. +/* Include guard. */ #ifndef COMMON_ERROR_HANDLER_H #define COMMON_ERROR_HANDLER_H /* Pull in DLL_PORT.h */ #include "../../../DLL_PORT.h" /* Defines MSYS_DLL_EXPORT, and MSYS_DLL_IMPORT_TEMPLATE. */ -// External includes. -#include // Defines NULL. +/* External includes. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ -// Project includes. -#ifdef _WIN32 // Needed for different path seperator in Windows. -#include "..\..\..\Core\Src\Panic_Error_Levels.h" // Defines the log levels. + #include /* Defines NULL. */ + +#ifdef __cplusplus +} /* End of extern C. */ +#endif /* __cplusplus */ + +#ifndef __cplusplus +#if _MSC_FULL_VER && _MSC_FULL_VER < 180031101 /* Visual C versions less than 2013 are special. (They lack support for C99's bool type.) */ +#include "..\..\..\stdbool.h" /* Defines bool data type. (For C compilers.) */ #else -#include "../../../Core/Src/Panic_Error_Levels.h" // Defines the log levels. -#include "Posix_Error_Translation_Table.h" // Defines the POSIX errno to Common namespace error translation table and functions. -#endif // _WIN32 +#include +#endif /* _MSC_FULL_VER && _MSC_FULL_VER < 180031101 */ +#endif /* __cplusplus */ -#include "Common_Error_Handler_Structures.h" // Defines the error codes, error lookup table error lookup table version number, and Common::commonLastErrorCode. +/* Project includes. */ +#ifdef _WIN32 /* Needed for different path seperator in Windows. */ +#include "..\..\..\Core\Src\Panic_Error_Levels.h" /* Defines the log levels. */ +#else +#include "../../../Core/Src/Panic_Error_Levels.h" /* Defines the log levels. */ +#include "Posix_Error_Translation_Table.h" /* Defines the POSIX errno to Common namespace error translation table and functions. */ +#endif /* _WIN32 */ -// Define namespaces. -namespace Common -{ - /*! - * const unsigned int Common::Get_Error_Table_Size() - * - * Returns the size of the common error table. - */ - MSYS_DLL_EXPORT const unsigned int Get_Error_Table_Size(); +#include "Common_Error_Handler_Log_Channel_Defs.h" /* Defines the error log channels and their related functions. */ +#include "Common_Error_Handler_Error_Codes.h" /* Defines error codes. */ +#include "Common_Error_Handler_Structures.h" /* Defines the error codes, error lookup table error lookup table version number, and Common::commonLastErrorCode. */ - /*! - * const char * Common::Get_Error_Message(const int & errorCode) - * - * This function takes the given error code and returns a pointer to a human - * readable string describing the meaning of the given error code. - * - * Returns a valid pointer if the given error code is in the common error table. - * Returns the message for Common::COMMON_UNKNOWN_ERROR otherwise. - */ - MSYS_DLL_EXPORT const char * Get_Error_Message(const int & errorCode); +/* Define the supported API version numbers. */ +#define MSYS_COMMON_ERROR_HANDLER_API_MAJOR_VER 1 +#define MSYS_COMMON_ERROR_HANDLER_API_MINOR_VER 0 +#define MSYS_COMMON_ERROR_HANDLER_API_REVISION_VER 0 + +/* Enable C linkage if needed. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Define the C bindings for the error handler. */ + +/*! + int Common_Error_Handler_Get_API_Major_Version_Number() + + Returns the API major version number for the Common Error Handler. + */ +MSYS_DLL_EXPORT int Common_Error_Handler_Get_API_Major_Version_Number(); + +/*! + int Common_Error_Handler_Get_API_Minor_Version_Number() + + Returns the API minor version number for the Common Error Handler. + */ +MSYS_DLL_EXPORT int Common_Error_Handler_Get_API_Minor_Version_Number(); + +/*! + int Common_Error_Handler_Get_API_Revision_Version_Number() + + Returns the API revision version number for the Common Error Handler. + */ +MSYS_DLL_EXPORT int Common_Error_Handler_Get_API_Revision_Version_Number(); + +/*! + * void Common_Set_Error_Log_Level(const unsigned int & logLevel) + * + * Sets the error logging level for the Common namespace functions. + * + * By default it sets the error logging level to ERROR_DISABLE. + * (Disables all logging. See Core/Src/Panic.h for a list of + * valid logging levels.) + */ +MSYS_DLL_EXPORT void Common_Set_Error_Log_Level(const unsigned int logLevel); + +/*! + * unsigned int Common_Get_Error_Log_Level() + * + * Returns the current error logging level for the Common namespace functions. + * + * See Core/Src/Panic.h for a list of valid logging levels. + */ +MSYS_DLL_EXPORT unsigned int Common_Get_Error_Log_Level(); +/*! + * void Common_Register_Error_Log_Callback(void (*loggingFunction)(const int channelID, const unsigned int logLevel, const char * errorMsg)) + * + * WARNING: The callback function MUST return control back to + * the caller, as the caller will be blocked until the callback + * function returns. + * + * Sets the logging function to call when an error is generated + * by a Common namespace function. + * + * For example, this function can be used to send the generated + * errors to the console in a multi-threaded enviroment. + * + * Passing a NULL pointer to this function (the default) will + * disable calling another function when an error is generated. + * In addition the logging level will be reset to ERROR_DISABLE. + */ +MSYS_DLL_EXPORT void Common_Register_Error_Log_Callback(void (*loggingFunction)(const int channelID, const unsigned int logLevel, const char * errorMsg)); +#ifdef MSYS_BUILD_FATAL_ERROR_SUPPORT + +/*! + * typedef void(*Common_pErrorCallBackFunction)(void) + * + * Defines the function pointer type for use as arguments by the Common fatal error handler functions. + */ +typedef void(*Common_pErrorCallBackFunction)(void); + +/*! + * bool Common_Register_Fatal_Error_Callback(const Common_pErrorCallBackFunction fatalErrorNotifyFunction) + * + * WARNING: The callback function MUST return control back to + * the caller, as the caller will be blocked until the callback + * function returns. This means any other registered callbacks + * will not be triggered, which may lead to data loss. The only exception + * to this is if the host system will kill the engine's process after a set + * amount of time. In this one specific instance, nothing can be done to + * prevent the host system from killing the engine. As such the function + * registered with this call should attempt to clean up and return as + * fast as possible. + * + * Registers a callback function for notification of an engine subsystem + * triggering the host system to kill the engine's process. + * + * Note: The registered callback is not guaranteed to be called at all prior to + * the engine process being terminated. (The host system reserves the right to + * kill the engine without warning it of the impending termination.) + * As such this should be considered an informal notification and not something + * to be relied on if data preservation / security or proper cleanup is required + * prior to engine shutdown. + * + * Returns true if the regisration completed successfully. + * Returns false otherwise. + */ +MSYS_DLL_EXPORT bool Common_Register_Fatal_Error_Callback(const Common_pErrorCallBackFunction fatalErrorNotifyFunction); + +/*! + * bool Common_Unregister_Fatal_Error_Callback(const Common_pErrorCallBackFunction fatalErrorNotifyFunction) + * + * Unregisters the given fatal error callback function from the list of fatal error + * callback functions to be triggered in the event of a fatal error being generated. + * + * (I.e. If unregistered, a given callback function will not be called if a fatal + * error occurs.) + * + * The callback function pointer given to this function must match a function pointer + * given to Common_Register_Fatal_Error_Callback() (Or Common::Register_Fatal_Error_Callback()) previously, + * otherwise this function will fail. + * + * Returns true if the unregisration completed successfully. + * Returns false otherwise. + */ +MSYS_DLL_EXPORT bool Common_Unregister_Fatal_Error_Callback(const Common_pErrorCallBackFunction fatalErrorNotifyFunction); + +/*! + * void Common_Fatal_Error_Notify() + * + * This function triggers the registered fatal error callback functions + * registered with Common_Register_Fatal_Error_Callback() (Or Common::Register_Fatal_Error_Callback()), + * in an attempt to notify all need to know sections of the engine, and application, that the engine is + * about to be terminated. + * + * When this function returns to it's caller, it is expected that the caller + * will terminate the engine's process if it does not happen automaticly. + * + * This function does not return any data to it's caller. + */ +MSYS_DLL_EXPORT void Common_Fatal_Error_Notify(); +#endif /* MSYS_BUILD_FATAL_ERROR_SUPPORT */ + +/* End C Linkage if needed. */ +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/* Define C++ Bindings. */ +#ifdef __cplusplus +/* Define namespaces. */ +namespace Common +{ /*! * void Common::Set_Error_Log_Level(const unsigned int & logLevel) - * + * + * (C++ Binding) + * * Sets the error logging level for the Common namespace functions. * * By default it sets the error logging level to ERROR_DISABLE. @@ -72,7 +223,9 @@ namespace Common /*! * unsigned int Common::Get_Error_Log_Level() - * + * + * (C++ Binding) + * * Returns the current error logging level for the Common namespace functions. * * See Core/Src/Panic.h for a list of valid logging levels. @@ -80,8 +233,10 @@ namespace Common MSYS_DLL_EXPORT unsigned int Get_Error_Log_Level(); /*! - * void Common::Register_Error_Log_Callback(void (*loggingFunction)(const unsigned int logLevel, const char * errorMsg)) - * + * void Common::Register_Error_Log_Callback(void (*loggingFunction)(const int channelID, const unsigned int logLevel, const char * errorMsg)) + * + * (C++ Binding) + * * WARNING: The callback function MUST return control back to * the caller, as the caller will be blocked until the callback * function returns. @@ -96,9 +251,79 @@ namespace Common * disable calling another function when an error is generated. * In addition the logging level will be reset to ERROR_DISABLE. */ - MSYS_DLL_EXPORT void Register_Error_Log_Callback(void (*loggingFunction)(const unsigned int logLevel, const char * errorMsg) = NULL); + MSYS_DLL_EXPORT void Register_Error_Log_Callback(void (*loggingFunction)(const int channelID, const unsigned int logLevel, const char * errorMsg) = NULL); + +#ifdef MSYS_BUILD_FATAL_ERROR_SUPPORT + /*! + * bool Common::Register_Fatal_Error_Callback(const Common_pErrorCallBackFunction fatalErrorNotifyFunction) + * + * (C++ Binding) + * + * WARNING: The callback function MUST return control back to + * the caller, as the caller will be blocked until the callback + * function returns. This means any other registered callbacks + * will not be triggered, which may lead to data loss. The only exception + * to this is if the host system will kill the engine's process after a set + * amount of time. In this one specific instance, nothing can be done to + * prevent the host system from killing the engine. As such the function + * registered with this call should attempt to clean up and return as + * fast as possible. + * + * Registers a callback function for notification of an engine subsystem + * triggering the host system to kill the engine's process. + * + * Note: The registered callback is not guaranteed to be called at all prior to + * the engine process being terminated. (The host system reserves the right to + * kill the engine without warning it of the impending termination.) + * As such this should be considered an informal notification and not something + * to be relied on if data preservation / security or proper cleanup is required + * prior to engine shutdown. + * + * Returns true if the regisration completed successfully. + * Returns false otherwise. + */ + MSYS_DLL_EXPORT bool Register_Fatal_Error_Callback(const Common_pErrorCallBackFunction fatalErrorNotifyFunction); + + /*! + * bool Common::Unregister_Fatal_Error_Callback(const Common_pErrorCallBackFunction fatalErrorNotifyFunction) + * + * (C++ Binding) + * + * Unregisters the given fatal error callback function from the list of fatal error + * callback functions to be triggered in the event of a fatal error being generated. + * + * (I.e. If unregistered, a given callback function will not be called if a fatal + * error occurs.) + * + * The callback function pointer given to this function must match a function pointer + * given to Common_Register_Fatal_Error_Callback() (Or Common::Register_Fatal_Error_Callback()) previously, + * otherwise this function will fail. + * + * Returns true if the unregisration completed successfully. + * Returns false otherwise. + */ + MSYS_DLL_EXPORT bool Unregister_Fatal_Error_Callback(const Common_pErrorCallBackFunction fatalErrorNotifyFunction); + + /*! + * void Common::Fatal_Error_Notify() + * + * (C++ Binding) + * + * This function triggers the registered fatal error callback functions + * registered with Or Common_Register_Fatal_Error_Callback() (Common::Register_Fatal_Error_Callback()), + * in an attempt to notify all need to know sections of the engine, and application, that the engine is + * about to be terminated. + * + * When this function returns to it's caller, it is expected that the caller + * will terminate the engine's process if it does not happen automaticly. + * + * This function does not return any data to it's caller. + */ + MSYS_DLL_EXPORT void Fatal_Error_Notify(); +#endif /* MSYS_BUILD_FATAL_ERROR_SUPPORT */ }; +#endif /* __cplusplus */ -#endif // COMMON_ERROR_HANDLER_H +#endif /* COMMON_ERROR_HANDLER_H */ -// End of Common_Error_Handler.h +/* End of Common_Error_Handler.h */ diff --git a/src/Common/Src/Error_Handler/Common_Error_Handler_CPP_Bindings.cpp b/src/Common/Src/Error_Handler/Common_Error_Handler_CPP_Bindings.cpp new file mode 100644 index 0000000..58a6bea --- /dev/null +++ b/src/Common/Src/Error_Handler/Common_Error_Handler_CPP_Bindings.cpp @@ -0,0 +1,121 @@ +/*! + Multiverse Engine Project 13/5/2015 Common Common_Error_Handler_CPP_Bindings.cpp + + Copyright (C) 2014 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +// Define C++ Bindings. +#ifdef __cplusplus + +// Internal includes. +#include "Common_Error_Handler.h" // Main header. +#include "Common_Error_Handler_Internal.h" // Private internal header that defines the structure used for error logging. + +// External includes. +#include + +/* Define the MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID macro. */ +#define MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID MSYS_ERROR_LOG_CHANNEL_ERROR_HANDLER + +void Common::Set_Error_Log_Level(const unsigned int & logLevel) +{ + Common_Set_Error_Log_Level(logLevel); +} + +unsigned int Common::Get_Error_Log_Level() +{ + return Common_Get_Error_Log_Level(); +} + +void Common::Register_Error_Log_Callback(void (*loggingFunction)(const int channelID, const unsigned int logLevel, const char * errorMsg)) +{ + Common_Register_Error_Log_Callback(loggingFunction); +} + +// Build the Fatal Error Handler if needed. +#ifdef MSYS_BUILD_FATAL_ERROR_SUPPORT + +bool Common::Register_Fatal_Error_Callback(const Common_pErrorCallBackFunction fatalErrorNotifyFunction) +{ + // Init vars. + bool ret = false; // The result of this function. + + // Begin try block. + try { + // Call real function. + ret = Common_Register_Fatal_Error_Callback(fatalErrorNotifyFunction); + } + catch (...) + { + /* + * Great probably a memory allocation error, if so, we don't do anything as the original list is not modifyed + * unless the operations succeed. + * + * If not, well we just destroyed the list of functions we needed to call when a fatal error happened, + * so maybe we should call terminate() here? + */ + ret = false; + } + + // Return the result. + return ret; +} + +bool Common::Unregister_Fatal_Error_Callback(const Common_pErrorCallBackFunction fatalErrorNotifyFunction) +{ + // Init vars. + bool ret = false; // The result of this function. + + // Begin try block. + try { + // Call real function. + ret = Common_Unregister_Fatal_Error_Callback(fatalErrorNotifyFunction); + } + catch (...) + { + /* + * Great probably a memory allocation error, if so, we don't do anything as the original list is not modifyed + * unless the operations succeed. + * + * If not, well we just destroyed the list of functions we needed to call when a fatal error happened, + * so maybe we should call terminate() here? + */ + ret = false; + } + + // Return the result. + return ret; +} + +void Common::Fatal_Error_Notify() +{ + // Begin try block. + try { + // Call real function. + Common_Fatal_Error_Notify(); + } + catch (...) + { + // Well, not much to do here, we are terminating anyway. + COMMON_LOG_CRITICAL(MSYS_SUBSYS_DEFAULT_ERROR_CHANNEL_ID, "Common::Fatal_Error_Notify(): Exception occured while notifying engine subsystems / application that a fatal error occured."); + } +} + +#endif // MSYS_BUILD_FATAL_ERROR_SUPPORT + +#endif // __cplusplus + diff --git a/src/Common/Src/Error_Handler/Common_Error_Handler_Error_Codes.h b/src/Common/Src/Error_Handler/Common_Error_Handler_Error_Codes.h new file mode 100644 index 0000000..37ef4c4 --- /dev/null +++ b/src/Common/Src/Error_Handler/Common_Error_Handler_Error_Codes.h @@ -0,0 +1,102 @@ +/*! + Multiverse Engine Project 05/7/2015 Common Common_Error_Handler_Error_Codes.h + + Copyright (C) 2015 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Include guard. */ +#ifndef COMMON_ERROR_HANDLER_ERROR_CODES_H +#define COMMON_ERROR_HANDLER_ERROR_CODES_H + +/* Common namespace error code definitions. (Human-readable error message translation table is located in Common_Error_Handler_Structures.c) */ + enum { + /* Generic error codes. */ + COMMON_ERROR_SYSTEM_SPECIFIC = 99, + COMMON_ERROR_SUCCESS = 0, + COMMON_ERROR_UNKNOWN_ERROR = -1, + COMMON_ERROR_INVALID_ARGUMENT = -2, + COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED = -3, + COMMON_ERROR_ACCESS_DENIED = -4, + COMMON_ERROR_EXCEPTION_THROWN = -5, + COMMON_ERROR_INTERNAL_ERROR = -6, + COMMON_ERROR_IO_ERROR = -7, + COMMON_ERROR_RANGE_ERROR = -8, + COMMON_ERROR_MEMORY_ERROR = -9, + COMMON_ERROR_INVALID_LIBRARY_ID = -10, /* Formerly THREAD_UTILS_INVALID_LIBRARY_ID. */ + COMMON_ERROR_PEBKAC_INVALID_OPERATION_ORDER = -11, + COMMON_ERROR_CANNOT_GET_SYSTEM_TIME = -12, + COMMON_ERROR_SUBSYSTEM_OBJECT_NOT_INITED = -13, + COMMON_ERROR_SUBSYSTEM_OBJECT_ALREADY_INITED = -14, + COMMON_ERROR_END_OF_DATA = -15, + COMMON_ERROR_COMPARISON_PASSED = -16, + COMMON_ERROR_COMPARISON_FAILED = -17, + COMMON_ERROR_RACE_CONDITION = -18, + COMMON_ERROR_HOST_NOT_SUPPORTED = -19, + COMMON_ERROR_TRUE = -20, + COMMON_ERROR_FALSE = -21, + COMMON_ERROR_ARGUMENT_CONVERSION_FAILURE = -22, + COMMON_ERROR_FALSE_SUCCESS = -23, + + /* Threading Subsystem error codes. */ + THREAD_UTILS_ERROR_EXCEPTION_THROWN = -31, + THREAD_UTILS_ERROR_PLUGIN_LOAD_FAILURE = -32, + THREAD_UTILS_ERROR_THREAD_COULD_NOT_START = -33, + THREAD_UTILS_ERROR_THREAD_COULD_NOT_DETACH = -34, + THREAD_UTILS_ERROR_THREAD_COULD_NOT_JOIN = -35, + THREAD_UTILS_ERROR_MUTEX_ALREADY_LOCKED = -36, + THREAD_UTILS_ERROR_CONDITION_CANNOT_LOCK_MUTEX = -37, + THREAD_UTILS_ERROR_CONDITION_WAIT_TIMEOUT_REACHED = -38, + + /* FileUtills error codes. */ + FILEUTILLS_ERROR_EXISTANT = -60, + FILEUTILLS_ERROR_NON_EXISTANT = -61, + FILEUTILLS_ERROR_READ_ONLY = -62, + FILEUTILLS_ERROR_PATH_LENGTH_INVALID = -63, + FILEUTILLS_ERROR_PATH_FILE_AS_DIRECTORY = -64, + FILEUTILLS_ERROR_PATH_IS_A_FILE = -65, + FILEUTILLS_ERROR_PATH_IS_A_DIRECTORY = -66, + FILEUTILLS_ERROR_PATH_IS_A_SYMLINK = -67, + FILEUTILLS_ERROR_PATH_IS_ABSOLUTE = -68, + FILEUTILLS_ERROR_PATH_IS_RELATIVE = -69, + FILEUTILLS_ERROR_FILESYSTEM_FULL = -70, + FILEUTILLS_ERROR_FILESYSTEM_QUOTA_REACHED = -71, + FILEUTILLS_ERROR_EMPTY_DIRECTORY = -72, + FILEUTILLS_ERROR_NON_EMPTY_DIRECTORY = -73, + FILEUTILLS_ERROR_SYMLINK_CHAIN_TOO_DEEP = -74, + + /* UI Subsystem. */ + UI_SUBSYSTEM_ERROR_EXCEPTION_THROWN = -90, + + /* Dynamic Library Subsystem. */ + DYNLIB_ERROR_INVALID_LIBRARY = -150, + DYNLIB_ERROR_LIBRARY_ALREADY_LOADED = -151, + DYNLIB_ERROR_LIBRARY_NOT_LOADED = -152, + DYNLIB_ERROR_HOST_VS_LIBRARY_MISMATCH = -153, + DYNLIB_ERROR_SYMBOL_NOT_FOUND = -154, + + /* Rendering Subsystem error codes. */ + RENDERER_ERROR_UNABLE_TO_ALLOC_OI_BUF = -175, /* Overlay image buffer. */ + RENDERER_ERROR_UNABLE_TO_ALLOC_TD_BUF = -176, /* Transparency data buffer. */ + RENDERER_ERROR_MEM_BUF_ALLOC_EXCEPTION = -177, + RENDERER_ERROR_DUPE_OVERLAY_EXCEPTION = -178, + RENDERER_ERROR_INVAL_OVERLAY_SELF_OVERWRITE = -179, + RENDERER_ERROR_TRANSPARENCY_DISABLED = -180, + }; + +#endif /* COMMON_ERROR_HANDLER_ERROR_CODES_H */ + +/* End of Common_Error_Handler_Error_Codes.h. */ diff --git a/src/Common/Src/Error_Handler/Common_Error_Handler_Internal.h b/src/Common/Src/Error_Handler/Common_Error_Handler_Internal.h index e938340..9a9d4fd 100644 --- a/src/Common/Src/Error_Handler/Common_Error_Handler_Internal.h +++ b/src/Common/Src/Error_Handler/Common_Error_Handler_Internal.h @@ -18,54 +18,29 @@ https://github.com/codebase7/mengine */ -// Include guard. +/* Include guard. */ #ifndef COMMON_ERROR_HANDLER_INTERNAL_H #define COMMON_ERROR_HANDLER_INTERNAL_H -// Project includes. -#ifdef __win32 // Needed for different path seperator in Windows. -#include "..\..\..\Core\Src\Panic_Error_Levels.h" // Defines the log levels. +/* Project includes. */ +#ifdef _WIN32 /* Needed for different path seperator in Windows. */ +#include "..\..\..\Core\Src\Panic_Error_Levels.h" /* Defines the log levels. */ #else -#include "../../../Core/Src/Panic_Error_Levels.h" // Defines the log levels. -#endif // __win32 +#include "../../../Core/Src/Panic_Error_Levels.h" /* Defines the log levels. */ +#endif /* _WIN32 */ -// Check to see if we are being included directly. -//#ifndef COMMON_ERROR_HANDLER_H -//#error "This header is for internal engine use only. It should not be linked against, as it is NOT a part of the public API." -//#endif // COMMON_ERROR_HANDLER_H +/* Check to see if we are being included directly. */ +/*#ifndef COMMON_ERROR_HANDLER_H */ +/*#error "This header is for internal engine use only. It should not be linked against, as it is NOT a part of the public API." */ +/*#endif COMMON_ERROR_HANDLER_H */ -/* - * struct CommonErrorLogData - * - * Private data struct to contain the registered error - * log callback pointer and current log level for the - * Common namespace functions. - * - * Note: We declare this here as the structure - * and it's definition is supposed to be private - * to the engine. DO NOT USE THIS STRUCTURE DIRECTLY! - * This structure is NOT a part of the public API, and - * is subject to change at anytime. - */ -struct CommonErrorLogData { - unsigned int errorLogLevel; // Current log level. - void (*loggingFunct)(const unsigned int logLevel, const char * errorMsg); // Pointer to current callback function. -}; +/* Enable C linkage if needed. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ /* - * static struct CommonErrorLogData commonErrorLoggingData - * - * The actual data structure that contains the error - * logging data for the Common namespace functions. - * - * Once again, DO NOT USE THIS STRUCTURE DIRECTLY! - * This structure is NOT a part of the public API, and - * is subject to change at anytime. - */ -static struct CommonErrorLogData commonErrorLoggingData = {ERROR_DISABLE, NULL}; - -/* - * void COMMON_LOG_ERROR(const unsigned int loggingLevel, const char * errorMsg) + * void COMMON_LOG_ERROR(const int channelID, const unsigned int loggingLevel, const char * errorMsg) * * This is the actual function that calls the current * error logging callback function for the Common @@ -75,10 +50,10 @@ static struct CommonErrorLogData commonErrorLoggingData = {ERROR_DISABLE, NULL}; * This function is NOT a part of the public API, and * is subject to change at anytime. */ -MSYS_DLL_EXPORT void COMMON_LOG_ERROR(const unsigned int loggingLevel, const char * errorMsg); +MSYS_DLL_EXPORT void COMMON_LOG_ERROR(const int channelID, const unsigned int loggingLevel, const char * errorMsg); /* - * COMMON_LOG_CRITICAL(const char * errorMsg) + * COMMON_LOG_CRITICAL(const int channelID, const char * errorMsg) * * Internal API for calling the current callback error * logging function with a log level of ERROR_CRITICAL. @@ -87,10 +62,10 @@ MSYS_DLL_EXPORT void COMMON_LOG_ERROR(const unsigned int loggingLevel, const cha * This function is NOT a part of the public API, and * is subject to change at anytime. */ -MSYS_DLL_EXPORT void COMMON_LOG_CRITICAL(const char * errorMsg); +MSYS_DLL_EXPORT void COMMON_LOG_CRITICAL(const int channelID, const char * errorMsg); /* - * COMMON_LOG_WARNING(const char * errorMsg) + * COMMON_LOG_WARNING(const int channelID, const char * errorMsg) * * Internal API for calling the current callback error * logging function with a log level of ERROR_WARNING. @@ -99,10 +74,10 @@ MSYS_DLL_EXPORT void COMMON_LOG_CRITICAL(const char * errorMsg); * This function is NOT a part of the public API, and * is subject to change at anytime. */ -MSYS_DLL_EXPORT void COMMON_LOG_WARNING(const char * errorMsg); +MSYS_DLL_EXPORT void COMMON_LOG_WARNING(const int channelID, const char * errorMsg); /* - * COMMON_LOG_INFO(const char * errorMsg) + * COMMON_LOG_INFO(const int channelID, const char * errorMsg) * * Internal API for calling the current callback error * logging function with a log level of ERROR_INFO. @@ -111,10 +86,10 @@ MSYS_DLL_EXPORT void COMMON_LOG_WARNING(const char * errorMsg); * This function is NOT a part of the public API, and * is subject to change at anytime. */ -MSYS_DLL_EXPORT void COMMON_LOG_INFO(const char * errorMsg); +MSYS_DLL_EXPORT void COMMON_LOG_INFO(const int channelID, const char * errorMsg); /* - * COMMON_LOG_DEBUG(const char * errorMsg) + * COMMON_LOG_DEBUG(const int channelID, const char * errorMsg) * * Internal API for calling the current callback error * logging function with a log level of ERROR_DEBUG. @@ -123,10 +98,10 @@ MSYS_DLL_EXPORT void COMMON_LOG_INFO(const char * errorMsg); * This function is NOT a part of the public API, and * is subject to change at anytime. */ -MSYS_DLL_EXPORT void COMMON_LOG_DEBUG(const char * errorMsg); +MSYS_DLL_EXPORT void COMMON_LOG_DEBUG(const int channelID, const char * errorMsg); /* - * COMMON_LOG_VERBOSE(const char * errorMsg) + * COMMON_LOG_VERBOSE(const int channelID, const char * errorMsg) * * Internal API for calling the current callback error * logging function with a log level of ERROR_VERBOSE. @@ -135,8 +110,13 @@ MSYS_DLL_EXPORT void COMMON_LOG_DEBUG(const char * errorMsg); * This function is NOT a part of the public API, and * is subject to change at anytime. */ -MSYS_DLL_EXPORT void COMMON_LOG_VERBOSE(const char * errorMsg); +MSYS_DLL_EXPORT void COMMON_LOG_VERBOSE(const int channelID, const char * errorMsg); + +/* End C Linkage if needed. */ +#ifdef __cplusplus +} +#endif /* __cplusplus */ -#endif // COMMON_ERROR_HANDLER_INTERNAL_H +#endif /* COMMON_ERROR_HANDLER_INTERNAL_H */ -// End of Common_Error_Handler_Internal.h +/* End of Common_Error_Handler_Internal.h */ diff --git a/src/Common/Src/Error_Handler/Common_Error_Handler_Log_Channel_Defs.c b/src/Common/Src/Error_Handler/Common_Error_Handler_Log_Channel_Defs.c new file mode 100644 index 0000000..8d57558 --- /dev/null +++ b/src/Common/Src/Error_Handler/Common_Error_Handler_Log_Channel_Defs.c @@ -0,0 +1,178 @@ +/*! + Multiverse Engine Project 12/2/2016 Common Common_Error_Handler_Log_Channel_Defs.c + + Copyright (C) 2016 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Include headers. */ +#include "Common_Error_Handler_Log_Channel_Defs.h" +#include "Common_Error_Handler_Error_Codes.h" + +/* External includes. */ +#include +#include + +/* Define Common_Error_Log_Channel_Status structure. + + Used internally for managing the states of each logging channel. +*/ +typedef struct Common_Error_Log_Channel_Status { + short disabled; /* Whether or not this channel is disabled. (Messages for disabled channels are discarded.) */ + const int channelID; /* Internal ID number of the channel. */ + const size_t channelNameLength; /* Length of the human readable channel name. */ + const char * const channelName; /* Human readable channel name. */ +} Common_Error_Log_Channel_Status; + +/* Define the internal array for storing the channel statuses. + + Contains a definition for each supported logging channel. +*/ +static Common_Error_Log_Channel_Status commonErrorLoggingChannelStatuses[] = { + {0, MSYS_ERROR_LOG_CHANNEL_UNDEFINED, sizeof(MSYS_ERROR_LOG_CHANNEL_UNDEFINED_NAME), MSYS_ERROR_LOG_CHANNEL_UNDEFINED_NAME}, + {0, MSYS_ERROR_LOG_CHANNEL_USERDEFINED, sizeof(MSYS_ERROR_LOG_CHANNEL_USERDEFINED_NAME), MSYS_ERROR_LOG_CHANNEL_USERDEFINED_NAME}, + {0, MSYS_ERROR_LOG_CHANNEL_ERROR_HANDLER, sizeof(MSYS_ERROR_LOG_CHANNEL_ERROR_HANDLER_NAME), MSYS_ERROR_LOG_CHANNEL_ERROR_HANDLER_NAME}, + {0, MSYS_ERROR_LOG_CHANNEL_DYNLIB, sizeof(MSYS_ERROR_LOG_CHANNEL_DYNLIB_NAME), MSYS_ERROR_LOG_CHANNEL_DYNLIB_NAME}, + {0, MSYS_ERROR_LOG_CHANNEL_BYTEORDER, sizeof(MSYS_ERROR_LOG_CHANNEL_BYTEORDER_NAME), MSYS_ERROR_LOG_CHANNEL_BYTEORDER_NAME}, + {0, MSYS_ERROR_LOG_CHANNEL_FILEUTILLS, sizeof(MSYS_ERROR_LOG_CHANNEL_FILEUTILLS_NAME), MSYS_ERROR_LOG_CHANNEL_FILEUTILLS_NAME}, + {0, MSYS_ERROR_LOG_CHANNEL_THREADUTILS, sizeof(MSYS_ERROR_LOG_CHANNEL_THREADUTILS_NAME), MSYS_ERROR_LOG_CHANNEL_THREADUTILS_NAME}, + {0, MSYS_ERROR_LOG_CHANNEL_RENDERING_SUBSYS, sizeof(MSYS_ERROR_LOG_CHANNEL_RENDERING_SUBSYS_NAME), MSYS_ERROR_LOG_CHANNEL_RENDERING_SUBSYS_NAME}, +}; + +size_t Common_Error_Get_Length_Of_Internal_Status_Array() +{ + /* Internal function to return the length of the commonErrorLoggingChannelStatuses array. + + Should NOT be called outside of this file. + */ + return ((sizeof(Common_Error_Log_Channel_Status) / sizeof(commonErrorLoggingChannelStatuses))); +} + +int Common_Error_Get_Logging_Channel_ID_Number_By_Name(int * channelID, const char * name, const size_t nameLength) +{ + /* Init vars. */ + int ret = COMMON_ERROR_INVALID_ARGUMENT; /* The result of this function. */ + size_t x = 0; /* Counter used in the for loop. */ + + /* Check for valid arguments. */ + if ((channelID != NULL) && (name != NULL) && (nameLength > 0)) + { + /* Begin search loop. */ + for (x = 0; ((ret == COMMON_ERROR_INVALID_ARGUMENT) && (x < Common_Error_Get_Length_Of_Internal_Status_Array())); x++) + { + /* Check the current struct in the array for the given channel name length. */ + if (commonErrorLoggingChannelStatuses[x].channelNameLength == nameLength) + { + /* Check for a valid name pointer. */ + if (commonErrorLoggingChannelStatuses[x].channelName != NULL) + { + /* Check the current struct in the array for the given channel name. */ + if (memcmp(name, commonErrorLoggingChannelStatuses[x].channelName, nameLength) == 0) + { + /* Copy the channel ID value. */ + (*channelID) = commonErrorLoggingChannelStatuses[x].channelID; + + /* Done. */ + ret = COMMON_ERROR_SUCCESS; + } + } + } + } + } + + /* Exit function. */ + return ret; +} + +int Common_Error_Get_Logging_Channel_Name_By_ID_Number(const int channelID, const char ** name, size_t * nameLength) +{ + /* Init vars. */ + int ret = COMMON_ERROR_INVALID_ARGUMENT; /* The result of this function. */ + size_t x = 0; /* Counter used in the for loop. */ + + /* Check for valid arguments. */ + if ((name != NULL) && (nameLength != NULL)) + { + /* Begin search loop. */ + for (x = 0; ((ret == COMMON_ERROR_INVALID_ARGUMENT) && (x < Common_Error_Get_Length_Of_Internal_Status_Array())); x++) + { + /* Check the current struct in the array for the given ID number. */ + if (commonErrorLoggingChannelStatuses[x].channelID == channelID) + { + /* Copy the pointer for the name and the value for the length. */ + (*name) = commonErrorLoggingChannelStatuses[x].channelName; + (*nameLength) = commonErrorLoggingChannelStatuses[x].channelNameLength; + + /* Done. */ + ret = COMMON_ERROR_SUCCESS; + } + } + } + + /* Exit function. */ + return ret; +} + +int Common_Error_Get_Logging_Channel_Status_By_ID_Number(const int channelID) +{ + /* Init vars. */ + int ret = COMMON_ERROR_INVALID_ARGUMENT; /* The result of this function. */ + size_t x = 0; /* Counter used in the for loop. */ + + /* Begin search loop. */ + for (x = 0; ((ret == COMMON_ERROR_INVALID_ARGUMENT) && (x < Common_Error_Get_Length_Of_Internal_Status_Array())); x++) + { + /* Check the current struct in the array for the given ID number. */ + if (commonErrorLoggingChannelStatuses[x].channelID == channelID) + { + /* Check and see if the channel is enabled. + Returns COMMON_ERROR_TRUE if the channel is enabled, or + Returns COMMON_ERROR_FALSE if the channel is disabled. + */ + ret = ((commonErrorLoggingChannelStatuses[x].disabled) ? (COMMON_ERROR_FALSE) : (COMMON_ERROR_TRUE)); + } + } + + /* Exit function. */ + return ret; +} + +int Common_Error_Set_Logging_Channel_Status_By_ID_Number(const int channelID, const short enabled) +{ + /* Init vars. */ + int ret = COMMON_ERROR_INVALID_ARGUMENT; /* The result of this function. */ + size_t x = 0; /* Counter used in the for loop. */ + + /* Begin search loop. */ + for (x = 0; ((ret == COMMON_ERROR_INVALID_ARGUMENT) && (x < Common_Error_Get_Length_Of_Internal_Status_Array())); x++) + { + /* Check the current struct in the array for the given ID number. */ + if (commonErrorLoggingChannelStatuses[x].channelID == channelID) + { + /* Set the channel status. + Set commonErrorLoggingChannelStatuses[x].disabled to non-zero value if the channel should be disabled. + Set commonErrorLoggingChannelStatuses[x].disabled to zero if the channel should be enabled. + */ + commonErrorLoggingChannelStatuses[x].disabled = ((enabled) ? (0) : (1)); + + /* Done. */ + ret = COMMON_ERROR_SUCCESS; + } + } + + /* Exit function. */ + return ret; +} diff --git a/src/Common/Src/Error_Handler/Common_Error_Handler_Log_Channel_Defs.h b/src/Common/Src/Error_Handler/Common_Error_Handler_Log_Channel_Defs.h new file mode 100644 index 0000000..4b487ed --- /dev/null +++ b/src/Common/Src/Error_Handler/Common_Error_Handler_Log_Channel_Defs.h @@ -0,0 +1,125 @@ +/*! + Multiverse Engine Project 12/2/2016 Common Common_Error_Handler_Log_Channel_Defs.h + + Copyright (C) 2016 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Include guard. */ +#ifndef COMMON_ERROR_HANDLER_LOG_CHANNEL_DEFS_H +#define COMMON_ERROR_HANDLER_LOG_CHANNEL_DEFS_H + +/* Internal includes. */ +#include "../../../DLL_PORT.h" + +/* Define error log channels. */ +#define MSYS_ERROR_LOG_CHANNEL_LIST_VER 0 /* Version ID of the channel list. If you change the channel IDs below change the version ID. */ +#define MSYS_ERROR_LOG_CHANNEL_UNDEFINED 0 +#define MSYS_ERROR_LOG_CHANNEL_USERDEFINED 1 +#define MSYS_ERROR_LOG_CHANNEL_ERROR_HANDLER 2 +#define MSYS_ERROR_LOG_CHANNEL_DYNLIB 3 +#define MSYS_ERROR_LOG_CHANNEL_BYTEORDER 4 +#define MSYS_ERROR_LOG_CHANNEL_FILEUTILLS 5 +#define MSYS_ERROR_LOG_CHANNEL_THREADUTILS 6 +#define MSYS_ERROR_LOG_CHANNEL_RENDERING_SUBSYS 7 + +/* Define the human readable error log channel name strings. */ +#define MSYS_ERROR_LOG_CHANNEL_UNDEFINED_NAME "Undefined" +#define MSYS_ERROR_LOG_CHANNEL_USERDEFINED_NAME "User Defined" +#define MSYS_ERROR_LOG_CHANNEL_ERROR_HANDLER_NAME "Error Handler" +#define MSYS_ERROR_LOG_CHANNEL_DYNLIB_NAME "Dynamic Library Subsystem" +#define MSYS_ERROR_LOG_CHANNEL_BYTEORDER_NAME "Byte Order" +#define MSYS_ERROR_LOG_CHANNEL_FILEUTILLS_NAME "File Management Subsystem" +#define MSYS_ERROR_LOG_CHANNEL_THREADUTILS_NAME "Threading Subsystem" +#define MSYS_ERROR_LOG_CHANNEL_RENDERING_SUBSYS_NAME "Rendering Subsystem" + +/* Check for a C++ Compiler. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*! + int Common_Error_Get_Logging_Channel_ID_Number_By_Name(int * channelID, const char * name, const size_t nameLength) + + Takes the given human readable error log channel name (in C-String format) and length, and returns it's associated channel ID number. + + Note: This function will overwrite whatever value is stored by the given channel ID argument. + If you need that value after this function returns, copy it elsewhere before calling this function. + + Returns COMMON_ERROR_SUCCESS if the channel ID was found. (The channel ID argument will be updated in this case.) + Returns COMMON_ERROR_INVALID_ARGUMENT if the given channel name is invalid / not recognized, the given channel name + length is less than or equal to zero, or a given pointer is NULL. + + No-alteration clause: + - In case of error, this function will not modify it's arguments. + */ +MSYS_DLL_EXPORT int Common_Error_Get_Logging_Channel_ID_Number_By_Name(int * channelID, const char * name, const size_t nameLength); + +/*! + int Common_Error_Get_Logging_Channel_Name_By_ID_Number(const int channelID, const char ** name, size_t * nameLength) + + Takes the given error log channel ID number, and returns a pointer to a human readable name in C-String format, along with it's length. + + WARNING: DO NOT ATTEMPT TO DEALLOCATE OR ALTER THIS STRING. IT IS FOR REFERENCE ONLY. + + Note: This function will overwrite whatever values are stored by the given name pointer and length arguments. + If you need those values after this function returns, copy them elsewhere before calling this function. + + Returns COMMON_ERROR_SUCCESS if the channel name was found. (The pointer and length arguments will be updated in this case.) + Returns COMMON_ERROR_INVALID_ARGUMENT if the given channel ID is invalid / not recognized, or a given pointer is NULL. + + No-alteration clause: + - In case of error, this function will not modify it's arguments. + */ +MSYS_DLL_EXPORT int Common_Error_Get_Logging_Channel_Name_By_ID_Number(const int channelID, const char ** name, size_t * nameLength); + +/*! + int Common_Error_Get_Logging_Channel_Status_By_ID_Number(const int channelID) + + Takes the given error log channel ID number, and returns whether or not the channel is enabled. + (If a channel is enabled, it's messages will be sent to the registered error handler callback function. + If a channel is disabled, it's messages will be discarded.) + + Returns COMMON_ERROR_TRUE if the channel is enabled. + Returns COMMON_ERROR_FALSE if the channel is disabled. + Returns COMMON_ERROR_INVALID_ARGUMENT if the given channel ID is invalid / not recognized. + */ +MSYS_DLL_EXPORT int Common_Error_Get_Logging_Channel_Status_By_ID_Number(const int channelID); + +/*! + int Common_Error_Set_Logging_Channel_Status_By_ID_Number(const int channelID, const short enabled) + + Takes the given error log channel ID number, and sets whether or not the channel is enabled. + (If a channel is enabled, it's messages will be sent to the registered error handler callback function. + If a channel is disabled, it's messages will be discarded.) + + Note: This function will return success if the given channel is already set to the given status. + + Pram enabled: If enabled is set to zero, the given channel will be disabled. + If enabled is set to a non-zero value, the given channel will be enabled. + + Returns COMMON_ERROR_SUCCESS if setting the channel's status was successful. + Returns COMMON_ERROR_INVALID_ARGUMENT if the given channel ID is invalid / not recognized. + */ +MSYS_DLL_EXPORT int Common_Error_Set_Logging_Channel_Status_By_ID_Number(const int channelID, const short enabled); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* COMMON_ERROR_HANDLER_LOG_CHANNEL_DEFS_H */ + +/* End of Common_Error_Handler_Log_Channel_Defs.h. */ diff --git a/src/Common/Src/Error_Handler/Common_Error_Handler_Structures.c b/src/Common/Src/Error_Handler/Common_Error_Handler_Structures.c new file mode 100644 index 0000000..00521f1 --- /dev/null +++ b/src/Common/Src/Error_Handler/Common_Error_Handler_Structures.c @@ -0,0 +1,168 @@ +/*! + Multiverse Engine Project 16/5/2015 Common Common_Error_Handler_Structures.c + + Copyright (C) 2015 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Internal Includes. */ +#include "Common_Error_Handler.h" + +/* Enable C linkage if needed. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*! + * const char * COMMON_ERROR_UNKNOWN_ERROR_MSG + * + * This is the definition for the generic unknown error + * code. + * + * It is defined here to allow Common_Get_Error_Message() + * to reference it without needing to use another for loop + * to locate it's offset in the error message table. + */ +const char COMMON_ERROR_UNKNOWN_ERROR_MSG[] = COMMON_UNKNOWN_ERROR_MSG_DEF; + +/*! + * const Common_Error_Object Common_commonErrorTable[] + * + * This array contains all of the error codes that a Common namespace + * function may return, in addition to a human readable string describing + * the error code's meaning. (This is a work in progress, some error codes + * conflict with error codes in other functions, as such these are slowly + * being corrected.) + * + * The easiest way of fetching the human readable string from this table + * is to call Common::GetErrorMessage(). + * + * Do not reuse an existing error code. (If the error is generic then use a + * generic error code.) + * + * Do not change an existing error code. (This is to keep the API stable + * between revisions.) + */ +const Common_Error_Object Common_commonErrorTable[] = { + /* Define the initilizers for the lookup table. */ + {COMMON_ERROR_UNKNOWN_ERROR, COMMON_ERROR_UNKNOWN_ERROR_MSG}, + {COMMON_ERROR_SYSTEM_SPECIFIC, "System specific error code. Check log."}, + {COMMON_ERROR_SUCCESS, "Success."}, + {COMMON_ERROR_INVALID_ARGUMENT, "Invalid argument."}, + {COMMON_ERROR_FUNCTION_NOT_IMPLEMENTED, "Function not implemented."}, + {COMMON_ERROR_ACCESS_DENIED, "Access Denied."}, + {COMMON_ERROR_EXCEPTION_THROWN, "Execption thrown."}, + {COMMON_ERROR_INTERNAL_ERROR, "Internal error."}, + {COMMON_ERROR_IO_ERROR, "Input / Output error. (Normally this is a hardware issue.)"}, + {COMMON_ERROR_RANGE_ERROR, "Given range is invalid."}, + {COMMON_ERROR_MEMORY_ERROR, "Memory error (Could not allocate memory / Control loop out of bounds.)"}, + {COMMON_ERROR_INVALID_LIBRARY_ID, "Given LibraryID does not match a supported library or a loaded plugin."}, + {COMMON_ERROR_PEBKAC_INVALID_OPERATION_ORDER, "Caller is attempting to do something that requires another call / process to be completed first. (Check the order in which you are doing things.)"}, + {COMMON_ERROR_CANNOT_GET_SYSTEM_TIME, "Could not get the system's current time."}, + {COMMON_ERROR_SUBSYSTEM_OBJECT_NOT_INITED, "Given object has not been inited yet."}, + {COMMON_ERROR_SUBSYSTEM_OBJECT_ALREADY_INITED, "Given object has already been inited."}, + {COMMON_ERROR_END_OF_DATA, "There is no remaining data to process."}, + {COMMON_ERROR_COMPARISON_PASSED, "A check passed it's requirements."}, + {COMMON_ERROR_COMPARISON_FAILED, "A check failed to pass it's requirements."}, + {COMMON_ERROR_RACE_CONDITION, "Another process or thread has altered the state of an object needed by the function while the function was using it. Because of the modification to the object, the function could not complete it's task successfully. Please make sure nothing is accessing the needed object before calling the function again."}, + {COMMON_ERROR_HOST_NOT_SUPPORTED, "The host system does not support the requested function / command / feature."}, + {COMMON_ERROR_TRUE, "The result of the previous operation returned true. (See the code documentation for what the result actually means. This is just a generic boolean response.)"}, + {COMMON_ERROR_FALSE, "The result of the previous operation returned false. (See the code documentation for what the result actually means. This is just a generic boolean response.)"}, + {COMMON_ERROR_ARGUMENT_CONVERSION_FAILURE, "A given argument to the previous engine call was not converted properly. (See the code documentation for what the result actually means.)"}, + {COMMON_ERROR_FALSE_SUCCESS, "A success code was returned without a valid result. (AKA. Some expected return value was not obtained, was invalid, corrupted, etc. This can happen when the engine interacts with poorly written / designed code. Including when interacting with itself.)"}, + /* Rendering Subsystem error codes. */ + {RENDERER_ERROR_UNABLE_TO_ALLOC_OI_BUF, "Could not allocate memory for overlay image buffer."}, + {RENDERER_ERROR_UNABLE_TO_ALLOC_TD_BUF, "Could not allocate memory for transparency data buffer."}, + {RENDERER_ERROR_MEM_BUF_ALLOC_EXCEPTION, "Exception thrown while attempting to allocate memory buffer(s)."}, + {RENDERER_ERROR_DUPE_OVERLAY_EXCEPTION, "Exception thrown while duplicating overlay, clearing dest overlay."}, + {RENDERER_ERROR_INVAL_OVERLAY_SELF_OVERWRITE, "Given overlays are the same. Cannot overwrite an overlay with itself."}, + {RENDERER_ERROR_TRANSPARENCY_DISABLED, "Transparency is disabled on given overlay."}, + /* Threading Subsystem (Thread_Utils) error codes. */ + {THREAD_UTILS_ERROR_EXCEPTION_THROWN, "Exception thrown in threading subsystem."}, + {THREAD_UTILS_ERROR_PLUGIN_LOAD_FAILURE, "Unable to load plugin(s). Internal error."}, + {THREAD_UTILS_ERROR_THREAD_COULD_NOT_START, "Could not start new thread."}, + {THREAD_UTILS_ERROR_THREAD_COULD_NOT_DETACH, "Could not detach thread."}, + {THREAD_UTILS_ERROR_THREAD_COULD_NOT_JOIN, "Could not join thread."}, + {THREAD_UTILS_ERROR_MUTEX_ALREADY_LOCKED, "The given mutex is already locked."}, + {THREAD_UTILS_ERROR_CONDITION_WAIT_TIMEOUT_REACHED, "Given timeout period was exceeded while waiting for the condition variable to signal."}, + {THREAD_UTILS_ERROR_CONDITION_CANNOT_LOCK_MUTEX, "Could not lock internal mutex in condition variable object."}, + /* FileUtills. */ + {FILEUTILLS_ERROR_EXISTANT, "The path exists."}, + {FILEUTILLS_ERROR_NON_EXISTANT, "The path (or a component of the path) does not exist."}, + {FILEUTILLS_ERROR_READ_ONLY, "The path is read only."}, + {FILEUTILLS_ERROR_PATH_LENGTH_INVALID, "The path's length is beyond the filesystem's maximum length."}, + {FILEUTILLS_ERROR_PATH_FILE_AS_DIRECTORY, "The path has a file in it that is being treated as a directory."}, + {FILEUTILLS_ERROR_PATH_IS_A_FILE, "Given path is a file."}, + {FILEUTILLS_ERROR_PATH_IS_A_DIRECTORY, "Given path is a directory."}, + {FILEUTILLS_ERROR_PATH_IS_A_SYMLINK, "Given path is a symbolic link."}, + {FILEUTILLS_ERROR_PATH_IS_ABSOLUTE, "Given path is in absolute format (Fully resolved)."}, + {FILEUTILLS_ERROR_PATH_IS_RELATIVE, "Given path is in relative format (Needs resolving)."}, + {FILEUTILLS_ERROR_FILESYSTEM_FULL, "Given filesystem is full."}, + {FILEUTILLS_ERROR_FILESYSTEM_QUOTA_REACHED, "User's disk usage quota for the given filesystem has been reached."}, + {FILEUTILLS_ERROR_EMPTY_DIRECTORY, "The given path is an empty directory."}, + {FILEUTILLS_ERROR_NON_EMPTY_DIRECTORY, "The given path is a non-empty directory."}, + {FILEUTILLS_ERROR_SYMLINK_CHAIN_TOO_DEEP, "While parsing a host-defined symbolic link chain, the host system indicated the link chain was longer than what it supports."}, + /* UI Subsystem */ + {UI_SUBSYSTEM_ERROR_EXCEPTION_THROWN, "An exception was thrown in the UI Subsystem."}, + /* Dynamic Library Subsystem. */ + {DYNLIB_ERROR_INVALID_LIBRARY, "The given library is not recognized by the system. (Invalid container format / not a library / data corruption / etc.)"}, + {DYNLIB_ERROR_LIBRARY_ALREADY_LOADED, "The given library is already loaded."}, + {DYNLIB_ERROR_LIBRARY_NOT_LOADED, "The given library is not currently loaded."}, + {DYNLIB_ERROR_HOST_VS_LIBRARY_MISMATCH, "The given library was built for a different system. (Different OS / Arch / etc.)"}, + {DYNLIB_ERROR_SYMBOL_NOT_FOUND, "The requested symbol was not found in the given library."}, + /* TODO: Need to add the error codes from all common namespace functions. */ +}; + +const unsigned int Common_Get_Error_Table_API_Version() +{ + return COMMON_ERROR_TABLE_ABI_VER; +} + +const unsigned int Common_Get_Error_Table_Size() +{ + return (sizeof(Common_commonErrorTable) / sizeof(Common_Error_Object)); +} + +const char * Common_Get_Error_Message(const int errorCode) +{ + /* Init vars. */ + const char * result = COMMON_ERROR_UNKNOWN_ERROR_MSG; /* Result of this function. */ + const size_t errorTableSize = Common_Get_Error_Table_Size(); /* Size of the Common error lookup table. */ + size_t x = 0; /* Counter used in for loop. */ + + /* Check for COMMON_UNKNOWN_ERROR. */ + if (errorCode != COMMON_ERROR_UNKNOWN_ERROR) + { + /* Begin lookup loop. */ + for (x = 0; ((x < errorTableSize) && (result == COMMON_ERROR_UNKNOWN_ERROR_MSG)); x++) + { + /* Check for the correct error code. */ + if (Common_commonErrorTable[x].errorCode == errorCode) + { + /* Found the correct error code. */ + result = Common_commonErrorTable[x].error; + } + } + } + + /* Return the result. */ + return result; +} + +/* End C Linkage if needed. */ +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ diff --git a/src/Common/Src/Error_Handler/Common_Error_Handler_Structures.h b/src/Common/Src/Error_Handler/Common_Error_Handler_Structures.h index eb656b1..98d6bc8 100644 --- a/src/Common/Src/Error_Handler/Common_Error_Handler_Structures.h +++ b/src/Common/Src/Error_Handler/Common_Error_Handler_Structures.h @@ -23,132 +23,90 @@ #define COMMON_ERROR_HANDLER_STRUCTURES_H /* Internal Includes. */ -#include "Error_Struct.h" // Structure used to create error lookup table. +#include "Error_Struct.h" /* Structure used to create error lookup table. */ +#include "../../../DLL_PORT.h" /* Defines MSYS_DLL_EXPORT. */ -namespace Common { - // Common namespace error code definitions. - // Error code table ABI version. - const unsigned int COMMON_ERROR_ABI_VER = 1; // Increment this if you alter the table. +/* Define the Common unknown error message. (It has to be replicated in two places, once for the C code and once for the C++ bindings.) */ +#define COMMON_UNKNOWN_ERROR_MSG_DEF "Unknown error code." +/* Error code table ABI version. */ +#define COMMON_ERROR_TABLE_ABI_VER 5 /* Increment this if you alter the table. */ + +/* Enable C linkage if needed. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* ERROR CODES MOVED TO Common_Error_Handler_Error_Codes.h */ + +/*! + * const unsigned int Common_Get_Error_Table_API_Version() + * + * Returns the API version number of the common error table. + */ +MSYS_DLL_EXPORT const unsigned int Common_Get_Error_Table_API_Version(); + +/*! + * const unsigned int Common_Get_Error_Table_Size() + * + * Returns the size of the common error table. + */ +MSYS_DLL_EXPORT const unsigned int Common_Get_Error_Table_Size(); + +/*! + * const char * Common_Get_Error_Message(const int & errorCode) + * + * This function takes the given error code and returns a pointer to a human + * readable string describing the meaning of the given error code. + * + * Returns a valid pointer if the given error code is in the common error table. + * Returns the message for Common_COMMON_UNKNOWN_ERROR otherwise. + */ +MSYS_DLL_EXPORT const char * Common_Get_Error_Message(const int errorCode); + +/* End C Linkage if needed. */ +#ifdef __cplusplus +} /* extern C */ +#endif /* __cplusplus */ + +/* Define C++ Bindings. */ +#ifdef __cplusplus +/* Define namespaces. */ +namespace Common +{ /*! - * const static char * Common::UNKNOWN_ERROR_MSG + * const unsigned int Common::Get_Error_Table_API_Version() * - * This is the definition for the generic unknown error - * code. + * (C++ Binding) * - * It is defined here to allow Common::Get_Error_Message() - * to reference it without needing to use another for loop - * to locate it's offset in the error message table. + * Returns the API version number of the common error table. */ - const static char * UNKNOWN_ERROR_MSG = "Unknown error code."; - - // Error code table. - enum { - // Generic error codes. - COMMON_SYSTEM_SPECIFIC = 99, - COMMON_SUCCESS = 0, - COMMON_UNKNOWN_ERROR = -1, - COMMON_INVALID_ARGUMENT = -2, - COMMON_FUNCTION_NOT_IMPLEMENTED = -3, - COMMON_ACCESS_DENIED = -4, - COMMON_EXCEPTION_THROWN = -5, - COMMON_INTERNAL_ERROR = -6, - COMMON_IO_ERROR = -7, - COMMON_RANGE_ERROR = -8, - COMMON_MEMORY_ERROR = -9, - // Rendering Subsystem error codes. - RENDERER_UNABLE_TO_ALLOC_OI_BUF = -12, // Overlay image buffer. - RENDERER_UNABLE_TO_ALLOC_TD_BUF = -13, // Transparency data buffer. - RENDERER_MEM_BUF_ALLOC_EXCEPTION = -14, - RENDERER_DUPE_OVERLAY_EXCEPTION = -15, - RENDERER_INVAL_OVERLAY_SELF_OVERWRITE = -16, - RENDERER_TRANSPARENCY_DISABLED = -17, - // Threading Subsystem error codes. - THREAD_UTILS_EXCEPTION_THROWN = -31, - THREAD_UTILS_INVALID_LIBRARY_ID = -32, - THREAD_UTILS_PLUGIN_LOAD_FAILURE = -33, - // FileUtills error codes. - FILEUTILLS_EXISTANT = -60, - FILEUTILLS_NON_EXISTANT = -61, - FILEUTILLS_READ_ONLY = -62, - FILEUTILLS_PATH_LENGTH_INVALID = -63, - FILEUTILLS_PATH_FILE_AS_DIRECTORY = -64, - FILEUTILLS_PATH_IS_A_FILE = -65, - FILEUTILLS_PATH_IS_A_DIRECTORY = -66, - FILEUTILLS_FILESYSTEM_FULL = -67, - FILEUTILLS_FILESYSTEM_QUOTA_REACHED = -68, - FILEUTILLS_EMPTY_DIRECTORY = -69, - FILEUTILLS_NON_EMPTY_DIRECTORY = -70, - }; + MSYS_DLL_EXPORT const unsigned int Get_Error_Table_API_Version(); /*! - * const Common_Error_Object Common::commonErrorTable[] - * - * This array contains all of the error codes that a Common namespace - * function may return, in addition to a human readable string describing - * the error code's meaning. (This is a work in progress, some error codes - * conflict with error codes in other functions, as such these are slowly - * being corrected.) - * - * The easiest way of fetching the human readable string from this table - * is to call Common::GetErrorMessage(). - * - * Do not reuse an existing error code. (If the error is generic then use a - * generic error code.) - * - * Do not change an existing error code. (This is to keep the API stable - * between revisions.) + * const unsigned int Common::Get_Error_Table_Size() + * + * (C++ Binding) + * + * Returns the size of the common error table. */ - const Common_Error_Object commonErrorTable[] = { - {COMMON_UNKNOWN_ERROR, UNKNOWN_ERROR_MSG}, - {COMMON_SYSTEM_SPECIFIC, "System specific error code. Check log."}, - {COMMON_SUCCESS, "Success."}, - {COMMON_INVALID_ARGUMENT, "Invalid argument."}, - {COMMON_FUNCTION_NOT_IMPLEMENTED, "Function not implemented."}, - {COMMON_ACCESS_DENIED, "Access Denied."}, - {COMMON_EXCEPTION_THROWN, "Execption thrown."}, - {COMMON_INTERNAL_ERROR, "Internal error."}, - {COMMON_IO_ERROR, "Input / Output error. (Normally this is a hardware issue.)"}, - {COMMON_RANGE_ERROR, "Given range is invalid."}, - {COMMON_MEMORY_ERROR, "Memory error (Could not allocate memory / Control loop out of bounds.)"}, - // Rendering Subsystem error codes. - {RENDERER_UNABLE_TO_ALLOC_OI_BUF, "Could not allocate memory for overlay image buffer."}, - {RENDERER_UNABLE_TO_ALLOC_TD_BUF, "Could not allocate memory for transparency data buffer."}, - {RENDERER_MEM_BUF_ALLOC_EXCEPTION, "Exception thrown while attempting to allocate memory buffer(s)."}, - {RENDERER_DUPE_OVERLAY_EXCEPTION, "Exception thrown while duplicating overlay, clearing dest overlay."}, - {RENDERER_INVAL_OVERLAY_SELF_OVERWRITE, "Given overlays are the same. Cannot overwrite an overlay with itself."}, - {RENDERER_TRANSPARENCY_DISABLED, "Transparency is disabled on given overlay."}, - // Threading Subsystem (Thread_Utils) error codes. - {THREAD_UTILS_EXCEPTION_THROWN, "Exception thrown in threading subsystem."}, - {THREAD_UTILS_INVALID_LIBRARY_ID, "Given LibraryID does not match a supported library or a loaded plugin."}, - {THREAD_UTILS_PLUGIN_LOAD_FAILURE, "Unable to load plugin(s). Internal error."}, - // FileUtills. - {FILEUTILLS_EXISTANT, "The path exists."}, - {FILEUTILLS_NON_EXISTANT, "The path (or a component of the path) does not exist."}, - {FILEUTILLS_READ_ONLY, "The path is read only."}, - {FILEUTILLS_PATH_LENGTH_INVALID, "The path's length is beyond the filesystem's maximum length."}, - {FILEUTILLS_PATH_FILE_AS_DIRECTORY, "The path has a file in it that is being treated as a directory."}, - {FILEUTILLS_PATH_IS_A_FILE, "Given path is a file."}, - {FILEUTILLS_PATH_IS_A_DIRECTORY, "Given path is a directory."}, - {FILEUTILLS_FILESYSTEM_FULL, "Given filesystem is full."}, - {FILEUTILLS_FILESYSTEM_QUOTA_REACHED, "User's disk usage quota for the given filesystem has been reached."}, - {FILEUTILLS_EMPTY_DIRECTORY, "The given path is an empty directory."}, - {FILEUTILLS_NON_EMPTY_DIRECTORY, "The given path is a non-empty directory."}, - // TODO: Need to add the error codes from all common namespace functions. - }; + MSYS_DLL_EXPORT const unsigned int Get_Error_Table_Size(); /*! - * static int Common::commonLastErrorCode + * const char * Common::Get_Error_Message(const int & errorCode) + * + * (C++ Binding) * - * Contains the last error code encountered by a Common namespace function. + * This function takes the given error code and returns a pointer to a human + * readable string describing the meaning of the given error code. * - * Note: Calling Common::GetErrorMessage() or Common::GetErrorTableSize() - * will NOT clear this variable. - * Calling any other Common namespace function WILL clear this variable. + * Returns a valid pointer if the given error code is in the common error table. + * Returns the message for Common_COMMON_UNKNOWN_ERROR otherwise. */ - static int commonLastErrorCode = COMMON_SUCCESS; + MSYS_DLL_EXPORT const char * Get_Error_Message(const int & errorCode); }; +#endif /* __cplusplus */ #endif /* COMMON_ERROR_HANDLER_STRUCTURES_H */ -// End of Common_Error_Handler_Structures.h +/* End of Common_Error_Handler_Structures.h */ diff --git a/src/Common/Src/Error_Handler/Common_Error_Handler_Structures_CPP_Bindings.cpp b/src/Common/Src/Error_Handler/Common_Error_Handler_Structures_CPP_Bindings.cpp new file mode 100644 index 0000000..0fd7237 --- /dev/null +++ b/src/Common/Src/Error_Handler/Common_Error_Handler_Structures_CPP_Bindings.cpp @@ -0,0 +1,41 @@ +/*! + Multiverse Engine Project 16/5/2015 Common Common_Error_Handler_Structures_CPP_Bindings.cpp + + Copyright (C) 2015 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +// Internal Includes. +#include "Common_Error_Handler.h" + +// Define C++ Bindings. +#ifdef __cplusplus + +const unsigned int Common::Get_Error_Table_API_Version() +{ + return Common_Get_Error_Table_API_Version(); +} + +const unsigned int Common::Get_Error_Table_Size() +{ + return Common_Get_Error_Table_Size(); +} + +const char * Common::Get_Error_Message(const int & errorCode) +{ + return Common_Get_Error_Message(errorCode); +} +#endif // __cplusplus diff --git a/src/Common/Src/Error_Handler/Error_Struct.h b/src/Common/Src/Error_Handler/Error_Struct.h index d551a0a..e08b1b0 100644 --- a/src/Common/Src/Error_Handler/Error_Struct.h +++ b/src/Common/Src/Error_Handler/Error_Struct.h @@ -18,14 +18,31 @@ https://github.com/codebase7/mengine */ +// Include guard. #ifndef ERROR_STRUCT_H #define ERROR_STRUCT_H -struct Common_Error_Object { +// Enable C linkage if needed. +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/*! + * typedef struct Common_Error_Object_T + * + * Defines the data structure used by the Common Error Handler functions + * to look up human-readable strings and their assoicated error codes. + */ +typedef struct Common_Error_Object_T { short errorCode; const char * error; -}; +} Common_Error_Object; + +// End C Linkage if needed. +#ifdef __cplusplus +} +#endif // __cplusplus -#endif +#endif // ERROR_STRUCT_H -// End of Error_Struct.h \ No newline at end of file +// End of Error_Struct.h diff --git a/src/Common/Src/Error_Handler/Posix_Error_Translation_Table.cpp b/src/Common/Src/Error_Handler/Posix_Error_Translation_Table.c similarity index 60% rename from src/Common/Src/Error_Handler/Posix_Error_Translation_Table.cpp rename to src/Common/Src/Error_Handler/Posix_Error_Translation_Table.c index edfe8c1..e33fe41 100644 --- a/src/Common/Src/Error_Handler/Posix_Error_Translation_Table.cpp +++ b/src/Common/Src/Error_Handler/Posix_Error_Translation_Table.c @@ -1,5 +1,5 @@ /*! - Multiverse Engine Project 05/7/2014 Common Posix_Error_Translation_Table.cpp + Multiverse Engine Project 05/7/2014 Common Posix_Error_Translation_Table.c Copyright (C) 2014 Multiverse Engine Project @@ -22,33 +22,48 @@ #include "Common_Error_Handler_Structures.h" #include "Posix_Error_Translation_Table.h" -unsigned int Common::Get_Posix_Error_Translation_Table_Size() +// Include Extern C if needed. +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +const unsigned int Common_Get_Posix_Error_Translation_Table_API_Version() +{ + return COMMON_POSIX_ERROR_TRANSLATION_TABLE_API_VERSION; +} + +const unsigned int Common_Get_Posix_Error_Translation_Table_Size() { - return (sizeof(Common::posixErrorTranslationTable) / sizeof(Common::posixErrnoTableEntry)); + return (sizeof(Common_posixErrorTranslationTable) / sizeof(Common_posixErrnoTableEntry)); } -int Common::Translate_Posix_Errno_To_Common_Error_Code(const int & err) +int Common_Translate_Posix_Errno_To_Common_Error_Code(const int err) { // Init result. - int ret = COMMON_SYSTEM_SPECIFIC; /* - * Default is COMMON_SYSTEM_SPECIFIC, as + int ret = COMMON_ERROR_SYSTEM_SPECIFIC; /* + * Default is COMMON_ERROR_SYSTEM_SPECIFIC, as * not all POSIX errno(s) are / can be * reperesented in the Common namespace * error code table. */ // Run loop. - for (unsigned int x = 0; ((x < Common::Get_Posix_Error_Translation_Table_Size()) && - (ret == COMMON_SYSTEM_SPECIFIC)); x++) + for (unsigned int x = 0; ((x < Common_Get_Posix_Error_Translation_Table_Size()) && + (ret == COMMON_ERROR_SYSTEM_SPECIFIC)); x++) { // Check for a match in the error code translation table. - if (Common::posixErrorTranslationTable[x].posixErrorNo == err) + if (Common_posixErrorTranslationTable[x].posixErrorNo == err) { // Match found, return the Common namespace error code. - ret = Common::posixErrorTranslationTable[x].commonErrorCode; + ret = Common_posixErrorTranslationTable[x].commonErrorCode; } } // Return the result. return ret; -} \ No newline at end of file +} + +// Terminate C linkage if needed. +#ifdef __cplusplus +} +#endif // __cplusplus diff --git a/src/Common/Src/Error_Handler/Posix_Error_Translation_Table.h b/src/Common/Src/Error_Handler/Posix_Error_Translation_Table.h index 25d3ab6..671704b 100644 --- a/src/Common/Src/Error_Handler/Posix_Error_Translation_Table.h +++ b/src/Common/Src/Error_Handler/Posix_Error_Translation_Table.h @@ -25,66 +25,143 @@ // Include POSIX errno header. #include +// Enable C linkage if needed. +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/*! + * #define COMMON_POSIX_ERROR_TRANSLATION_TABLE_API_VERSION + * + * Defines the API version of the posix errno to + * common namespace error code translation table. + * + * If you change the table increment the version + * number. + */ +#define COMMON_POSIX_ERROR_TRANSLATION_TABLE_API_VERSION 1 + +/*! + * typedef struct Common_posixErrnoTableEntry_T Common_posixErrnoTableEntry + * + * (C Binding.) + * + * Used to construct the errno translation table. + * for POSIX compliant systems. + */ +typedef struct Common_posixErrnoTableEntry_T { + int posixErrorNo; + int commonErrorCode; +} Common_posixErrnoTableEntry; + +/*! + * const static Common_posixErrnoTableEntry Common_posixErrorTranslationTable[] + * + * A table that contains (some) POSIX errno codes and their + * Common namespace error code equilivants. + * + * Not all POSIX errno(s) are present in this table, as + * some POSIX errno(s) are specific to POSIX compliant + * systems. As such there is no Common namespace error + * code (beyond COMMON_SYSTEM_SPECIFIC) to represent them. + */ +const static Common_posixErrnoTableEntry Common_posixErrorTranslationTable[] = { + {EACCES, COMMON_ERROR_ACCESS_DENIED}, + {ENOENT, FILEUTILLS_ERROR_NON_EXISTANT}, + {EEXIST, FILEUTILLS_ERROR_EXISTANT}, + {EROFS, FILEUTILLS_ERROR_READ_ONLY}, + {EINVAL, COMMON_ERROR_INVALID_ARGUMENT}, + {ENAMETOOLONG, FILEUTILLS_ERROR_PATH_LENGTH_INVALID}, + {ENOTDIR, FILEUTILLS_ERROR_PATH_FILE_AS_DIRECTORY}, + {ENOMEM, COMMON_ERROR_MEMORY_ERROR}, + {EFAULT, COMMON_ERROR_INVALID_ARGUMENT}, + {ENOSPC, FILEUTILLS_ERROR_FILESYSTEM_FULL}, + {EDQUOT, FILEUTILLS_ERROR_FILESYSTEM_QUOTA_REACHED}, + {ENOTEMPTY, FILEUTILLS_ERROR_NON_EMPTY_DIRECTORY}, +}; + +/*! + * const unsigned int Common_Get_Posix_Error_Translation_Table_API_Version() + * + * Returns the API Version number of the Common_posixErrorTranslationTable + * array. + */ +const unsigned int Common_Get_Posix_Error_Translation_Table_API_Version(); + +/*! + * const unsigned int Common_Get_Posix_Error_Translation_Table_Size() + * + * Returns the size of the Common::posixErrorTranslationTable + * array. + */ +const unsigned int Common_Get_Posix_Error_Translation_Table_Size(); + +/*! + * int Common_Translate_Posix_Errno_To_Common_Error_Code(const int err) + * + * Translates the given POSIX errno to it's Common namespace + * error code equilivant. (If applicable.) + * + * WARNING: Because the POSIX errno variable is global, you + * should never call this function passing errno directly. + * + * Instead, copy the errno to a temporary variable and then + * pass the temporary variable to this function. + * + * (Otherwise just calling this function could change errno + * before it is checked.) + * + * @pram const int err, the POSIX error code to translate. + * + * Returns the translated Common namespace error code if applicable. + * + * Returns COMMON_SYSTEM_SPECIFIC if the POSIX errno does not have a + * Common namespace error code translation. + */ +int Common_Translate_Posix_Errno_To_Common_Error_Code(const int err); + +// End C Linkage if needed. +#ifdef __cplusplus +} +#endif // __cplusplus + +// Check for a C compiler. +#ifdef __cplusplus namespace Common { /*! - * struct Common::posixErrnoTableEntry - * + * typedef Common_posixErrnoTableEntry Common::posixErrnoTableEntry + * + * (C++ Binding.) + * * Used to construct the errno translation table. * for POSIX compliant systems. */ - struct posixErrnoTableEntry{ - int posixErrorNo; - int commonErrorCode; - }; + typedef Common_posixErrnoTableEntry posixErrnoTableEntry; /*! - * const int posixErrorTranslationTableAPIVersion - * - * Defines the API version of the posix errno to - * common namespace error code translation table. - * - * If you change the table increment the version - * number. - */ - const int posixErrorTranslationTableAPIVersion = 1; - - /*! - * const Common::posixErrnoTableEntry Common::posixErrorTranslationTable[] - * - * A table that contains (some) POSIX errno codes and their - * Common namespace error code equilivants. + * const unsigned int Common::Get_Posix_Error_Translation_Table_API_Version() * - * Not all POSIX errno(s) are present in this table, as - * some POSIX errno(s) are specific to POSIX compliant - * systems. As such there is no Common namespace error - * code (beyond COMMON_SYSTEM_SPECIFIC) to represent them. + * Returns the API Version number of the Common_posixErrorTranslationTable + * array. */ - const posixErrnoTableEntry posixErrorTranslationTable[] = { - {EACCES, Common::COMMON_ACCESS_DENIED}, - {ENOENT, Common::FILEUTILLS_NON_EXISTANT}, - {EEXIST, Common::FILEUTILLS_EXISTANT}, - {EROFS, Common::FILEUTILLS_READ_ONLY}, - {EINVAL, Common::COMMON_INVALID_ARGUMENT}, - {ENAMETOOLONG, Common::FILEUTILLS_PATH_LENGTH_INVALID}, - {ENOTDIR, Common::FILEUTILLS_PATH_FILE_AS_DIRECTORY}, - {ENOMEM, Common::COMMON_MEMORY_ERROR}, - {EFAULT, Common::COMMON_INVALID_ARGUMENT}, - {ENOSPC, Common::FILEUTILLS_FILESYSTEM_FULL}, - {EDQUOT, Common::FILEUTILLS_FILESYSTEM_QUOTA_REACHED}, - }; + const unsigned int Get_Posix_Error_Translation_Table_API_Version(); /*! - * unsigned int Common::Get_Posix_Error_Translation_Table_Size() - * + * const unsigned int Common::Get_Posix_Error_Translation_Table_Size() + * + * (C++ Binding) + * * Returns the size of the Common::posixErrorTranslationTable * array. */ - unsigned int Get_Posix_Error_Translation_Table_Size(); + const unsigned int Get_Posix_Error_Translation_Table_Size(); /*! * int Common::Translate_Posix_Errno_To_Common_Error_Code(const int & err) - * + * + * (C++ Binding) + * * Translates the given POSIX errno to it's Common namespace * error code equilivant. (If applicable.) * @@ -106,6 +183,7 @@ namespace Common */ int Translate_Posix_Errno_To_Common_Error_Code(const int & err); }; +#endif // __cplusplus #endif // POSIX_ERROR_TRANSLATION_TABLE_H diff --git a/src/Common/Src/Error_Handler/Posix_Error_Translation_Table_CPP_Bindings.cpp b/src/Common/Src/Error_Handler/Posix_Error_Translation_Table_CPP_Bindings.cpp new file mode 100644 index 0000000..96c7adb --- /dev/null +++ b/src/Common/Src/Error_Handler/Posix_Error_Translation_Table_CPP_Bindings.cpp @@ -0,0 +1,45 @@ +/*! + Multiverse Engine Project 15/5/2015 Common Posix_Error_Translation_Table_CPP_Bindings.cpp + + Copyright (C) 2015 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +// C++ Bindings. +#ifdef __cplusplus + +// Internal includes. +#include "Common_Error_Handler_Structures.h" +#include "Posix_Error_Translation_Table.h" + +// External includes. +#include + +const unsigned int Common::Get_Posix_Error_Translation_Table_API_Version() +{ + return Common_Get_Posix_Error_Translation_Table_API_Version(); +} + +const unsigned int Common::Get_Posix_Error_Translation_Table_Size() +{ + return Common_Get_Posix_Error_Translation_Table_Size(); +} + +int Common::Translate_Posix_Errno_To_Common_Error_Code(const int & err) +{ + return Common_Translate_Posix_Errno_To_Common_Error_Code(err); +} +#endif // __cplusplus diff --git a/src/Common/Src/Error_Handler/Windows_Error_Translation_Table.c b/src/Common/Src/Error_Handler/Windows_Error_Translation_Table.c new file mode 100644 index 0000000..77758ec --- /dev/null +++ b/src/Common/Src/Error_Handler/Windows_Error_Translation_Table.c @@ -0,0 +1,70 @@ +/*! + Multiverse Engine Project 17/1/2016 Common Windows_Error_Translation_Table.c + + Copyright (C) 2016 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Internal includes. */ +#include "Common_Error_Handler_Structures.h" +#include "Windows_Error_Translation_Table.h" + +/* Include Extern C if needed. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +const unsigned int Common_Get_Windows_Error_Translation_Table_API_Version() +{ + return COMMON_WINDOWS_ERROR_TRANSLATION_TABLE_API_VERSION; +} + +const unsigned int Common_Get_Windows_Error_Translation_Table_Size() +{ + return (sizeof(Common_windowsErrorTranslationTable) / sizeof(Common_windowsErrorCodeTableEntry)); +} + +int Common_Translate_Windows_Error_Code_To_Common_Error_Code(const DWORD err) +{ + /* Init result. */ + int ret = COMMON_ERROR_SYSTEM_SPECIFIC; /* + * Default is COMMON_ERROR_SYSTEM_SPECIFIC, as + * not all Windows error codes are / can be + * reperesented in the Common namespace + * error code table. + */ + unsigned int x = 0; /* Loop counter */ + + /* Run loop. */ + for (x = 0; ((x < Common_Get_Windows_Error_Translation_Table_Size()) && + (ret == COMMON_ERROR_SYSTEM_SPECIFIC)); x++) + { + /* Check for a match in the error code translation table. */ + if (Common_windowsErrorTranslationTable[x].windowsErrorCode == err) + { + /* Match found, return the Common namespace error code. */ + ret = Common_windowsErrorTranslationTable[x].commonErrorCode; + } + } + + /* Return the result. */ + return ret; +} + +/* Terminate C linkage if needed. */ +#ifdef __cplusplus +} +#endif /* __cplusplus */ diff --git a/src/Common/Src/Error_Handler/Windows_Error_Translation_Table.h b/src/Common/Src/Error_Handler/Windows_Error_Translation_Table.h new file mode 100644 index 0000000..a28a552 --- /dev/null +++ b/src/Common/Src/Error_Handler/Windows_Error_Translation_Table.h @@ -0,0 +1,189 @@ +/*! + Multiverse Engine Project 17/1/2016 Common Windows_Error_Translation_Table.h + + Copyright (C) 2016 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Include guard. */ +#ifndef WINDOWS_ERROR_TRANSLATION_TABLE_H +#define WINDOWS_ERROR_TRANSLATION_TABLE_H + +/* Include common error code definitions. */ +#include "Common_Error_Handler_Error_Codes.h" + +/* Include Windows headers. */ +#include +#include + +/* Enable C linkage if needed. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*! + * #define COMMON_WINDOWS_ERROR_TRANSLATION_TABLE_API_VERSION + * + * Defines the API version of the Windows Error code to + * common namespace error code translation table. + * + * If you change the table increment the version + * number. + */ +#define COMMON_WINDOWS_ERROR_TRANSLATION_TABLE_API_VERSION 1 + +/*! + * typedef struct Common_windowsErrorCodeTableEntry_T Common_windowsErrorCodeTableEntry_T + * + * (C Binding.) + * + * Used to construct the error code translation table + * for Windows systems. + */ +typedef struct Common_windowsErrorCodeTableEntry_T { + int windowsErrorCode; + int commonErrorCode; +} Common_windowsErrorCodeTableEntry; + +/*! + * const static Common_windowsErrorCodeTableEntry Common_windowsErrorTranslationTable[] + * + * A table that contains (some) Windows error codes and their + * Common namespace error code equilivants. + * + * Not all Windows error codes are present in this table. + */ +const static Common_windowsErrorCodeTableEntry Common_windowsErrorTranslationTable[] = { + {ERROR_SUCCESS, COMMON_ERROR_SUCCESS}, + {ERROR_ACCESS_DENIED, COMMON_ERROR_ACCESS_DENIED}, + {ERROR_PATH_NOT_FOUND, FILEUTILLS_ERROR_NON_EXISTANT}, + {ERROR_FILE_NOT_FOUND, FILEUTILLS_ERROR_NON_EXISTANT}, + {ERROR_INVALID_HANDLE, COMMON_ERROR_INVALID_ARGUMENT}, + {ERROR_TOO_MANY_OPEN_FILES, COMMON_ERROR_MEMORY_ERROR}, + {ERROR_ARENA_TRASHED, COMMON_ERROR_MEMORY_ERROR}, + {ERROR_NOT_ENOUGH_MEMORY, COMMON_ERROR_MEMORY_ERROR}, + {ERROR_INVALID_BLOCK, COMMON_ERROR_INVALID_ARGUMENT}, + {ERROR_INVALID_ACCESS, COMMON_ERROR_ACCESS_DENIED}, + {ERROR_OUTOFMEMORY, COMMON_ERROR_MEMORY_ERROR}, + {ERROR_INVALID_DRIVE, FILEUTILLS_ERROR_NON_EXISTANT}, + {ERROR_CURRENT_DIRECTORY, COMMON_ERROR_PEBKAC_INVALID_OPERATION_ORDER}, + {ERROR_NO_MORE_FILES, COMMON_ERROR_END_OF_DATA}, + {ERROR_WRITE_PROTECT, FILEUTILLS_ERROR_READ_ONLY}, + {ERROR_BAD_LENGTH, COMMON_ERROR_INVALID_ARGUMENT}, + {ERROR_BAD_COMMAND, COMMON_ERROR_INVALID_ARGUMENT}, + {ERROR_WRITE_FAULT, COMMON_ERROR_IO_ERROR}, + {ERROR_READ_FAULT, COMMON_ERROR_IO_ERROR}, + {ERROR_HANDLE_DISK_FULL, FILEUTILLS_ERROR_FILESYSTEM_FULL}, + {ERROR_NOT_SUPPORTED, COMMON_ERROR_HOST_NOT_SUPPORTED}, + {ERROR_FILE_EXISTS, FILEUTILLS_ERROR_EXISTANT}, + {ERROR_CANNOT_MAKE, COMMON_ERROR_IO_ERROR}, + {ERROR_BUFFER_OVERFLOW, COMMON_ERROR_INVALID_ARGUMENT}, + {ERROR_DISK_FULL, FILEUTILLS_ERROR_FILESYSTEM_FULL}, + {ERROR_BAD_DRIVER_LEVEL, COMMON_ERROR_HOST_NOT_SUPPORTED}, + {ERROR_CALL_NOT_IMPLEMENTED, COMMON_ERROR_HOST_NOT_SUPPORTED}, + {ERROR_INSUFFICIENT_BUFFER, COMMON_ERROR_INVALID_ARGUMENT}, +}; + +/*! + * const unsigned int Common_Get_Windows_Error_Translation_Table_API_Version() + * + * Returns the API Version number of the Common_windowsErrorTranslationTable + * array. + */ +MSYS_DLL_EXPORT const unsigned int Common_Get_Windows_Error_Translation_Table_API_Version(); + +/*! + * const unsigned int Common_Get_Windows_Error_Translation_Table_Size() + * + * Returns the size of the Common_windowsErrorTranslationTable + * array. + */ +MSYS_DLL_EXPORT const unsigned int Common_Get_Windows_Error_Translation_Table_Size(); + +/*! + * int Common_Translate_Windows_Error_Code_To_Common_Error_Code(const DWORD err) + * + * Translates the given Windows error code to it's Common namespace + * error code equilivant. (If applicable.) + * + * @pram const DWORD err, the Windows error code to translate. + * + * Returns the translated Common namespace error code if applicable. + * + * Returns COMMON_SYSTEM_SPECIFIC if the given Windows error code does not have a + * Common namespace error code translation. + */ +MSYS_DLL_EXPORT int Common_Translate_Windows_Error_Code_To_Common_Error_Code(const DWORD err); + +/* End C Linkage if needed. */ +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/* Check for a C compiler. */ +#ifdef __cplusplus +namespace Common +{ + /*! + * typedef Common_windowsErrorCodeTableEntry Common::windowsErrorCodeTableEntry + * + * (C++ Binding.) + * + * Used to construct the windows error code translation table. + * for Windows systems. + */ + typedef Common_windowsErrorCodeTableEntry windowsErrorCodeTableEntry; + + /*! + * const unsigned int Common::Get_Windows_Error_Translation_Table_API_Version() + * + * Returns the API Version number of the Common_windowsErrorTranslationTable + * array. + */ + MSYS_DLL_EXPORT const unsigned int Get_Windows_Error_Translation_Table_API_Version(); + + /*! + * const unsigned int Common::Get_Windows_Error_Translation_Table_Size() + * + * (C++ Binding) + * + * Returns the size of the Common::windowsErrorTranslationTable + * array. + */ + MSYS_DLL_EXPORT const unsigned int Get_Windows_Error_Translation_Table_Size(); + + /*! + * int Common::Translate_Windows_Error_Code_To_Common_Error_Code(const DWORD & err) + * + * (C++ Binding) + * + * Translates the given Windows error code to it's Common namespace + * error code equilivant. (If applicable.) + * + * @pram const DWORD & err, the Windows error code to translate. + * + * Returns the translated Common namespace error code if applicable. + * + * Returns COMMON_SYSTEM_SPECIFIC if the given Windows error code does not have a + * Common namespace error code translation. + */ + MSYS_DLL_EXPORT int Translate_Windows_Error_Code_To_Common_Error_Code(const DWORD & err); +}; +#endif /* __cplusplus */ + +#endif /* WINDOWS_ERROR_TRANSLATION_TABLE_H */ + +/* End of Windows_Error_Translation_Table.h. */ diff --git a/src/Common/Src/Error_Handler/Windows_Error_Translation_Table_CPP_Bindings.cpp b/src/Common/Src/Error_Handler/Windows_Error_Translation_Table_CPP_Bindings.cpp new file mode 100644 index 0000000..7e6b99b --- /dev/null +++ b/src/Common/Src/Error_Handler/Windows_Error_Translation_Table_CPP_Bindings.cpp @@ -0,0 +1,45 @@ +/*! + Multiverse Engine Project 17/1/2016 Common Windows_Error_Translation_Table_CPP_Bindings.cpp + + Copyright (C) 2016 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* C++ Bindings. */ +#ifdef __cplusplus + +/* Internal includes. */ +#include "Common_Error_Handler_Structures.h" +#include "Windows_Error_Translation_Table.h" + +/* External includes. */ +#include + +const unsigned int Common::Get_Windows_Error_Translation_Table_API_Version() +{ + return Common_Get_Windows_Error_Translation_Table_API_Version(); +} + +const unsigned int Common::Get_Windows_Error_Translation_Table_Size() +{ + return Common_Get_Windows_Error_Translation_Table_Size(); +} + +int Common::Translate_Windows_Error_Code_To_Common_Error_Code(const DWORD & err) +{ + return Common_Translate_Windows_Error_Code_To_Common_Error_Code(err); +} +#endif /* __cplusplus */ diff --git a/src/Common/Src/Mutexes/MSYS_Mutexes.c b/src/Common/Src/Mutexes/MSYS_Mutexes.c index 33e2738..677de37 100644 --- a/src/Common/Src/Mutexes/MSYS_Mutexes.c +++ b/src/Common/Src/Mutexes/MSYS_Mutexes.c @@ -167,7 +167,7 @@ MSYS_Mutex * MSYS_Lock_Mutex(MSYS_Mutex * mu) if ((mu != NULL) && (mu->lock != NULL)) { /* Begin loop. */ - while (retFromLOCK != MSYS_MU_SUCCESS) + while ((retFromLOCK != MSYS_MU_SUCCESS) || (retFromLOCK != MSYS_MU_ALREADY_OWNED)) { /* Attempt to lock the mutex. */ retFromLOCK = MSYS_Try_Lock_Mutex(mu); @@ -243,15 +243,44 @@ short MSYS_Try_Lock_Mutex(MSYS_Mutex * mu) } else { - /* Lock is already active. */ - ret = MSYS_MU_ALREADY_LOCKED; + /* Check and see if we own the lock. */ + if (((MSYS_Mutex_Private *)mu->lock)->tidLock == tid) + { + /* Lock is already held by us. */ + ret = MSYS_MU_ALREADY_OWNED; + } + else + { + /* Lock is owned by someone else. */ + ret = MSYS_MU_ALREADY_LOCKED; + } } /* Release the lock. */ MSYS_Compare_And_Swap((&((MSYS_Mutex_Private *)mu->lock)->lock), TRUE, FALSE); #else /* Attempt to lock the mutex. */ - ret = MSYS_Compare_And_Swap_Long((&((MSYS_Mutex_Private *)mu->lock)->tidLock), MSYS_INVALID_TID, tid); + retFromCAS = MSYS_Compare_And_Swap_Long((&((MSYS_Mutex_Private *)mu->lock)->tidLock), MSYS_INVALID_TID, tid); + if (retFromCAS == TRUE) + { + /* Set ret. */ + ret = MSYS_MU_SUCCESS; + } + else + { + /* Check and see if we own the lock. */ + retFromCAS = MSYS_Compare_And_Swap_Long((&((MSYS_Mutex_Private *)mu->lock)->tidLock), tid, tid); + if (retFromCAS) + { + /* Lock is already held by us. */ + ret = MSYS_MU_ALREADY_OWNED; + } + else + { + /* Lock is owned by someone else. */ + ret = MSYS_MU_ALREADY_LOCKED; + } + } #endif /* MSYS_INSUFFIENCT_BITS_LONG_LOCK */ } @@ -326,8 +355,17 @@ short MSYS_Unlock_Mutex(MSYS_Mutex * mu) } else { - /* Lock is owned by another thread, or is unowned. */ - ret = MSYS_MU_ALREADY_LOCKED; + /* Check whether lock is owned by another thread, or is unowned. */ + if (((MSYS_Mutex_Private *)mu->lock)->tidLock == MSYS_INVALID_TID) + { + /* The mutex is not owned by anyone. */ + ret = MSYS_MU_ALREADY_UNLOCKED; + } + else + { + /* The mutex is locked by another thread. */ + ret = MSYS_MU_ALREADY_LOCKED; + } } /* Release the lock. */ @@ -341,8 +379,18 @@ short MSYS_Unlock_Mutex(MSYS_Mutex * mu) } else { - /* Lock is owned by another thread, or is unowned. */ - ret = MSYS_MU_ALREADY_LOCKED; + /* Check whether lock is owned by another thread, or is unowned. */ + retFromCAS = MSYS_Compare_And_Swap_Long((&((MSYS_Mutex_Private *)mu->lock)->tidLock), MSYS_INVALID_TID, MSYS_INVALID_TID); + if (retFromCAS == TRUE) + { + /* The mutex is not owned by anyone. */ + ret = MSYS_MU_ALREADY_UNLOCKED; + } + else + { + /* The mutex is locked by another thread. */ + ret = MSYS_MU_ALREADY_LOCKED; + } } #endif /* MSYS_INSUFFIENCT_BITS_LONG_LOCK */ } diff --git a/src/Common/Src/Mutexes/MSYS_Mutexes.h b/src/Common/Src/Mutexes/MSYS_Mutexes.h index d46ddc9..bdf9047 100644 --- a/src/Common/Src/Mutexes/MSYS_Mutexes.h +++ b/src/Common/Src/Mutexes/MSYS_Mutexes.h @@ -32,7 +32,9 @@ extern "C" { /* Define error codes. */ #define MSYS_MU_SUCCESS 0 -#define MSYS_MU_ALREADY_LOCKED 1 +#define MSYS_MU_ALREADY_UNLOCKED 3 /* Locked by no-one. */ +#define MSYS_MU_ALREADY_OWNED 2 /* Locked by the current thread. */ +#define MSYS_MU_ALREADY_LOCKED 1 /* Locked by another thread. */ #define MSYS_MU_INVALID -1 #define MSYS_MU_UNKNOWN_ERROR -2 @@ -107,13 +109,14 @@ MSYS_Mutex * MSYS_Lock_Mutex(MSYS_Mutex * mu); * Takes the given MSYS_Mutex struct pointer and blocks the * caller until a lock attempt is made. * - * Returns 0 if the lock is aquired and now owned by the + * Returns MSYS_MU_SUCCESS if the lock is aquired and now owned by the * calling thread. * - * Returns 1 if the lock is already owned by another thread, - * or owned by the calling thread. + * Returns MSYS_MU_ALREADY_LOCKED if the lock is already owned by another thread. * - * Returns -1 if the given mutex pointer is invalid. + * Returns MSYS_MU_ALREADY_OWNED if owned by the calling thread. + * + * Returns MSYS_MU_INVALID if the given mutex pointer is invalid. */ short MSYS_Try_Lock_Mutex(MSYS_Mutex * mu); @@ -123,12 +126,13 @@ short MSYS_Try_Lock_Mutex(MSYS_Mutex * mu); * Takes the given MSYS_Mutex struct pointer and attempts * to release the mutex lock. * - * Returns 0 if successful. + * Returns MSYS_MU_SUCCESS if successful. + * + * Returns MSYS_MU_ALREADY_UNLOCKED if the lock is free. * - * Returns 1 if the lock is unowned, or if - * the calling thread does not own the lock. + * Returns MSYS_MU_ALREADY_LOCKED the calling thread does not own the lock. * - * Returns -1 if the given mutex pointer is invalid. + * Returns MSYS_MU_INVALID if the given mutex pointer is invalid. */ short MSYS_Unlock_Mutex(MSYS_Mutex * mu); diff --git a/src/Common/Src/Mutexes/Windows/MSYS_Mutexes_MSVC.h b/src/Common/Src/Mutexes/Windows/MSYS_Mutexes_MSVC.h index 8082ecf..c5bdd00 100644 --- a/src/Common/Src/Mutexes/Windows/MSYS_Mutexes_MSVC.h +++ b/src/Common/Src/Mutexes/Windows/MSYS_Mutexes_MSVC.h @@ -35,7 +35,7 @@ extern "C" { #endif /* __cplusplus */ /* Define stdbool. */ -#include "..\stdbool.h" +#include "..\..\..\stdbool.h" /* Define the functions. */ diff --git a/src/Core/Src/BaseHeader.h b/src/Core/Src/BaseHeader.h index 0846d01..992a0eb 100644 --- a/src/Core/Src/BaseHeader.h +++ b/src/Core/Src/BaseHeader.h @@ -30,5 +30,3 @@ #include #include #include - -using namespace std; diff --git a/src/Core/Src/CMakeLists.txt b/src/Core/Src/CMakeLists.txt index 800ab92..bfeda7c 100644 --- a/src/Core/Src/CMakeLists.txt +++ b/src/Core/Src/CMakeLists.txt @@ -6,7 +6,13 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${O_OUTPUT_DIR}) add_library(Panic_Handler_Multiverse_Engine SHARED Panic.cpp) add_library(Panic_Handler_Multiverse_Engine_Static STATIC Panic.cpp) -add_library(Core_Multiverse_Engine SHARED DataProcess.cpp FileStreams.cpp) -add_library(Core_Multiverse_Engine_Static STATIC DataProcess.cpp FileStreams.cpp) +add_library(Core_Multiverse_Engine SHARED DataProcess.cpp +DataProcess.c +DataProcess_Endianness_Check.cpp +FileStreams.cpp) +add_library(Core_Multiverse_Engine_Static STATIC DataProcess.cpp +DataProcess.c +DataProcess_Endianness_Check.cpp +FileStreams.cpp) target_link_libraries(Core_Multiverse_Engine Panic_Handler_Multiverse_Engine) target_link_libraries(Core_Multiverse_Engine_Static Panic_Handler_Multiverse_Engine_Static) diff --git a/src/Core/Src/DataProcess.c b/src/Core/Src/DataProcess.c new file mode 100644 index 0000000..590f079 --- /dev/null +++ b/src/Core/Src/DataProcess.c @@ -0,0 +1,483 @@ +/*! + Multiverse Engine Project DataProcess DataProcess.c 07/8/2015 + + Copyright (C) 2015 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Set extern C. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Internal includes. */ +#include "DataProcess.h" +#include "../../Common/Src/Error_Handler/Common_Error_Handler_Error_Codes.h" /* Defines Common Error Codes. */ + +/* External includes. */ +#include + +size_t DataProcess_Trivial_Random_Number_Generator(const size_t min_value, const size_t max_value, const bool reset_rand) +{ + /* Define MAX_MODIFIER */ +#define MAX_MODIFIER 100000 /* Used to prevent overflowing the static modifier variable below. */ + + /* NO, it's not 4..... (Although it could be. I won't lie.) */ + + /* Init vars. */ + static bool rand_set; /* Whether or not the random seed has been set or not. */ + static size_t modifier; /* Used to ensure that the random seed is unique if the function is called more than once within the timeframe of a second. */ + time_t tt; /* The current system time as a time_t. */ + struct tm * timeM = NULL; /* The current system time as a tm structure. */ + + /* Check if we need to set the RNG. */ + if ((!rand_set) || (reset_rand)) + { + /* Increment modifier. */ + modifier = ((modifier < MAX_MODIFIER) ? (modifier + 1) : (0)); + + /* Get the current system time. */ + time(&tt); + + /* Convert the current system time to a tm structure. */ + timeM = gmtime(&tt); + + /* Check for NULL pointer. */ + if (timeM != NULL) + { + /* Seed random number generator. */ + srand(((timeM->tm_sec) + (timeM->tm_min) + (timeM->tm_hour) + (timeM->tm_yday) + (timeM->tm_year) + (timeM->tm_mon) + (modifier))); + + /* Set rand_set. */ + rand_set = true; + } + else + { + /* Clear rand_set, so we can try again on the next call. */ + rand_set = false; + } + } + + /* Return the result. */ + return ((rand_set) ? (rand() % max_value + min_value) : (0)); + +/* Undef MAX_MODIFIER. */ +#undef MAX_MODIFIER +} + +int DataProcess_Reallocate_C_String(char ** str, const size_t strLength, const size_t newLength) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result code for this function. */ + char * tempStr = NULL; /* Temporary string pointer used during reallocation.*/ + + /* Check for invalid arguments. */ + if (str != NULL) + { + /* Allocate memory for new string. (If needed.) */ + if (newLength > 0) + { + tempStr = (char *)malloc(newLength); + if (tempStr != NULL) + { + /* NULL out the new string. */ + memset(tempStr, '\0', newLength); + + /* Check and see if we need to copy the old data. */ + if (((*str) != NULL) && (strLength > 0)) + { + /* Determine which length is longer. */ + if (newLength < strLength) + { + /* Copy the old data. */ + memcpy(tempStr, (*str), newLength); + } + else + { + /* Copy the old data. */ + memcpy(tempStr, (*str), strLength); + } + } + } + else + { + /* Could not allocate memory. */ + ret = COMMON_ERROR_MEMORY_ERROR; + } + } + + /* Deallocate the old string. (If needed.) */ + if ((*str) != NULL) + { + DataProcess_Deallocate_CString(str); + } + + /* Copy the new string pointer if needed. */ + if ((newLength > 0) && (ret == COMMON_ERROR_UNKNOWN_ERROR) && (tempStr != NULL)) + { + (*str) = tempStr; + } + + /* Done. */ + ret = COMMON_ERROR_SUCCESS; + } + else + { + /* Invalid argument. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; +} + +int DataProcess_Reallocate_C_String_With_NULL_Terminator(char ** str, const size_t strLength, size_t * newLength) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result of this function. */ + size_t newSize = 0; /* The modified size if needed. */ + + /* Check for valid args. */ + if ((str != NULL) && (newLength != NULL) && (((*str) == NULL) || (strLength > 0))) + { + /* Check and see if new length is greater than zero (0). */ + /* Safety check on newSize.... */ + newSize = ((*newLength) > 0) ? (((*newLength) < (SIZE_MAX - (sizeof(char)))) ? ((*newLength) + (sizeof(char))) : (*newLength)) : (0); + + /* Call DataProcess_Reallocate_C_String(). (It will NULL out the allocated buffer before copying data.) */ + ret = DataProcess_Reallocate_C_String(str, strLength, newSize); + if ((ret == COMMON_ERROR_SUCCESS) && (str != NULL) && ((*str) != NULL)) + { + /* See if the string is NULL terminated. */ + if ((newSize > 0) && (((*str)[(newSize - 1)]) != '\0')) + { + /* Set the last byte to NULL, because it should be. + (The last byte is always NULL if this function returns COMMON_ERROR_SUCCESS.) + */ + ((*str)[(newSize - 1)]) = '\0'; + } + } + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; +} + +void DataProcess_Deallocate_CString(char ** str) +{ + /* Check for invalid arguments. */ + if ((str != NULL) && ((*str) != NULL)) + { + /* Deallocate (*str) and set it to NULL. */ + free((*str)); + (*str) = NULL; + } + + /* Exit function. */ + return; +} + +int DataProcess_getCStringFromSizeT(const size_t number, char ** str, size_t * strLength) +{ + /* Init vars. */ + size_t currentNum = 0; /* Temporary value used to store the current number we are working on. */ + char outputValue = '\0'; /* The value that we need to write into the output buffer. (Calculated from currentNum.) */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result code of this function. */ + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; /* The result code of a call to an engine function. */ + char * result = NULL; /* The resulting string of this function. */ + char * previousResult = NULL; /* Temporary pointer used to copy previously generated data into the current result. */ + size_t resultLength = 1; /* The size of the result string. Set to one by default to allow the string to be NULL terminated. */ + const char outputValues[10] = "0123456789"; /* C-String used to map a generated value to it's corresponding character. */ + + /* Check for invalid arguments. */ + if ((str != NULL) && (strLength != NULL)) + { + /* Allocate memory for result. */ + retFromCall = DataProcess_Reallocate_C_String(&result, 0, resultLength); + if ((retFromCall == COMMON_ERROR_SUCCESS) && (result != NULL)) + { + /* Set currentNum. */ + currentNum = number; + + /* Begin value parsing loop. */ + do + { + /* Read the current byte's value from right to left. (Mod is a reduction operation.) */ + outputValue = (currentNum % 10); + + /* Copy the current buffer's pointer because we are about to create a new one. */ + previousResult = result; + + /* Reset the current buffer's pointer. (Otherwise Reallocate_C_String() will deallocate it.) */ + result = NULL; + + /* Increment the size of the new buffer. */ + resultLength++; + + /* Allocate the new buffer. */ + retFromCall = DataProcess_Reallocate_C_String(&result, 0, resultLength); + + /* Check for successful memory allocation. */ + if ((retFromCall == COMMON_ERROR_SUCCESS) && (result != NULL)) + { + /* Set the first value as the previous data comes after it. */ + result[0] = outputValues[outputValue]; + + /* If we have any previous data we need to copy it into the new buffer and deallocate the previous one. */ + if (previousResult != NULL) + { + memcpy((result + 1), previousResult, (resultLength - 1)); + DataProcess_Deallocate_CString(&previousResult); + } + + /* Get the next value by chopping off the "ones place", aka divide by the current base. */ + currentNum /= 10; + } + else + { + /* Could not allocate memory for output buffer. */ + ret = COMMON_ERROR_MEMORY_ERROR; + } + } while ((currentNum) && (ret != COMMON_ERROR_MEMORY_ERROR)); + + /* Check for success. */ + if ((ret == COMMON_ERROR_UNKNOWN_ERROR) && (result != NULL) && (resultLength > 0)) + { + /* Copy result pointer, and length. */ + (*str) = result; + (*strLength) = resultLength; + + /* Done. */ + ret = COMMON_ERROR_SUCCESS; + } + else + { + /* Deallocate result if needed. */ + if (result != NULL) + { + DataProcess_Deallocate_CString(&result); + } + resultLength = 0; + } + } + else + { + /* Could not allocate memory for result string. */ + ret = COMMON_ERROR_MEMORY_ERROR; + } + } + else + { + /* Invalid argument(s). */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; +} + +int DataProcess_Get_SubString_Using_Delimiter(const char * src, const size_t srcLength, const char * delim, const size_t delimLength, + char ** subStr, size_t * subStrLength, const int searchFromEnd, const int getPriorData) +{ + /* Init vars. */ + int foundDelim = 0; /* Whether or not we have found the delim. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result code of this function. */ + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; /* The result code of a call to an engine function. */ + char * tempSubStr = NULL; /* Used to create the substr. */ + size_t x = 0; /* Counter used in search loop. */ + size_t y = 0; /* Counter used in search subloop. */ + size_t tempSubStrLength = 0; /* Size of the tempSubString. */ + + /* Check for invalid arguments. */ + if ((src != NULL) && (srcLength > 0) && (delim != NULL) && (delimLength > 0) && (subStr != NULL) && (subStrLength != NULL)) + { + /* Begin search loop. */ + for (x = 0; ((x < srcLength) && (!foundDelim) && (ret == COMMON_ERROR_UNKNOWN_ERROR));) + { + /* Reset foundDelim. */ + foundDelim = 1; + + /* Begin search subloop for the delim. */ + for (y = 0; ((y < delimLength) && (foundDelim)); y++) + { + /* Determine if we are searching from the end of the search string or not. */ + if (searchFromEnd) + { + /* Check and see if the current byte is a match to the delim. */ + if (src[((srcLength - 1) - (x + y))] != delim[((delimLength - 1) - y)]) + { + /* Mismatch, have not found delim. */ + foundDelim = 0; + } + } + else + { + /* Check and see if the current byte is a match to the delim. */ + if (src[(x + y)] != delim[y]) + { + /* Mismatch, have not found delim. */ + foundDelim = 0; + } + } + } + + /* Add the y value to the current x value. (Update the counters.) */ + x += y; + } /* End of search loop. */ + + /* Check and see if we have found the delim. */ + if ((foundDelim) && (y == delimLength)) + { + /* We found the delim, Check and see if we need the data after the delimiter or before it. */ + if ((getPriorData) ? ((srcLength - x) > 0) : (((x - delimLength) > 0) && (x < (srcLength - 1)))) + { + /* Set the size for the new substring. */ + tempSubStrLength = ((getPriorData) ? (srcLength - x) : (x - delimLength)); + + /* Allocate memory for the substring. */ + retFromCall = DataProcess_Reallocate_C_String(&tempSubStr, 0, tempSubStrLength); + if ((retFromCall == COMMON_ERROR_SUCCESS) && (tempSubStr != NULL)) + { + /* Copy the bytes, before the delimiter if getPriorData is true, otherwise + Copy the bytes after the delimiter. + */ + memcpy(tempSubStr, ((getPriorData) ? (src) : + (searchFromEnd ? (src + ((srcLength + 1) - x)) : (src + x))), + tempSubStrLength); + + /* Copy the pointer and size. */ + (*subStr) = tempSubStr; + (*subStrLength) = tempSubStrLength; + + /* Done. */ + ret = COMMON_ERROR_SUCCESS; + } + else + { + /* Could not allocate memory for substring. */ + ret = COMMON_ERROR_MEMORY_ERROR; + } + } + else + { + /* No bytes remaining to create substring. */ + ret = COMMON_ERROR_END_OF_DATA; + } + } + else + { + /* Delim not found in search string. */ + ret = COMMON_ERROR_RANGE_ERROR; + } + } + else + { + /* Invalid argument(s). */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; +} + +int DataProcess_Get_SubString_Using_Offset(const char * src, const size_t srcLength, const size_t offset, + char ** subStr, size_t * subStrLength, const int searchFromEnd, const int getPriorData) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result code of this function. */ + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; /* The result code of a call to an engine function. */ + char * tempSubStr = NULL; /* Used to create the substr. */ + size_t tempRealOffset = 0; /* Used to hold the real starting offset in the given string. */ + size_t tempSubStrLength = 0; /* Size of the tempSubString. */ + + /* Check for invalid arguments. */ + if ((src != NULL) && (srcLength > 0) && (offset >= 0) && (offset < srcLength) && (subStr != NULL) && (subStrLength != NULL)) + { + /* + * --------------------------------------------------------------------------------------------------------- + * | searchFromEnd: | getPriorData: | substring contents: (Starting and ending offset ranges.) | + * --------------------------------------------------------------------------------------------------------- + * | FALSE | FALSE | offset <--> end of string | + * | TRUE | FALSE | (end of string - offset) <--> end of string | + * | FALSE | TRUE | start of string <--> offset | + * | TRUE | TRUE | start of string <--> (end of string - offset) | + * --------------------------------------------------------------------------------------------------------- + * + * Note: searchFromEnd only controls the offset's point of origin. (I.e. which end of the given + * string the offset is based at.) searchFromEnd does NOT control what substring is selected + * based on the given offset; the selection is made based on getPriorData. + */ + + /* Determine the real starting offset and sub-string length. */ + tempRealOffset = ((searchFromEnd) ? ((getPriorData) ? (0) : ((srcLength - offset))) : ((getPriorData) ? (0) : (offset))); + tempSubStrLength = ((searchFromEnd) ? ((getPriorData) ? ((srcLength - offset)) : ((srcLength - 1))) : ((getPriorData) ? (offset) : ((srcLength - 1)))); + + /* Make sure the temp values are within the given string's buffer. */ + if ((tempRealOffset >= 0) && (tempRealOffset < srcLength) && (tempSubStrLength > 0) && ((tempRealOffset + tempSubStrLength) < srcLength)) + { + /* Allocate memory for the substring. Using DataProcess_Reallocate_C_String(). */ + retFromCall = DataProcess_Reallocate_C_String(&tempSubStr, 0, tempSubStrLength); + if ((retFromCall == COMMON_ERROR_SUCCESS) && (tempSubStr != NULL)) + { + /* Copy the data. */ + memcpy(tempSubStr, (src + tempRealOffset), tempSubStrLength); + + /* Copy the pointer and data length. */ + (*subStr) = tempSubStr; + (*subStrLength) = tempSubStrLength; + + /* Done. */ + ret = COMMON_ERROR_SUCCESS; + } + else + { + /* Could not allocate memory for substring. */ + ret = COMMON_ERROR_MEMORY_ERROR; + } + } + else + { + /* Invalid temp vars. */ + if (tempSubStrLength <= 0) + { + /* No data to create substring with. */ + ret = COMMON_ERROR_END_OF_DATA; + } + else + { + /* Internal calculation error. (Could not calculate a valid offset and / or substring length.) */ + ret = COMMON_ERROR_RANGE_ERROR; + } + } + } + else + { + /* Invalid argument(s). */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; +} + +#ifdef __cplusplus +} /* End of extern "C". */ +#endif __cplusplus diff --git a/src/Core/Src/DataProcess.cpp b/src/Core/Src/DataProcess.cpp index 2ba04c7..9b960c6 100644 --- a/src/Core/Src/DataProcess.cpp +++ b/src/Core/Src/DataProcess.cpp @@ -22,28 +22,10 @@ #include "DataProcess.h" #include "FileStreams.h" -/* External includes. */ -#include - size_t DataProcess::Trivial_Random_Number_Generator(const size_t & min_value, const size_t & max_value, const bool & reset_rand) { - // NO, it's not 4..... (Although it could be. I won't lie.) - - // Set static. - static bool rand_set; - - // Check if we need to set the rng. - if ((!rand_set) || (reset_rand)) - { - // Seed random number generator. - srand(time(NULL)); - - // Set rand_set. - rand_set = true; - } - - // Return the result. - return (rand() % max_value + min_value); + /* Call C function. */ + return (DataProcess_Trivial_Random_Number_Generator(min_value, max_value, reset_rand)); } short DataProcess::IncrementingSort(std::vector & sort) @@ -162,7 +144,7 @@ short DataProcess::IncrementingSort(std::vector & sort) } catch (...) { - // Exception thrown. + // std::exception thrown. return -9; } } @@ -287,7 +269,7 @@ short DataProcess::DecrementingSort(std::vector & sort) } catch (...) { - // Exception thrown. + // std::exception thrown. return -9; } } @@ -296,7 +278,7 @@ short DataProcess::DecrementingSort(std::vector & sort) return 0; } -bool DataProcess::CheckForEOF(fstream & source) +bool DataProcess::CheckForEOF(std::fstream & source) { // Init vars. size_t current_pos = 0; // Used to store current pos. @@ -314,7 +296,7 @@ bool DataProcess::CheckForEOF(fstream & source) current_pos = source.tellg(); // Seek to the end of the file. - source.seekg(0, ios::end); + source.seekg(0, std::ios::end); // Compare positions. if (current_pos == (unsigned)source.tellg()) @@ -324,7 +306,7 @@ bool DataProcess::CheckForEOF(fstream & source) } // Seek back to the original position. - source.seekg(current_pos, ios::beg); + source.seekg(current_pos, std::ios::beg); } // Exit function and return the result. @@ -415,7 +397,7 @@ double DataProcess::getnumberFromString(std::string source, std::string varName, } // Look for the varName. - if (source.find(varName) == string::npos) + if (source.find(varName) == std::string::npos) { error.PanicHandler("DataProcess::getnumberFromString : Can't find varName in string. Returning default 0."); real_limiter = ""; @@ -441,56 +423,56 @@ double DataProcess::getnumberFromString(std::string source, std::string varName, if (temp2 == "1") { temp1 = temp1 += temp2; - cout <> output; + std::istringstream (temp1) >> output; } - catch(exception& ex){ - cout << "\n ERROR: DataProcess::getnumberFromString() Exception: " << ex.what() << "\n Clearing data buffer and returning zero.\n\n"; + catch(std::exception& ex){ + std::cout << "\n ERROR: DataProcess::getnumberFromString() std::exception: " << ex.what() << "\n Clearing data buffer and returning zero.\n\n"; // Guess what? we found bullshit. we can't clear it now so dump the buffer and exit. error.PanicHandler("DataProcess::getnumberFromString : Can't convert number string back to double."); @@ -530,7 +512,7 @@ double DataProcess::getnumberFromString(std::string source, std::string varName, real_location = 0; sourceSize = 0; } - cout <<" the result is: " <> number; - getline(cin, dummy); // cin appends a end line char, so we use this to get rid of it. other wise it will show up on the next cin op. - if (cin.fail() == true) // If this goes true user has inputed a non int. + std::cin >> number; + getline(std::cin, dummy); // std::cin appends a end line char, so we use this to get rid of it. other wise it will show up on the next std::cin op. + if (std::cin.fail() == true) // If this goes true user has inputed a non int. { - cout << " invalid data \n "; + std::cout << " invalid data \n "; // Fix the buffer. - cin.clear(); - getline(cin, dummy); + std::cin.clear(); + getline(std::cin, dummy); } return number; } @@ -558,7 +540,7 @@ bool DataProcess::yesNoConsolePrompt() // Prompt user. std::cout << "(YES or NO) (Must be in CAPS): "; - getline(cin, dummy); + getline(std::cin, dummy); // Check result, if user said YES then return true. if (dummy == "YES") @@ -581,7 +563,7 @@ bool DataProcess::getboolFromstring(std::string source, std::string varName, cha std::string searchString = ""; // Look for the var name - if (source.find(varName) == string::npos) + if (source.find(varName) == std::string::npos) { // If varname is not found in the string return default. error.PanicHandler("DataProcess::getboolFromstring : Varname not found."); @@ -598,11 +580,11 @@ bool DataProcess::getboolFromstring(std::string source, std::string varName, cha { delimiterReal = '\n'; } - if (source.find(delimiterReal, location1) == string::npos) + if (source.find(delimiterReal, location1) == std::string::npos) { location2 = -1; } - if (source.find('\n', location1) == string::npos) + if (source.find('\n', location1) == std::string::npos) { location2 = -1; } @@ -617,24 +599,24 @@ bool DataProcess::getboolFromstring(std::string source, std::string varName, cha searchString = source; } // Debug - cout << searchString < 31 ) && (data[x] < 127)) { - cout << data[x] << " "; + std::cout << data[x] << " "; } else { - cout << " 0x" << (int)data[x] << " "; + std::cout << " 0x" << (int)data[x] << " "; } if (memory_format == true) { if (x%15 == 0) { // Print current line. - cout << (x/15) << "\n"; + std::cout << (x/15) << "\n"; } } } @@ -1306,10 +1288,10 @@ void DataProcess::dumpDataToConsole(const char * data, size_t length, size_t off // Some error. // Flush console buffer. - cout.flush(); + std::cout.flush(); // Output a new line. - cout << "\n\n"; + std::cout << "\n\n"; // Exit function. return; @@ -1317,10 +1299,10 @@ void DataProcess::dumpDataToConsole(const char * data, size_t length, size_t off } // Flush console buffer. - cout.flush(); + std::cout.flush(); // Flush console buffer. - cout.flush(); + std::cout.flush(); // Default return. return; diff --git a/src/Core/Src/DataProcess.h b/src/Core/Src/DataProcess.h index a7d7fe5..c9c398e 100644 --- a/src/Core/Src/DataProcess.h +++ b/src/Core/Src/DataProcess.h @@ -18,12 +18,267 @@ https://github.com/codebase7/mengine */ +/* Include guard. */ #ifndef DATAPROCESS_H #define DATAPROCESS_H -#include "BaseHeader.h" +/* Internal includes. */ #include "Panic.h" +#if _MSC_FULL_VER && _MSC_FULL_VER < 180031101 +/* Visual C++ 2013 introduced support for C99's _Bool. Anything lower than that has to use our fake bool header. */ +#include "../../stdbool.h" +#else +/* Use the built in bool data type. */ +#include +#endif /* _MSC_FULL_VER 180021005 */ + +/* Define extern "C". */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* External includes. */ +#include +#include +#include +#include + +/* Define C functions. */ +/*! + size_t DataProcess_Trivial_Random_Number_Generator(const size_t min_value, const size_t max_value, const bool reset_rand) + + This function generates psudo-random numbers based on the given max_value. + + @pram min_value, the minimum value that is acceptable for the function to return. + @pram max_value, the maximum value that is acceptable for the function to return. + + E.x. If you want a range of 1 to 100 set min_value to 1 and max_value to 100. + + @pram reset_rand, if this is set to true, the RNG will be re-seeded with the current time value returned by time(). + Otherwise the next psudo-random number from the current seed will be returned. + + Returns the generated psudo-random number if successful. + If the current system time cannot be used to set the random seed, then this function will consistantly return zero (0) + regardless of the range defined by min_value and max_value. +*/ +size_t DataProcess_Trivial_Random_Number_Generator(const size_t min_value, const size_t max_value, const bool reset_rand); + +/*! + * int DataProcess_Reallocate_C_String(char ** str, const size_t strLength, const size_t newLength) + * + * Reallocates the given string to be the new length. + * + * Optionally it may do the following: + * - If newLength is 0, it will only deallocate the given string. + * - If newLength is greater than zero, but str is NULL or strLength is zero then, + * this function will only allocate a string of newLength bytes. + * (The string will be NULL filled.) + * - If newLength and strLength is greater than zero, and str is non-NULL, + * then the data from str will be copied into the reallocated string as follows: + * - If the newLength is less than the original length, then the data from str + * will be copied, but any bytes after newLength will be truncated. + * - If the newLength is greater than or equal to the original length then, + * the entire original string will be copied. + * In any instance, the reallocated string may NOT be NULL terminated. This occurs if + * data is copied from the original string and either the original string is not NULL + * terminated, or if the data to be copied from the original string did not include the + * NULL terminator. In addition, the resulting string is always newLength in size if + * this function is successful. + * + * Returns COMMON_ERROR_SUCCESS if successful. + * Returns COMMON_ERROR_INVALID_ARGUMENT if the given pointer to pointer is NULL. + * Returns COMMON_ERROR_MEMORY_ERROR if a memory allocation attempt fails. + * Otherwise returns the appropriate error code. + * + * In case of error, the given arguments will NOT be altered. + */ +int DataProcess_Reallocate_C_String(char ** str, const size_t strLength, const size_t newLength); + +/*! + * int DataProcess_Reallocate_C_String_With_NULL_Terminator(char ** str, const size_t strLength, size_t * newLength) + * + * Reallocates the given string to be the new length and adds a NULL byte terminator if needed. + * The resulting string is guaranteed to ALWAYS be NULL byte terminated if this function returns COMMON_ERROR_SUCCESS. + * + * Note: This function WILL change the given string to make it NULL byte terminated if the NULL byte + * could not be added during reallocation (this happens if the additional byte would result in a length greater than SIZE_MAX), + * but only if the function returns COMMON_ERROR_SUCCESS. + * + * (This function is a wrapper around DataProcess_Reallocate_C_String(), see that function for more information.) + * + * In case of error, the given arguments will NOT be altered. + */ +int DataProcess_Reallocate_C_String_With_NULL_Terminator(char ** str, const size_t strLength, size_t * newLength); + +/*! + * void DataProcess_Deallocate_CString(char ** str) + * + * Destructor function for C-Strings allocated by DataProcess. + * + * WARNING: Giving an object or a C-String not allocated by DataProcess will cause + * undefined behaviour. + * + * If a given pointer is NULL, this function will silently fail. + * + * This function has no return. + */ +void DataProcess_Deallocate_CString(char ** str); + +/*! + * int DataProcess_getCStringFromSizeT(const size_t number, char ** str, size_t * strLength) + * + * Takes given size_t and outputs the equivalent human-readable string as a C-String. + * + * The generated string should be freed using DataProcess_Deallocate_CString() when it is no longer needed. + * + * WARNING: This function will NOT deallocate the given string if it is already allocated. + * The pointer WILL be overwritten if this function returns success! + * If you need to keep the pointer for later deallocation, copy it elsewhere before calling this function. + * + * Returns COMMON_ERROR_SUCCESS if successful. str will point to a C-String with string equivalent to number in this case. + * Returns COMMON_ERROR_INVALID_ARGUMENT if a given argument is invalid. + * Returns COMMON_ERROR_MEMORY_ERROR if a memory allocation attempt fails. + * Otherwise returns the appropriate error code. + * + * No alteration clause: + * In case of error, this function will not alter any given argument. + */ +int DataProcess_getCStringFromSizeT(const size_t number, char ** str, size_t * strLength); +/*! + * int DataProcess_Get_SubString_Using_Delimiter(const char * src, const size_t srcLength, const char * delim, const size_t delimLength, + * char ** subStr, size_t * subStrLength, const int searchFromEnd, const int getPriorData) + * + * Basic delimiter based sub-string generation function. + * + * Takes the given source string and looks for the first occurrence of the given delimiter string within it. + * If the delimiter string is found, this function will produce a sub-string with either the remaining bytes in the + * source string that come after the delimiter, or the bytes from the source string that came before the delimiter. + * + * The generated sub-string should be freed using DataProcess_Deallocate_CString() when it is no longer needed. + * + * Optionally if searchFromEnd is non-zero, the search will start from the end of the source string instead of the beginning. + * + * Notes about resulting substring: + * If getPriorData is true, the length of the substring is sourceLength - , otherwise + * the length of the substring is - . + * + * If getPriorData is true the start of the substring is the start of the source string, otherwise it depends + * on the value of searchFromEnd. If searchFromEnd is true, then the start of the substring is + * ( - ), otherwise the start of the string is the . + * + * Truth Table: + * + * -------------------------------------------------------------------------------------------------------------------------------------------------- + * | getPriorData: | searchFromEnd: | Start of substring: | Length of substring: | + * -------------------------------------------------------------------------------------------------------------------------------------------------- + * | true | N / A | Start of source string | ( - ) | + * -------------------------------------------------------------------------------------------------------------------------------------------------- + * | false | true | ( - ) | ( - ) | + * -------------------------------------------------------------------------------------------------------------------------------------------------- + * | false | false | Delimiter offset | ( - ) | + * -------------------------------------------------------------------------------------------------------------------------------------------------- + * + * @pram getPriorData, Chooses the bytes that came before the delimiter or after the delimiter for generating the sub-string from. + * If getPriorData is non-zero then the sub-string will contain the bytes before the delimiter, otherwise the sub-string will + * contain the bytes after the delimiter. + * + * Returns COMMON_ERROR_SUCCESS if the delimiter was found and a sub-string was created. + * Returns COMMON_ERROR_RANGE_ERROR if the delimiter string was not found in the source string. + * Returns COMMON_ERROR_END_OF_DATA if the delimiter string was found at the end of source string + * with no data remaining to create the sub-string with. (subStr and subStrLength will NOT be altered in this case.) + * Returns COMMON_ERROR_INVALID_ARGUMENT if a given argument is invalid. + * Returns COMMON_ERROR_MEMORY_ERROR if a memory allocation attempt fails. + * Otherwise returns the appropriate error code. + * + * No alteration clause: + * In case of error, this function will not alter any given argument. + * (For the purposes of this no-alteration clause, the error codes COMMON_ERROR_RANGE_ERROR and COMMON_ERROR_END_OF_DATA + * are considered errors.) + */ +int DataProcess_Get_SubString_Using_Delimiter(const char * src, const size_t srcLength, const char * delim, const size_t delimLength, + char ** subStr, size_t * subStrLength, const int searchFromEnd, const int getPriorData); + +/*! + * int DataProcess_Get_SubString_Using_Offset(const char * src, const size_t srcLength, const size_t offset, + * char ** subStr, size_t * subStrLength, const int searchFromEnd, const int getPriorData) + * + * Takes the given source data string and offset and generates a substring from it. The generated sub-string should be freed using + * DataProcess_Deallocate_CString() when it is no longer needed. + * + * Note: The generated substring is not NULL terminated. This is to allow the function to be used with unformatted data. + * + * The substring is generated based on the given offset, searchFromEnd, and getPriorData arguments using the following truth table: + * + * --------------------------------------------------------------------------------------------------------- + * | searchFromEnd: | getPriorData: | substring contents: (Starting and ending offset ranges.) | + * --------------------------------------------------------------------------------------------------------- + * | FALSE | FALSE | offset <--> end of string | + * | TRUE | FALSE | (end of string - offset) <--> end of string | + * | FALSE | TRUE | start of string <--> offset | + * | TRUE | TRUE | start of string <--> (end of string - offset) | + * --------------------------------------------------------------------------------------------------------- + * + * Note: searchFromEnd only controls the offset's point of origin. (I.e. which end of the given + * string the offset is based at.) searchFromEnd does NOT control what substring is selected + * based on the given offset; the selection is made based on getPriorData. + * + * @pram src (const char *), the source string that the substring is generated from. + * + * @pram srcLength (const size_t), the length of the source string. (Function may fail if given length is invalid / incorrect.) + * + * @pram offset (const size_t), the starting offset within the source string to start copying data from. + * + * @pram subStr (char **), a pointer that points to the pointer for the generated sub-string. WARNING: The pointer value will be overwritten + * if this call returns COMMON_ERROR_SUCCESS. This pointer should be released by calling DataProcess_Deallocate_CString(). + * + * @pram subStrLength (size_t *), a pointer to a size_t value that contains the length of the generated substring. + * + * @pram searchFromEnd (integer treated as boolean), Which end of the given source string the given offset is is based at. + * (Start of given string = 0, end of given string = any non-zero value.) + * + * @pram getPriorData (integer treated as boolean), Whether or not to use the segment of data that comes before the given offset as the + * generated substring. (False = zero, True = any non-zero value.) + * + * Returns COMMON_ERROR_SUCCESS if successfull. In this case the values of subStr and subStrLength will change to contain a pointer to the generated + * substring and the length of the generated substring respectively. + * + * Returns COMMON_ERROR_INVALID_ARGUMENT if a given pointer is NULL, the length of the source string is 0, the given offset is less than zero or + * greater than or equal to the length of the string. + * + * Returns COMMON_ERROR_MEMORY_ERROR if memory allocation for the substring fails. + * + * Returns COMMON_ERROR_END_OF_DATA if the given arguments would generate a substring that contains no data. + * (I.e. The generated substring's length would be zero.) + * + * Returns COMMON_ERROR_RANGE_ERROR if an internal calculation fails. + * + * Otherwise returns the approperite error code. + * + * No alteration clause: + * In case of error, this function will not alter any given argument. + * (For the purposes of this no-alteration clause, the error codes COMMON_ERROR_RANGE_ERROR and COMMON_ERROR_END_OF_DATA + * are considered errors.) + */ +int DataProcess_Get_SubString_Using_Offset(const char * src, const size_t srcLength, const size_t offset, + char ** subStr, size_t * subStrLength, const int searchFromEnd, const int getPriorData); +#ifdef __cplusplus +} /* End of extern "C". */ +#endif /* __cplusplus */ + +/* Only define the below with a CPP compiler. */ +#ifdef __cplusplus + +/* Internal includes. */ +#include "DataProcess_Endianness_Check.h" + +/* External includes. */ +#include +#include +#include +#include + +/* Define DataProcess namespace. */ namespace DataProcess{ class Data_Object{ @@ -247,19 +502,11 @@ class Data_Object{ /*! size_t DataProcess::Trivial_Random_Number_Generator(const size_t & min_value, const size_t & max_value, const bool & reset_rand) - This function generates psudo-random numbers based on the given max_value. - - @pram min_value, the minimum value that is acceptable for the function to return. - @pram max_value, the maximum value that is acceptable for the function to return. - - E.x. If you want a range of 1 to 100 set min_value to 1 and max_value to 100. + A wrapper around the DataProcess_Trivial_Random_Number_Generator() C function. (For compatibility.) - By default this function returns a number between 0 and 255. + See DataProcess_Trivial_Random_Number_Generator()'s description for documentation. - @pram reset_rand, if this is set to true, the rng will be re-seeded with the current time value returned by time(NULL). - Otherwise the next psudo-random number from the current seed will be returned. (Default) - - Returns the generated psudo-random number. + Note: Default values for arguments are: min_value 0, max_value 255, reset_rand false. */ MSYS_DLL_EXPORT size_t Trivial_Random_Number_Generator(const size_t & min_value = 0, const size_t & max_value = 255, const bool & reset_rand = false); @@ -292,7 +539,7 @@ MSYS_DLL_EXPORT short IncrementingSort(std::vector & sort); MSYS_DLL_EXPORT short DecrementingSort(std::vector & sort); /*! - bool DataProcess::CheckForEOF(fstream & source) + bool DataProcess::CheckForEOF(std::fstream & source) Checks the given file stream for eof (End of File) status and returns the result. @@ -302,7 +549,7 @@ MSYS_DLL_EXPORT short DecrementingSort(std::vector & sort); Returns true if the fstream is at EOF. (End of File) Returns false otherwise. (Note: This function will return false if the fstream has failed. (i.e source.fail() == true).) */ -MSYS_DLL_EXPORT bool CheckForEOF(fstream & source); +MSYS_DLL_EXPORT bool CheckForEOF(std::fstream & source); /*! GenerateUID(long int length) @@ -519,6 +766,8 @@ MSYS_DLL_EXPORT short RegularExpressionParser(const std::string & expression, co MSYS_DLL_EXPORT short RegularExpressionParser(const DataProcess::Data_Object & expression, const DataProcess::Data_Object & input, Panic::Panic_ERROR * error = NULL); } -#endif +#endif /* __cplusplus */ + +#endif /* DATAPROCESS_H */ -// End of DataProcess.h +/* End of DataProcess.h */ diff --git a/src/Core/Src/DataProcess_Endianness_Check.cpp b/src/Core/Src/DataProcess_Endianness_Check.cpp new file mode 100644 index 0000000..f30da8f --- /dev/null +++ b/src/Core/Src/DataProcess_Endianness_Check.cpp @@ -0,0 +1,126 @@ +/*! + Multiverse Engine Project 11/7/2015 DataProcess DataProcess_Endianness_Check.cpp + + Copyright (C) 2015 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Include internal header. */ +#include "DataProcess_Endianness_Check.h" + +template +int DataProcess_Endianness_Check(const T & a) +{ + /* Init vars. */ + int ret = MSYS_UNKNOWN_ENDIANNESS; /* The result of this function. */ + T t = 1; /* Variable to check. */ + + /* Cast t to a char string and see if the result is 1. */ + if (((char*)&t)[0]) + { + /* The first byte is 1 so it's little endian. */ + ret = MSYS_LITTLE_ENDIAN; + } + else + { + /* + * The first byte is 0 so, check and see if the last byte is non-zero. + * If it is, then the host is big endian. + * + * Otherwise the host is using something like middle-endian to store + * the value, but we would need more checks to determine what exact + * kind of endianness the host is using. + */ + if (((char*)&t)[((sizeof(t)) - 1)]) + { + /* It's big endian. */ + ret = MSYS_BIG_ENDIAN; + } + } + + /* Return the result. */ + return ret; +} + +template<> +int DataProcess_Endianness_Check(const float & a) +{ + /* Init vars. */ + int ret = MSYS_UNKNOWN_ENDIANNESS; /* The result of this function. */ + float t = 1.0; /* Variable to check. */ + + /* Cast t to a char string and see if the first 2 values are 0x3F80. */ + if ((((char*)&t)[0] == 0x3F) && ((((char*)&t)[1] == 0x80))) + { + /* The first 2 bytes are 0x3F80 so it's big endian. */ + ret = MSYS_BIG_ENDIAN; + } + else + { + /* + * The first check did not pass, so check and see if the last 2 bytes are 0x803F. + * If they are, then the host is little endian. + * + * Otherwise the host is using something like middle-endian to store + * the value, but we would need more checks to determine what exact + * kind of endianness the host is using. + */ + if ((((char*)&t)[(sizeof (float) - 1)] == 0x80) && ((((char*)&t)[(sizeof (float) - 2)] == 0x3F))) + { + /* It's little endian. */ + ret = MSYS_LITTLE_ENDIAN; + } + } + + /* Return the result. */ + return ret; +} + +template<> +int DataProcess_Endianness_Check(const double & a) +{ + /* Init vars. */ + int ret = MSYS_UNKNOWN_ENDIANNESS; /* The result of this function. */ + double t = 1.0; /* Variable to check. */ + + /* Cast t to a char string and see if the first 2 values are 0x3FF0. */ + if ((((char*)&t)[0] == 0x3F) && ((((char*)&t)[1] == 0xF0))) + { + /* The first 2 bytes are 0x3F80 so it's big endian. */ + ret = MSYS_BIG_ENDIAN; + } + else + { + /* + * The first check did not pass, so check and see if the last 2 bytes are 0xF03F. + * If they are, then the host is little endian. + * + * Otherwise the host is using something like middle-endian to store + * the value, but we would need more checks to determine what exact + * kind of endianness the host is using. + */ + if ((((char*)&t)[(sizeof (double) - 1)] == 0xF0) && ((((char*)&t)[(sizeof (double) - 2)] == 0x3F))) + { + /* It's little endian. */ + ret = MSYS_LITTLE_ENDIAN; + } + } + + /* Return the result. */ + return ret; +} + +/* End of DataProcess_Endianness_Check.cpp */ diff --git a/src/Core/Src/DataProcess_Endianness_Check.h b/src/Core/Src/DataProcess_Endianness_Check.h new file mode 100644 index 0000000..148e5c5 --- /dev/null +++ b/src/Core/Src/DataProcess_Endianness_Check.h @@ -0,0 +1,68 @@ +/*! + Multiverse Engine Project 11/7/2015 DataProcess DataProcess_Endianness_Check.h + + Copyright (C) 2015 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Include guard. */ +#ifndef DATAPROCESS_ENDIANNESS_CHECK_H +#define DATAPROCESS_ENDIANNESS_CHECK_H + +/* Define Endianness Result Values. */ +#define MSYS_BIG_ENDIAN 0 +#define MSYS_LITTLE_ENDIAN 1 +#define MSYS_UNKNOWN_ENDIANNESS 2 + +/* Define namespace. */ +namespace DataProcess { + +/*! + * template + * int DataProcess_Endianness_Check(T & a) + * + * Template function which checks the host's endianness for the + * given argument's data type. + * + * Note: The given argument is not altered or used by the function. + * It's only used to exploit the C++ template generator. + * + * The specializations for float and double are required as floating + * point data types must be detected differently from integers. + * + * Returns MSYS_BIG_ENDIAN if the given data type is stored as big + * endian on the host machine. + * + * Returns MSYS_LITTLE_ENDIAN if the given data type stored as little + * endian on the host machine. + * + * Returns MSYS_UNKNOWN_ENDIANNESS if the given data type's byte ordering + * is unknown for the given host. + */ +template +int DataProcess_Endianness_Check(const T & a); + +template<> +int DataProcess_Endianness_Check(const float & a); + +template<> +int DataProcess_Endianness_Check(const double & a); + +} /* namespace DataProcess */ + +#endif /* DATAPROCESS_ENDIANNESS_CHECK_H */ + +/* End of DataProcess_Endianness_Check.h */ diff --git a/src/Core/Src/FileStreams.cpp b/src/Core/Src/FileStreams.cpp index f8be1ef..66b6c38 100644 --- a/src/Core/Src/FileStreams.cpp +++ b/src/Core/Src/FileStreams.cpp @@ -31,7 +31,7 @@ Mode Values are std::string FileStreams::configCreate(std::string path, Panic::Panic_ERROR & error) { // init vars - ofstream Ini; + std::ofstream Ini; // open file on disk. Ini.open(path.c_str()); @@ -52,11 +52,11 @@ std::string FileStreams::configCreate(std::string path, Panic::Panic_ERROR & err return "OK"; } -std::string FileStreams::configParser(string path, string key, Panic::Panic_ERROR & Error) +std::string FileStreams::configParser(std::string path, std::string key, Panic::Panic_ERROR & Error) { // init vars - ifstream Ini; + std::ifstream Ini; bool dataFound = false; bool fileatEOF = false; bool fileFail = false; @@ -68,8 +68,7 @@ std::string FileStreams::configParser(string path, string key, Panic::Panic_ERRO long diff = 0; // Open file - - Ini.open(path.c_str(), ios::in); + Ini.open(path.c_str(), std::ios::in); // check if file open failed @@ -100,7 +99,7 @@ std::string FileStreams::configParser(string path, string key, Panic::Panic_ERRO // Comment Line ignore it. temp = ""; } - if (temp.find(key) != string::npos) + if (temp.find(key) != std::string::npos) { // data found. Condence variable to just data and return it. dStartLocation = temp.find("="); @@ -126,12 +125,12 @@ std::string FileStreams::configParser(string path, string key, Panic::Panic_ERRO output = temp; Ini.close(); } - if (temp.find(key) == string::npos && Ini.eof() != true) + if (temp.find(key) == std::string::npos && Ini.eof() != true) { // data not found try again. fileatEOF = false; } - if (temp.find(key) == string::npos && Ini.eof() == true) + if (temp.find(key) == std::string::npos && Ini.eof() == true) { // We didn't find what we were looking for so close the file, warn the user, clear the buffers, and exit the function. fileatEOF = true; @@ -145,10 +144,10 @@ std::string FileStreams::configParser(string path, string key, Panic::Panic_ERRO } -string FileStreams::configWriter(string path, string key, string value, Panic::Panic_ERROR & error , bool createkey) +std::string FileStreams::configWriter(std::string path, std::string key, std::string value, Panic::Panic_ERROR & error , bool createkey) { // Init vars. - fstream OUT; // Output File stream + std::fstream OUT; // Output File stream bool keyfound = false; // has key been found in file bool atEOF = false; // has end of file been hit. std::string buffer = ""; // Temp buffer for data from file. @@ -191,8 +190,8 @@ string FileStreams::configWriter(string path, string key, string value, Panic::P // Get line from file getline(OUT , buffer); - // Check buffer for string - if (buffer.find(key.c_str()) != string::npos) + // Check buffer for std::string + if (buffer.find(key.c_str()) != std::string::npos) { // Key found keyfound = true; @@ -217,7 +216,7 @@ string FileStreams::configWriter(string path, string key, string value, Panic::P // Open file in write mode. - OUT.open(path.c_str(), ios::out); + OUT.open(path.c_str(), std::ios::out); // If key is not present and createkey is true write key into file. @@ -225,7 +224,7 @@ string FileStreams::configWriter(string path, string key, string value, Panic::P if (keyfound == false && createkey == true) { // Seek to eof. - OUT.seekp(ios::end); + OUT.seekp(std::ios::end); // Write key to file before writing variable. OUT << key <<" = " ; @@ -235,7 +234,7 @@ string FileStreams::configWriter(string path, string key, string value, Panic::P if (keyfound == true) { // Move to correct line. - OUT.seekp(ios::beg+location); + OUT.seekp(std::ios::beg+location); getline(OUT, buffer); } @@ -256,7 +255,7 @@ std::string readFile(std::string file_name, int indexNumber) //char input[900]; std::string output; output = ""; - ifstream SYSIN; + std::ifstream SYSIN; bool indexnumberFound = false; bool fileatEOF = false; std::string temp = ""; @@ -271,62 +270,62 @@ std::string readFile(std::string file_name, int indexNumber) realIndexNumber = realIndexNumber += indexNumber; realIndexNumber = realIndexNumber += ']'; - cout << "the realIndexNumber is : " < 2) { - cout << "ERROR: FileStreams.cpp: Unknown Command. \n"; - cout << "the mode is : " << mode <<"\n" << "the filename is : " << file_name <<"\n" << "the data is: " << data << "\n"; + std::cout << "ERROR: FileStreams.cpp: Unknown Command. \n"; + std::cout << "the mode is : " << mode <<"\n" << "the filename is : " << file_name.c_str() <<"\n" << "the data is: " << data.c_str() << "\n"; errorCode = mode; } return errorCode; } -string FileStreams::readEntireFile(std::string filename, Panic::Panic_ERROR & error) +std::string FileStreams::readEntireFile(std::string filename, Panic::Panic_ERROR & error) { // init vars std::string output = ""; std::string temp = ""; - ifstream SYSIN; + std::ifstream SYSIN; // Open the file - SYSIN.open(filename.c_str(), ios::in); + SYSIN.open(filename.c_str(), std::ios::in); // Make sure file is open if (SYSIN.is_open() != true) { // File did not open call PanicHandler and exit the function. - cout << "ERROR: Opening File " <LastError = "PanicHandler : No error message specified"; // Print error to stdout - cout << "PanicHandler : No error message specified" <<"\n\n"; + std::cout << "PanicHandler : No error message specified" <<"\n\n"; // Check and see if we need to die. if (killengine == true) @@ -85,7 +86,7 @@ std::string Panic::Panic_ERROR::PanicHandler(const std::string & message, const this->LastError += message; // Print error to stdout. - cout << "\nPanicHandler: " << this->LastError <<"\n\n"; + std::cout << "\nPanicHandler: " << this->LastError.c_str() <<"\n\n"; } // Check and see if logging is enabled. @@ -105,21 +106,21 @@ std::string Panic::Panic_ERROR::PanicHandler(const std::string & message, const { // Reset the log line count and reset file position. this->currentLogLine = 0; - this->logfile.seekp(0, ios::beg); - this->logfile.seekg(0, ios::beg); + this->logfile.seekp(0, std::ios::beg); + this->logfile.seekg(0, std::ios::beg); // Create old file name. temp_path = this->pathToLogFile; temp_path += ".old"; // Try to open the file. - old_log_file.open(temp_path.c_str(), ios::in | ios::out | ios::trunc); + old_log_file.open(temp_path.c_str(), std::ios::in | std::ios::out | std::ios::trunc); if (old_log_file.is_open()) { // Compute the size of the old log file. - this->logfile.seekg(0, ios::end); + this->logfile.seekg(0, std::ios::end); size = this->logfile.tellg(); - this->logfile.seekg(0, ios::beg); + this->logfile.seekg(0, std::ios::beg); // Copy the old log file. for(size_t x = 0; x < size; x++) @@ -136,7 +137,7 @@ std::string Panic::Panic_ERROR::PanicHandler(const std::string & message, const // Close the log_file and attempt to reopen it. this->logfile.close(); - this->logfile.open(this->pathToLogFile.c_str(), ios::in | ios::out | ios::trunc); + this->logfile.open(this->pathToLogFile.c_str(), std::ios::in | std::ios::out | std::ios::trunc); if(!this->logfile.is_open()) { // Could not open log file, disable logging. @@ -155,7 +156,7 @@ std::string Panic::Panic_ERROR::PanicHandler(const std::string & message, const } // Write the log entry. - this->logfile << this->LastError << '\n'; + this->logfile << this->LastError.c_str() << '\n'; // Flush the output buffer. this->logfile.flush(); @@ -202,7 +203,7 @@ short Panic::Panic_ERROR::enable_logging(const std::string & path_to_logfile, co } // Attempt to open the file. - this->logfile.open(path_to_logfile.c_str(), ios::in | ios::out | ios::trunc); + this->logfile.open(path_to_logfile.c_str(), std::ios::in | std::ios::out | std::ios::trunc); if (this->logfile.is_open() == false) { // Could not open log file. @@ -287,7 +288,7 @@ unsigned int Panic::Panic_ERROR::get_current_log_line() const return this->currentLogLine; } -void Panic::FileStream_Status(Panic::Panic_ERROR & error, fstream & stream, const unsigned int & log_level) +void Panic::FileStream_Status(Panic::Panic_ERROR & error, std::fstream & stream, const unsigned int & log_level) { // Output status header. error.PanicHandler("FileStream_Status:", ERROR_ID, log_level); diff --git a/src/Core/Src/Panic.h b/src/Core/Src/Panic.h index 23f4df5..72ebebf 100644 --- a/src/Core/Src/Panic.h +++ b/src/Core/Src/Panic.h @@ -19,12 +19,11 @@ https://github.com/codebase7/mengine */ +/* Include guard. */ #ifndef PANIC_H #define PANIC_H -#include "BaseHeader.h" - -// Define version and compile date time. +/* Define version and compile date time. */ #ifndef PANIC_HANDLER_VERSION #define PANIC_HANDLER_VERSION "0.0.1 Alpha\0" #endif @@ -37,7 +36,7 @@ #define PANIC_HANDLER_COMPILETIME __TIME__ #endif -// Module ERROR IDs +/* Module ERROR IDs */ #define CORE_ID 1 #define COMMON_ID 2 #define GAME_ID 7 @@ -45,7 +44,19 @@ #define PORT_AUDIO_ID 9 #define ERROR_ID 10 -#include "Panic_Error_Levels.h" // Defines the error / log levels. +/* Include the error / log level definitions. */ +#include "Panic_Error_Levels.h" + +/* Check for C++ compiler. */ +#ifdef __cplusplus + +/* Internal includes. */ +#include "../../DLL_PORT.h" /* Defines MSYS_DLL_EXPORT. */ + +/* External includes. */ +#include +#include +#include namespace Panic{ class Panic_ERROR { @@ -57,7 +68,7 @@ class Panic_ERROR { unsigned int logLevel; // Determines when to write to the log file. unsigned int maxLogLines; // Determines when the log file will start being overwritten. unsigned int currentLogLine; // Contains the current Log line. - fstream logfile; // File handler for the log file. + std::fstream logfile; // File handler for the log file. bool logfile_enabled; // Used to tell if we are writing to a log file or not. /* @@ -210,11 +221,11 @@ class Panic_ERROR { MSYS_DLL_EXPORT unsigned int get_current_log_line() const; }; /*! - void Panic::FileStream_Status(Panic::ERROR & error, fstream & stream, const unsigned int & log_level) + void Panic::FileStream_Status(Panic::ERROR & error, std::fstream & stream, const unsigned int & log_level) Gets the status for a given file stream, and outputs that status to the given error handler with the given log_level. */ - MSYS_DLL_EXPORT void FileStream_Status(Panic::Panic_ERROR & error, fstream & stream, const unsigned int & log_level); + MSYS_DLL_EXPORT void FileStream_Status(Panic::Panic_ERROR & error, std::fstream & stream, const unsigned int & log_level); /*! const char * Panic::Get_Library_Version() @@ -238,6 +249,8 @@ class Panic_ERROR { MSYS_DLL_EXPORT const char * Get_Library_Compile_Time(); } -#endif +#endif /* __cplusplus */ + +#endif /* PANIC_H */ -// End of Panic.h +/* End of Panic.h */ diff --git a/src/Core/Src/Panic_Error_Levels.h b/src/Core/Src/Panic_Error_Levels.h index 2616c9a..18421a0 100644 --- a/src/Core/Src/Panic_Error_Levels.h +++ b/src/Core/Src/Panic_Error_Levels.h @@ -19,11 +19,11 @@ https://github.com/codebase7/mengine */ -// Include guard. +/* Include guard. */ #ifndef PANIC_ERROR_LEVELS_H #define PANIC_ERROR_LEVELS_H -// Define the error / log levels. +/* Define the error / log levels. */ #define ERROR_DISABLE 0 #define ERROR_CRITICAL 1 #define ERROR_WARNING 2 @@ -31,6 +31,6 @@ #define ERROR_DEBUG 4 #define ERROR_VERBOSE 5 -#endif // PANIC_ERROR_LEVELS_H +#endif /* PANIC_ERROR_LEVELS_H */ -// End of Panic_Error_Levels.h \ No newline at end of file +/* End of Panic_Error_Levels.h */ diff --git a/src/Tests/CMakeLists.txt b/src/Tests/CMakeLists.txt index d6ed68f..91a73fc 100644 --- a/src/Tests/CMakeLists.txt +++ b/src/Tests/CMakeLists.txt @@ -5,11 +5,13 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${O_OUTPUT_DIR}) # Define Unit Tests base includes. set (UNIT_TESTS_INCLUDES_BASE Unit_Tests.cpp) -# We may make Core an optional subsystem in the future. +# We may make Core and Byte_Order an optional subsystem in the future. set (UNIT_TESTS_INCLUDES ${UNIT_TESTS_INCLUDES_BASE} Test_Base_Header.cpp +Unit_Test_DataProcess.c Unit_Test_Data_Object.cpp -Unit_Test_Data_Object_Insert_Char.cpp) +Unit_Test_Data_Object_Insert_Char.cpp +Unit_Test_Byte_Order.cpp) # Only build the tests for the subsystems that are enabled. if (BUILD_COMMON_ERROR_HANDLER) diff --git a/src/Tests/Test_Base_Header.h b/src/Tests/Test_Base_Header.h index f435d66..3028489 100644 --- a/src/Tests/Test_Base_Header.h +++ b/src/Tests/Test_Base_Header.h @@ -22,7 +22,17 @@ #define TEST_BASE_HEADER_H // External Includes. + +/* C++ specific includes. */ +#ifdef __cplusplus #include // For std::cout / NULL macro. +#else +/* C specific includes. */ +#include +#include +#include +#endif /* __cplusplus */ + #include // For strcmp. #ifdef _WIN32 #include /* For SleepEx(). */ diff --git a/src/Tests/Unit_Test_Byte_Order.cpp b/src/Tests/Unit_Test_Byte_Order.cpp new file mode 100644 index 0000000..b9011f8 --- /dev/null +++ b/src/Tests/Unit_Test_Byte_Order.cpp @@ -0,0 +1,461 @@ +/*! + Multiverse Engine Project 11/7/2015 Unit Tests Unit_Test_Byte_Order.cpp + + Copyright (C) 2015 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Internal includes. */ +#include "Unit_Tests.h" + +void Print_Random_Bits(const char bits) +{ + /* Init vars. */ + int retFromFunct = COMMON_ERROR_UNKNOWN_ERROR; /* Result code from engine function. */ + char * bitMaskString = NULL; /* The bitmask represented as a human-readable string. */ + size_t bitMaskStringLength = 0; /* The length of the bit mask string. */ + + /* Print the bits. */ + retFromFunct = Common_Print_Bytes_In_Binary(&bits, 1, &bitMaskString, &bitMaskStringLength, 1); + if (retFromFunct == COMMON_ERROR_SUCCESS) + { + /* Print the string. */ + std::cout << bitMaskString << " "; + + /* Deallocate the string. */ + Common_Deallocate_Print_Bytes_CString(&bitMaskString); + } + else + { + std::cout << "< ERROR: Unable to print random bits, Common_Print_Bytes_In_Binary() failed. > "; + } + std::cout.flush(); + + /* Exit function. */ + return; +} + +void Print_Bits_and_BitMask(const char byteToCheck, const char bitMask, const char bitValues) +{ + /* Print the values. */ + std::cout << "DEBUG: BYTE:\t\t"; + Print_Random_Bits(byteToCheck); + std::cout << "\nDEBUG: BITMASK:\t\t"; + Print_Random_Bits(bitMask); + std::cout << "\nDEBUG: BIT_VALUES:\t"; + Print_Random_Bits(bitValues); + std::cout << '\n'; + std::cout.flush(); + + /* Exit function. */ + return; +} + +char Generate_Random_Non_Conforming_Bit_Mask(const char byte1, const char byte2) +{ + /* Init vars. */ + char ret = '\0'; /* The result of this function. */ + + /* Generate a random bit mask to check for. */ + std::cout << "Generating random bit mask. Please Wait.\n"; + std::cout.flush(); + + /* Begin generation loop. */ + do + { + ret = ((char)DataProcess::Trivial_Random_Number_Generator(0, 255)); + } while ((byte1 | byte2) ^ ret); + + /* Exit function. */ + return ret; +} + +char Generate_Random_Bit_Mask(const char bitMask) +{ + /* Init vars. */ + char ret = '\0'; /* The result of this function. */ + + /* Generate a random bit mask to check for. */ + std::cout << "Generating random bit mask. Please Wait.\n"; + std::cout.flush(); + do + { + /* Generate a bit mask. */ + ret = ((char)DataProcess::Trivial_Random_Number_Generator(1, 254)); + } while (ret == bitMask); + + /* Exit function. */ + return ret; +} + +char Generate_Random_Bits(const char notThisValue) +{ + /* Init vars. */ + char ret = '\0'; /* The result of this function. */ + + /* Generate some random bits to check for. */ + std::cout << "Generating random bits. Please Wait.\n"; + std::cout.flush(); + + /* Generate some bits, avoiding the given value if needed. */ + while (ret == notThisValue) + { + ret = ((char)DataProcess::Trivial_Random_Number_Generator(2, 254)); + } + + /* Exit function. */ + return ret; +} + +int Generate_Matching_Bitmask_Random_Data(char * byteToCheck, char * bitMask, char * bitValues) +{ + /* Init vars. */ + int ret = COMMON_ERROR_UNKNOWN_ERROR; /* The result code of this function. */ + + /* Check for invalid arguments. */ + if ((byteToCheck != NULL) && (bitMask != NULL) && (bitValues != NULL)) + { + /* Call bitmask generation function. */ + (*bitMask) = Generate_Random_Bit_Mask(0); + + /* Generate the byteToCheck and bitValues data. (If needed, check memory addresses.) */ + if (byteToCheck != bitMask) + { + (*byteToCheck) = Generate_Random_Bits((*bitMask)); + + /* Bitwise Or the bitMask to the byteToCheck data. */ + (*byteToCheck) |= (*bitMask); + } + if ((bitValues != bitMask) && (bitValues != byteToCheck)) + { + (*bitValues) = Generate_Random_Bits((*byteToCheck)); + + /* Bitwise Or the bitMask to the bitValues data. */ + (*bitValues) |= (*bitMask); + } + + /* Done. */ + ret = COMMON_ERROR_SUCCESS; + } + else + { + /* Invalid arguments. */ + ret = COMMON_ERROR_INVALID_ARGUMENT; + } + + /* Exit function. */ + return ret; +} + +int unit_test_byte_order_Common_Print_Bytes_In_Binary_check() +{ + /* Init vars. */ + int ret = 0; /* The result of this function. */ + + + + /* Exit function. */ + return ret; +} + +int unit_test_byte_order_comparison_check() +{ + /* Init vars. */ + int ret = 0; /* The result of this function. */ + char byteToCheck = '\0'; /* The byte to compare against. */ + char bitMask = '\0'; /* The bits we should compare. */ + char bitValues = '\0'; /* The bits we compare to. */ + char extraBits = '\0'; /* Used to generate extra random bits to test with. */ + + /* Run zero comparison checks. */ + std::cout << "Byte_Order_Bit_Comparison() Test 1: All zero, no bits to check test. (Should result in COMMON_ERROR_COMPARISON_FAILED.): "; + if (Byte_Order_Bit_Comparison(&byteToCheck, bitMask, bitValues) == COMMON_ERROR_COMPARISON_FAILED) + { + /* Test 1 successful. */ + std::cout << "PASS\n"; + std::cout << "Byte_Order_Bit_Comparison() Test 2: All zero, check all bits test. (Should result in COMMON_ERROR_COMPARISON_PASSED.): "; + bitMask = CHAR_MIN; + if (Byte_Order_Bit_Comparison(&byteToCheck, bitMask, bitValues) == COMMON_ERROR_COMPARISON_PASSED) + { + /* Test 2 successful. */ + std::cout << "PASS\n"; + + /* Generate random bit mask. */ + std::cout << "Byte_Order_Bit_Comparison() Test 3: All zero, random bit mask test.\n"; + bitMask = Generate_Random_Bit_Mask(0); + Print_Bits_and_BitMask(byteToCheck, bitMask, bitValues); + std::cout << "(Should result in COMMON_ERROR_COMPARISON_PASSED.): "; + + /* Perform all zero test with random bit mask. */ + if (Byte_Order_Bit_Comparison(&byteToCheck, bitMask, bitValues) == COMMON_ERROR_COMPARISON_PASSED) + { + /* Test 3 successful. */ + std::cout << "PASS\n"; + + std::cout << "Byte_Order_Bit_Comparison() Test 4: Non-zero matching bits, no bits to check test. (Should result in COMMON_ERROR_COMPARISON_FAILED.): "; + /* Begin checks on non-zero bit values. */ + bitMask = 0; + bitValues = 1; + byteToCheck = 1; + if (Byte_Order_Bit_Comparison(&byteToCheck, bitMask, bitValues) == COMMON_ERROR_COMPARISON_FAILED) + { + /* Test 4 successful. */ + std::cout << "PASS\n"; + + std::cout << "Byte_Order_Bit_Comparison() Test 5: Non-zero matching bits, check bits test. (Should result in COMMON_ERROR_COMPARISON_PASSED.): "; + bitMask = 1; + + if (Byte_Order_Bit_Comparison(&byteToCheck, bitMask, bitValues) == COMMON_ERROR_COMPARISON_PASSED) + { + /* Test 5 successful. */ + std::cout << "PASS\n"; + + std::cout << "Byte_Order_Bit_Comparison() Test 6: Non-zero matching bits, extra bits in byte, check bits test.\n"; + Generate_Matching_Bitmask_Random_Data(&byteToCheck, &bitMask, &bitMask); + bitValues = bitMask; /* Only the bits in the bit mask should be set in bitValues. */ + Print_Bits_and_BitMask(byteToCheck, bitMask, bitValues); + std::cout << "(Should result in COMMON_ERROR_COMPARISON_PASSED.): "; + + /* Perform Non-zero matching bits, extra bits in byte, check bits test. */ + if (Byte_Order_Bit_Comparison(&byteToCheck, bitMask, bitValues) == COMMON_ERROR_COMPARISON_PASSED) + { + /* Test 6 successful. */ + std::cout << "PASS\n"; + + std::cout << "Byte_Order_Bit_Comparison() Test 7: Non-zero matching bits, extra bits in bitValues, check bits test.\n"; + Generate_Matching_Bitmask_Random_Data(&bitMask, &bitMask, &bitValues); + byteToCheck = bitMask; /* Only the bits in the bit mask should be set in byteToCheck. */ + Print_Bits_and_BitMask(byteToCheck, bitMask, bitValues); + std::cout << "(Should result in COMMON_ERROR_COMPARISON_PASSED.): "; + + /* Perform Non-zero matching bits, extra bits in bitValues, check bits test. */ + if (Byte_Order_Bit_Comparison(&byteToCheck, bitMask, bitValues) == COMMON_ERROR_COMPARISON_PASSED) + { + /* Test 7 successful. */ + std::cout << "PASS\n"; + + std::cout << "Byte_Order_Bit_Comparison() Test 8: Non-zero matching bits, extra bits in byte and bitValues, check bits test.\n"; + Generate_Matching_Bitmask_Random_Data(&byteToCheck, &bitMask, &bitValues); + Print_Bits_and_BitMask(byteToCheck, bitMask, bitValues); + std::cout << "(Should result in COMMON_ERROR_COMPARISON_PASSED.): "; + + /* Perform Non-zero matching bits, extra bits in byte and bitValues, check bits test. */ + if (Byte_Order_Bit_Comparison(&byteToCheck, bitMask, bitValues) == COMMON_ERROR_COMPARISON_PASSED) + { + /* Test 8 successful. */ + std::cout << "PASS\n"; + + std::cout << "Byte_Order_Bit_Comparison() Test 9: Non-zero matching bits, extra bits in byte and bitValues, random bitmask check bits test.\n"; + extraBits = Generate_Random_Bits(0); + + /* Binary OR the bits together so that the bits we check for will be valid. */ + byteToCheck = 0; + byteToCheck |= extraBits; + extraBits = Generate_Random_Bits(0); + + /* Binary OR the bits together so that the bits we check for will be valid. */ + bitValues = 0; + bitValues |= extraBits; + + /* Generate random bit mask. */ + bitMask = Generate_Random_Bit_Mask(0); + + /* Binary OR the bits together so that the bits we check for will be valid. */ + byteToCheck |= bitMask; + bitValues |= bitMask; + + Print_Bits_and_BitMask(byteToCheck, bitMask, bitValues); + std::cout << "(Should result in COMMON_ERROR_COMPARISON_PASSED.): "; + + /* Perform Non-zero matching bits, extra bits in byte and bitValues, random bitmask check bits test. */ + if (Byte_Order_Bit_Comparison(&byteToCheck, bitMask, bitValues) == COMMON_ERROR_COMPARISON_PASSED) + { + /* Test 9 successful. */ + std::cout << "PASS\n"; + + std::cout << "Byte_Order_Bit_Comparison() Test 10: Non-zero NON-matching bits, extra bits in byte and bitValues, random bitmask check bits test.\n"; + extraBits = Generate_Random_Bits(0); + + /* Binary OR the bits together so that the bits we check for will be valid. */ + byteToCheck = 0; + byteToCheck |= extraBits; + extraBits = Generate_Random_Bits(byteToCheck); + + /* Binary OR the bits together so that the bits we check for will be valid. */ + bitValues = 0; + bitValues |= extraBits; + + /* Generate random bit mask. */ + bitMask = Generate_Random_Non_Conforming_Bit_Mask(byteToCheck, bitValues); + + Print_Bits_and_BitMask(byteToCheck, bitMask, bitValues); + std::cout << "(Should result in COMMON_ERROR_COMPARISON_FAILED.): "; + + /* Perform Non-zero NON-matching bits, extra bits in byte and bitValues, random bitmask check bits test. */ + if (Byte_Order_Bit_Comparison(&byteToCheck, bitMask, bitValues) == COMMON_ERROR_COMPARISON_FAILED) + { + /* Test 10 successful. */ + std::cout << "PASS\n"; + + std::cout << "Byte_Order_Bit_Comparison() Test 11: All bits set, check all bits test. (Should result in COMMON_ERROR_COMPARISON_PASSED.): "; + bitMask = UCHAR_MAX; + byteToCheck = UCHAR_MAX; + bitValues = UCHAR_MAX; + + /* Perform All bits set, check all bits test. */ + if (Byte_Order_Bit_Comparison(&byteToCheck, bitMask, bitValues) == COMMON_ERROR_COMPARISON_PASSED) + { + /* Test 11 successful. */ + std::cout << "PASS\n"; + std::cout << "Byte_Order_Bit_Comparison() Test 12: All bits set, no bits to check test. (Should result in COMMON_ERROR_COMPARISON_FAILED.): "; + bitMask = 0; + + /* Perform All bits set, no bits to check test. */ + if (Byte_Order_Bit_Comparison(&byteToCheck, bitMask, bitValues) == COMMON_ERROR_COMPARISON_FAILED) + { + /* Test 12 successful. */ + std::cout << "PASS\n"; + + std::cout << "Byte_Order_Bit_Comparison() Test 13: All bits set, random bit mask test.\n"; + bitMask = Generate_Random_Bit_Mask(0); + Print_Bits_and_BitMask(byteToCheck, bitMask, bitValues); + std::cout << "(Should result in COMMON_ERROR_COMPARISON_PASSED.): "; + + /* Perform All bits set, random bit mask test. */ + if (Byte_Order_Bit_Comparison(&byteToCheck, bitMask, bitValues) == COMMON_ERROR_COMPARISON_PASSED) + { + /* Test 13 successful. */ + std::cout << "PASS\n"; + + /* End of tests. */ + ret = 0; + } + else + { + /* All bits set, random bit mask test failed. */ + ret = -13; + std::cout << "FAIL\n"; + } + } + else + { + /* All bits set, no bits to check test failed. */ + ret = -12; + std::cout << "FAIL\n"; + } + } + else + { + /* All bits set, check all bits test failed. */ + ret = -11; + std::cout << "FAIL\n"; + } + } + else + { + /* Non-zero NON-matching bits, extra bits in byte and bitValues, random bitmask check bits test failed. */ + ret = -10; + std::cout << "FAIL\n"; + } + } + else + { + /* Non-zero matching bits, extra bits in byte and bitValues, random bitmask check bits test failed. */ + ret = -9; + std::cout << "FAIL\n"; + } + } + else + { + /* Non-zero matching bits, extra bits in byte and bitValues, check bits test failed. */ + ret = -8; + std::cout << "FAIL\n"; + } + } + else + { + /* Non-zero matching bits, extra bits in bitValues, check bits test failed. */ + ret = -7; + std::cout << "FAIL\n"; + } + } + else + { + /* Non-zero matching bits, extra bits in byte, check bits test failed. */ + ret = -6; + std::cout << "FAIL\n"; + } + } + else + { + /* Non-zero matching bits, check bits test failed. */ + ret = -5; + std::cout << "FAIL\n"; + } + } + else + { + /* Non-zero matching bits, no bits to check test failed. */ + ret = -4; + std::cout << "FAIL\n"; + } + } + else + { + /* All zero, random bit mask test failed. */ + ret = -3; + std::cout << "FAIL\n"; + } + } + else + { + /* All zero, check all bits test failed. */ + ret = -2; + std::cout << "FAIL\n"; + } + } + else + { + /* All zero no bits to check test failed. */ + ret = -1; + std::cout << "FAIL\n"; + } + + /* Flush output buffer. */ + std::cout.flush(); + + /* Exit function. */ + return ret; +} + +int Unit_Test_Byte_Order_Main() +{ + /* Init vars. */ + int ret = 0; /* The result of this function. */ + int result_comparision_check = 0; /* The result of the comparison checks. */ + + /* Output START OF TEST SECTION. */ + std::cout << START_TEST_SECTION; + + /* Run comparison checks. */ + result_comparision_check = unit_test_byte_order_comparison_check(); + + /* Output END OF TEST SECTION. */ + std::cout << END_TEST_SECTION; + + /* Exit function. */ + return ret; +} diff --git a/src/Tests/Unit_Test_Common.h b/src/Tests/Unit_Test_Common.h index d72fb95..20c1a9d 100644 --- a/src/Tests/Unit_Test_Common.h +++ b/src/Tests/Unit_Test_Common.h @@ -23,6 +23,8 @@ #define COMMON_UNIT_TESTS_H /* Include headers from Common. (If needed.) */ +#include "Unit_Tests_Byte_Order.h" + #ifdef MSYS_HAVE_FILEUTILLS #include "Unit_Tests_FileUtills.h" #endif /* MSYS_HAVE_FILEUTILLS */ diff --git a/src/Tests/Unit_Test_Core.h b/src/Tests/Unit_Test_Core.h index cae904d..0fcad61 100644 --- a/src/Tests/Unit_Test_Core.h +++ b/src/Tests/Unit_Test_Core.h @@ -24,6 +24,17 @@ // Include headers from Core. #include "../Core/Src/DataProcess.h" +/* The Unit_Tests_DataProcess_Main() function is a C function. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +int Unit_Tests_DataProcess_Main(); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + int Unit_Test_Data_Object(); int Unit_Test_Data_Object_Insert_char(); diff --git a/src/Tests/Unit_Test_DataProcess.c b/src/Tests/Unit_Test_DataProcess.c new file mode 100644 index 0000000..38dd39f --- /dev/null +++ b/src/Tests/Unit_Test_DataProcess.c @@ -0,0 +1,1067 @@ +/*! + Multiverse Engine Project 09/9/2015 Unit Tests Unit_Test_DataProcess.c + + Copyright (C) 2015 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Internal includes. */ +#include "Unit_Tests.h" + +/*! + * Unit_Tests_DataProcess_TRNG() + * + * Tests the DataProcess_Trivial_Random_Number_Generator() function. + * Function should return at least one different value in both runs for the test to be considered successful. + * + * Note: The number of values per run can be controlled by the TEST_ARRAY_SIZE #define within the function. + * + * Note: The range of permissible values returned by the function can be controlled by the TEST_MIN_VAL and + * TEST_MAX_VAL #define(s) within the function, however the test code expects a result of zero (0) to be an error, + * so the range defined by TEST_MIN_VAL and TEST_MAX_VAL should NOT include zero (0) for it to work correctly. + * (The original range is 1 - 10000.) + * + * Note: The number of test runs performed by the function can be controlled by the TEST_NUM_OF_RUNS #define + * within the function, however the test code expects that at least two (2) runs will be made, so TEST_NUM_OF_RUNS + * must be greater than two (2) for the function to work correctly. + * + * Returns 0 if the test passes. + * Returns -1 if the initial function call does not return a valid value. + * Returns -2 if the TRNG function's seed could not be reset. + * Returns -3 if the output from the TRNG function for both runs was identical. + * Returns -9 if an unknown error occurs. + * Returns -10 if memory allocation fails. + */ +int Unit_Tests_DataProcess_TRNG() +{ +#define TEST_ARRAY_SIZE 10 /* Size of the test arrays, (also defines the number of calls per test run of the tested function.) */ +#define TEST_MIN_VAL 1 /* Minimal value that the test function may return. (Do NOT set this to zero the test code below will fail to work correctly if you do.) */ +#define TEST_MAX_VAL 10000 /* Maximum value that the test function may return. (This value should be bigger than TEST_MIN_VAL.) */ +#define TEST_NUM_OF_RUNS 10 /* Number of test runs to make. */ + + /* Init vars. */ + int ret = -9; /* Result of this test. */ + size_t retFromTRNG = 0; /* The result of the call to the TRNG. */ + size_t x = 0; /* Counter used in the outer for loops. */ + size_t y = 0; /* Counter used in the inner for loops. */ + size_t ** testArrays[TEST_NUM_OF_RUNS] = { NULL }; /* Holds the pointer to the test result arrays. */ + const char * ERR_MSG_INVALID_VAL = "TEST FAILURE: Unit_Tests_DataProcess_TRNG(): Call to DataProcess_Trivial_Random_Number_Generator() returned an invalid value.\n"; + const char * ERR_MSG_INVALID_VAL_RESET = "TEST FAILURE: Unit_Tests_DataProcess_TRNG(): Unable to reset TRNG, call to DataProcess_Trivial_Random_Number_Generator() returned an invalid value.\n"; + const char * STAT_MSG_RESET_TRNG = "TEST INFO: Unit_Tests_DataProcess_TRNG(): Resetting TRNG.\n"; + const char * STAT_MSG_BEGIN_RUN = "TEST INFO: Unit_Tests_DataProcess_TRNG(): Begining test run, please wait.\n"; + const char * STAT_MSG_CHECK_RETVALS = "TEST INFO: Unit_Tests_DataProcess_TRNG(): Checking results of the test runs to see if they do not match. Please wait.\n"; + const char * STAT_MSG_INITIAL_CALL = "TEST INFO: Unit_Tests_DataProcess_TRNG(): Makeing initial test call to DataProcess_Trivial_Random_Number_Generator(). Please Wait.\n"; + const char * STAT_MSG_TEST_PASS = "TEST INFO: Unit_Tests_DataProcess_TRNG(): TEST PASSED.\n"; + const char * STAT_MSG_TEST_FAIL = "TEST INFO: Unit_Tests_DataProcess_TRNG(): TEST FAILED, generated numbers were identical despite TRNG reset.\n"; + const char * ERR_MSG_MEM_ALLOC_FAIL = "TEST FAILURE: Unit_Tests_DataProcess_TRNG(): Unable to allocate memory for test.\n"; + const char * ERR_MSG_INVALID_PTR_TO_ARRAYS = "TEST FAILURE: Unit_Tests_DataProcess_TRNG(): Invalid pointer to result arrays.\n"; + const char * ERR_MSG_INVALID_ARRAY = "TEST FAILURE: Unit_Tests_DataProcess_TRNG(): Invalid result array pointer.\n"; + + /* Start test section. */ + printf("%s", START_TEST_SECTION); + + /* Run call. */ + printf("%s", STAT_MSG_INITIAL_CALL); + retFromTRNG = DataProcess_Trivial_Random_Number_Generator(TEST_MIN_VAL, TEST_MAX_VAL, false); + if ((retFromTRNG >= TEST_MIN_VAL) && (retFromTRNG <= TEST_MAX_VAL)) + { + /* Begin test run memory allocation outer loop. */ + printf("%s", STAT_MSG_BEGIN_RUN); + for (x = 0; ((x < TEST_NUM_OF_RUNS) && (ret == -9)); x++) + { + /* Allocate memory for test array pointer. */ + testArrays[x] = (size_t **)malloc(((sizeof(size_t *)) * TEST_ARRAY_SIZE)); + if (testArrays[x] != NULL) + { + /* Set the pointers to NULL, and allocate them. */ + memset(testArrays[x], 0, ((sizeof(size_t *)) * TEST_ARRAY_SIZE)); + + /* Allocate the test array values. */ + for (y = 0; ((y < TEST_ARRAY_SIZE) && (ret == -9)); y++) + { + (testArrays[x])[y] = (size_t *)malloc(sizeof(size_t)); + if ((testArrays[x])[y] != NULL) + { + /* Set the allocated value to zero. (0). */ + *((testArrays[x])[y]) = 0; + } + else + { + /* Memory allocation error. */ + ret = -10; + printf("%s", ERR_MSG_MEM_ALLOC_FAIL); + } + } + } + + /* Check for mem alloc success. */ + if (ret == -9) + { + /* Reset the TRNG. */ + printf("%s", STAT_MSG_RESET_TRNG); + retFromTRNG = DataProcess_Trivial_Random_Number_Generator(TEST_MIN_VAL, TEST_MAX_VAL, true); + if ((retFromTRNG >= TEST_MIN_VAL) && (retFromTRNG <= TEST_MAX_VAL)) + { + /* Begin test run inner loop. */ + for (y = 0; ((y < TEST_ARRAY_SIZE) && ((retFromTRNG >= TEST_MIN_VAL) && (retFromTRNG <= TEST_MAX_VAL))); y++) + { + retFromTRNG = DataProcess_Trivial_Random_Number_Generator(TEST_MIN_VAL, TEST_MAX_VAL, false); + if ((retFromTRNG >= TEST_MIN_VAL) && (retFromTRNG <= TEST_MAX_VAL)) + { + /* Copy the value to the array. */ + (*((testArrays[x])[y])) = retFromTRNG; + } + else + { + /* Test failure, invalid value. */ + ret = -1; + printf("%s", ERR_MSG_INVALID_VAL); + } + } + } + else + { + /* Could not reset the TRNG. */ + ret = -2; + printf("%s", ERR_MSG_INVALID_VAL_RESET); + } + } + } /* End of test run outer loop. */ + + /* Check for valid data. */ + if ((ret == -9) && (testArrays != NULL)) + { + /* Begin test result loop. */ + for (x = 0; (x < TEST_NUM_OF_RUNS); x++) + { + /* Check for NULL. */ + if (testArrays[x] == NULL) + { + /* Invalid test result arrays. */ + ret = -10; + printf("%s", ERR_MSG_INVALID_ARRAY); + } + } + + /* Check for success. */ + if (ret == -9) + { + /* Set failure code to bad RNG source. */ + ret = -3; + + /* A note about the verify loop structure: + * + * The outer loop runs through each value in the result array, + * and the inner loop loops through each result array. + * + * The reason why is that we are looking for a value to be different + * at some point in each array. I.e. We care about the order in which the + * values appear, not the values themselves. As long as at least one pair of + * values at the exact same position in the arrays do not match each other, + * the test is considered successful. + */ + /* Begin outer verify loop. (Loops through each value.) */ + for (y = 0; ((y < TEST_ARRAY_SIZE) && (ret == -3)); y++) + { + /* Begin inner verify loop. (Loops through each result array.) */ + for (x = 0; ((x < (TEST_NUM_OF_RUNS - 1)) && (ret == -3)); x++) + { + /* Check the results of each run to see if they match exactly, (they should not.) */ + if ((*((testArrays[x])[y])) != (*((testArrays[(x + 1)])[y]))) + { + /* Set ret to success. */ + ret = 0; + } + } + } + + /* Print out the arrays for verification. */ + printf("%s", "Random value table:\n|Run Number:|Random values:|\n"); + for (x = 0; (x < TEST_NUM_OF_RUNS); x++) + { + printf("|%u|", x); + for (y = 0; (y < TEST_ARRAY_SIZE); y++) + { + printf("%u ", (*((testArrays[x])[y]))); + } + printf("%s", "|\n"); + } + + /* Check for failure. */ + if (ret == 0) + { + printf("%s", STAT_MSG_TEST_PASS); + } + else + { + printf("%s", STAT_MSG_TEST_FAIL); + } + } + } + else + { + /* Invalid test result arrays. */ + ret = -10; + printf("%s", ERR_MSG_INVALID_PTR_TO_ARRAYS); + } + } + else + { + /* Test failure. */ + ret = -1; + printf("%s", ERR_MSG_INVALID_VAL); + } + + /* Deallocate memory. */ + for (x = 0; (x < TEST_NUM_OF_RUNS); x++) + { + /* Check for NULL. */ + if (testArrays[x] != NULL) + { + /* Deallocate the test array values. */ + for (y = 0; ((y < TEST_ARRAY_SIZE) && (ret == -9)); y++) + { + if ((testArrays[x])[y] != NULL) + { + free((testArrays[x])[y]); + (testArrays[x])[y] = NULL; + } + } + + /* Deallocate the pointer to the array. */ + free(testArrays[x]); + testArrays[x] = NULL; + } + } + + /* End test section. */ + printf("%s", END_TEST_SECTION); + + /* Return ret. */ + return ret; + +/* Run sanity checks on defines here, and abort build if they fail. */ +#if TEST_NUM_OF_RUNS < 2 +#error __FILE__ "Unit_Tests_DataProcess_TRNG(): TEST_NUM_OF_RUNS must be greater than one (1)." +#endif +#if TEST_MIN_VAL <= 0 +#error __FILE__ "Unit_Tests_DataProcess_TRNG(): TEST_MIN_VAL cannot be less than or equal to zero (0)." +#endif +#if (TEST_MAX_VAL <= TEST_MIN_VAL) +#error __FILE__ "Unit_Tests_DataProcess_TRNG(): TEST_MAX_VAL must be greater than TEST_MIN_VAL." +#endif + +#undef TEST_NUM_OF_RUNS +#undef TEST_MAX_VAL +#undef TEST_MIN_VAL +#undef TEST_ARRAY_SIZE +} + +/* Define TRNGUseMayFailMSG. */ +const static char * TRNGUseMayFailMSG = "The remainder of these tests rely on the DataProcess_Trivial_Random_Number_Generator() function to work correctly and may fail or give false results if that function does not work correctly. Therefore the results for the remainder of the test should only be considered valid if the TRNG function works correctly.\n\n"; + +/* Define some common error messages. */ +const static char * periodAndNewlineMSG = ".\n"; +const static char * errorCodeReturnedMSG = "The function returned error code: "; +const static char * errorSuccessNoResultMSG = "The function returned success without producing a result.\n"; +const static char * errorSamePtrMSG = "The function returned success, but the returned memory pointer is identical to the original one. (No actual allocation occured.)\n"; +const static char * InvalidArgStringPointerTestMSG = "Attempting to get COMMON_ERROR_INVALID_ARGUMENT error code by passing a NULL string pointer to "; +const static char * InvalidArgStringPointerFailMSG = "Unable to get COMMON_ERROR_INVALID_ARGUMENT error code by passing a NULL string pointer to "; +const static char * InvalidArgLengthPointerTestMSG = "Attempting to get COMMON_ERROR_INVALID_ARGUMENT error code by passing a NULL length pointer to "; +const static char * InvalidArgLengthPointerFailMSG = "Unable to get COMMON_ERROR_INVALID_ARGUMENT error code by passing a NULL length pointer to "; + +/*! + * int Unit_Tests_DataProcess_Random_String_Generator(char ** string, size_t * stringLength) + * + * Generates a c-string using printable ASCII characters for use by other testing functions. + * The generated string should be deallocated by DataProcess_Deallocate_CString() when it is + * no longer needed. + * + * Returns 0 if successful. + * Returns -1 if an argument pointer is NULL. + * Returns -2 if a random number could not be generated. + * Returns -3 if memory allocation fails. + * + * This function will not modifiy the given arguments if it's return code is not zero (0). + */ +int Unit_Tests_DataProcess_Random_String_Generator(char ** string, size_t * stringLength) +{ + /* Define the error messaging macros. */ +#define TEST_FAILURE_MSG_HEAD "TEST_FAILURE: Unit_Tests_DataProcess_Allocator_and_Deallocator(): " +#define TEST_ERROR_LOG_REAL(ERR_MSG) printf("%s", TEST_FAILURE_MSG_HEAD); printf("%s", ERR_MSG); +#define TEST_ERROR_LOG(ERR_MSG) TEST_ERROR_LOG_REAL(ERR_MSG) + + /* Define the range of ASCII values to use for the random string. */ +#define TEST_PRINTABLE_ASCII_START 33 +#define TEST_PRINTABLE_ASCII_END 126 + + /* Define the range used to select the length of the randomly generated string. */ +#define TEST_RANDOM_STRING_LENGTH_MINIMAL 3 +#define TEST_RANDOM_STRING_LENGTH_MAXIMUM 100 + + /* Init vars. */ + int ret = -999; /* Result of the tests. */ + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; /* Result code from engine function. */ + size_t x = 0; /* Counter used in random string generation loop. */ + size_t randVal = 0; /* Result from the call to TRNG() function. */ + size_t randomLength = 0; /* Chosen length of the string to be generated. */ + char * randString = NULL; /* Temporary pointer used to create the random string. */ + + /* Check for invalid arguments. */ + if ((string != NULL) && (stringLength != NULL)) + { + /* Randomly generate a length for the string. */ + randomLength = DataProcess_Trivial_Random_Number_Generator(TEST_RANDOM_STRING_LENGTH_MINIMAL, TEST_RANDOM_STRING_LENGTH_MAXIMUM, true); + if (randomLength > 0) + { + /* Allocate memory for the TRNG String. */ + retFromCall = DataProcess_Reallocate_C_String(&randString, 0, randomLength); + if ((retFromCall == COMMON_ERROR_SUCCESS) && (randString != NULL)) + { + /* Use the TRNG to generate the source string. (Note the last character in the string should be a NULL byte. + Which it is if the string was allocated by DataProcess_Reallocate_C_String().) + */ + for (x = 0; (x < (randomLength - 1)); x++) + { + randVal = DataProcess_Trivial_Random_Number_Generator(TEST_PRINTABLE_ASCII_START, TEST_PRINTABLE_ASCII_END, false); + randString[x] = (int)randVal; + } + + /* Copy the string pointer, and length value. */ + (*string) = randString; + (*stringLength) = (randomLength - 1); /* Omit NULL termination byte from string length. */ + + /* Done. */ + ret = 0; + } + else + { + /* Could not allocate memory? */ + ret = -3; + TEST_ERROR_LOG("Unable to allocate memory for random string.\n"); + ((retFromCall != COMMON_ERROR_SUCCESS) ? (printf("%s%i%s", errorCodeReturnedMSG, retFromCall, ".\n")) : + (printf("%s", errorSuccessNoResultMSG))); + } + } + else + { + /* Could not generate a random number. */ + ret = -2; + TEST_ERROR_LOG("Could not generate a random number.\n"); + } + } + else + { + /* Invalid arguments. */ + ret = -1; + TEST_ERROR_LOG("Invalid argument.\n"); + } + + /* Exit function. */ + return ret; + + /* Check for valid random string length. */ +#if TEST_RANDOM_STRING_LENGTH_MINIMAL < 3 +#error "Unit_Tests_DataProcess_Allocator_and_Deallocator(): TEST_RANDOM_STRING_LENGTH must be greater than two (2)." +#endif /* TEST_RANDOM_STRING_LENGTH < 3 */ + + /* Check for valid ASCII ranges. */ +#if TEST_PRINTABLE_ASCII_START >= TEST_PRINTABLE_ASCII_END +#error "Unit_Tests_DataProcess_Allocator_and_Deallocator(): TEST_PRINTABLE_ASCII_START must be less than TEST_PRINTABLE_ASCII_END." +#endif /* TEST_PRINTABLE_ASCII_START >= TEST_PRINTABLE_ASCII_END */ +#if TEST_PRINTABLE_ASCII_START < 1 +#error "Unit_Tests_DataProcess_Allocator_and_Deallocator(): TEST_PRINTABLE_ASCII_START must be a greater than or equal to one (1)." +#endif /* TEST_PRINTABLE_ASCII_START < 1 */ +#if TEST_PRINTABLE_ASCII_END < 2 +#error "Unit_Tests_DataProcess_Allocator_and_Deallocator(): TEST_PRINTABLE_ASCII_END must be a greater than or equal to two (2)." +#endif /* TEST_PRINTABLE_ASCII_END < 2 */ + + /* Undefine the macros. */ +#undef TEST_RANDOM_STRING_LENGTH_MAXIMUM +#undef TEST_RANDOM_STRING_LENGTH_MINIMAL +#undef TEST_PRINTABLE_ASCII_END +#undef TEST_PRINTABLE_ASCII_START +#undef TEST_ERROR_LOG +#undef TEST_ERROR_LOG_REAL +#undef TEST_FAILURE_MSG_HEAD +} + +/*! + * int Unit_Tests_DataProcess_Allocator_and_Deallocator() + * + * This function tests the DataProcess_Reallocate_C_String(), + * DataProcess_Reallocate_C_String_With_NULL_Terminator(), + * and DataProcess_Deallocate_CString() functions. + * + * Note: This test function depends on a working DataProcess_Trivial_Random_Number_Generator() + * function to work correctly, and may produce inaccurate results if + * DataProcess_Trivial_Random_Number_Generator() does not work correctly. + */ +int Unit_Tests_DataProcess_Allocator_and_Deallocator() +{ + /* Define the passed test message. */ +#define TEST_PASSED_MSG "Unit_Tests_DataProcess_Allocator_and_Deallocator(): TEST_PASSED" + + /* Define the error messaging macros. */ +#define TEST_FAILURE_MSG_HEAD "TEST_FAILURE: Unit_Tests_DataProcess_Allocator_and_Deallocator(): " +#define TEST_ERROR_LOG_REAL(ERR_MSG) printf("%s", TEST_FAILURE_MSG_HEAD); printf("%s", ERR_MSG); +#define TEST_ERROR_LOG(ERR_MSG) TEST_ERROR_LOG_REAL(ERR_MSG) + + /* Init vars. */ + int ret = -999; /* Result of the tests. */ + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; /* Result code from engine function. */ + size_t x = 0; /* Counter used in random string generation loop. */ + size_t randVal = 0; /* Result from the call to TRNG() function. */ + size_t randStringLength = 0; /* Length of the random string. */ + char * currentString = NULL; /* The current string pointer. */ + char * previousString = NULL; /* The previous string pointer. */ + char * randString = NULL; /* A random string. */ + const char * byteAllocationTestMSG = "Attempting to allocate one (1) byte using DataProcess_Reallocate_C_String().\n"; + const char * byteAllocationFailMSG = "Unable to allocate one (1) byte. "; + const char * byteReallocationTestMSG = "Attempting to reallocate the byte using DataProcess_Reallocate_C_String().\n"; + const char * byteReallocationFailMSG = "Unable to reallocate the byte. "; + const char * byteDeallocationTestMSG = "Attempting to deallocate the byte using DataProcess_Deallocate_CString().\n"; + const char * byteDeallocationFailMSG = "Unable to deallocate the byte.\n"; + const char * useAsAllocatorTestMSG = "Attempting to use DataProcess_Reallocate_C_String() as a memory allocator.\n"; + const char * useAsAllocatorFailMSG = "Unable to use DataProcess_Reallocate_C_String() as a memory allocator.\n"; + const char * rangeTest1MSG = "Attempting to reallocate the following string < "; + const char * rangeTest2MSG = " > using only the first "; + const char * rangeTest3MSG = " bytes"; + const char * rangeFailMSG = "Unable to reallocate the following string < "; + const char * dataMismatch1FailMSG = "Copied string < "; + const char * dataMismatch2FailMSG = " > does not match the source string.\n"; + const char * reallocationWithNullTermTestMSG = "Attempting to reallocate the random string with a NULL termination byte using DataProcess_Reallocate_C_String_With_NULL_Terminator().\n"; + const char * reallocationWithNullTermFailMSG = "Unable to reallocate the random string with a NULL termination byte.\n"; + const char * reallocationWithNullTermFailInvalidSize1MSG = "Expected length of NULL terminated string was: "; + const char * reallocationWithNullTermFailInvalidSize2MSG = ". The returned length was: "; + const char * reallocationWithNullTermFailNoNullMSG = "The reallocated string is not null byte terminated."; + const char * reallocationWithPreExistingNullTermTestMSG = "Attempting to reallocate the random string using DataProcess_Reallocate_C_String_With_NULL_Terminator() with a NULL termination byte already present.\n"; + const char * reallocationWithPreExistingNullTermFailMSG = "Unable to reallocate the random string with a pre-existing NULL termination byte using DataProcess_Reallocate_C_String_With_NULL_Terminator().\n"; + const char * reallocateCStringFunctMSG = "DataProcess_Reallocate_C_String()"; + const char * reallocateCStringWithNullFunctMSG = "DataProcess_Reallocate_C_String_With_NULL_Terminator()"; + + /* Start test section. */ + printf("%s", START_TEST_SECTION); + + /* Attempt to allocate a small amount of memory. */ + printf("%s", byteAllocationTestMSG); + retFromCall = DataProcess_Reallocate_C_String(¤tString, 0, 1); + if ((retFromCall == COMMON_ERROR_SUCCESS) && (currentString != NULL)) + { + /* Copy the pointer. */ + previousString = currentString; + + /* Now attempt to reallocate the string. */ + printf("%s", byteReallocationTestMSG); + retFromCall = retFromCall = DataProcess_Reallocate_C_String(¤tString, 1, 1); + if ((retFromCall == COMMON_ERROR_SUCCESS) && (currentString != NULL) && (currentString != previousString)) + { + /* Set previousString to NULL. + (The string was deallocated by DataProcess_Reallocate_C_String() as it was a copy of currentString's pointer value.) + */ + previousString = NULL; + + /* Test the deallocation function. */ + printf("%s", byteDeallocationTestMSG); + DataProcess_Deallocate_CString(¤tString); + if (currentString == NULL) + { + /* Warn user about TRNG use. */ + printf("%s", TRNGUseMayFailMSG); + fflush(stdout); + + /* Create the TRNG String. */ + retFromCall = Unit_Tests_DataProcess_Random_String_Generator(&randString, &randStringLength); + if ((retFromCall == 0) && (randString != NULL) && (randStringLength > 0)) + { + /* Reset retFromCall. */ + retFromCall = COMMON_ERROR_UNKNOWN_ERROR; + + /* Allocate memory to copy the random string into. */ + printf("%s", useAsAllocatorTestMSG); + retFromCall = DataProcess_Reallocate_C_String(¤tString, 0, randStringLength); + if ((retFromCall == COMMON_ERROR_SUCCESS) && (currentString != NULL)) + { + /* Copy the random string, because reallocating it will loose data. */ + memcpy(currentString, randString, randStringLength); + + /* Copy the pointer. (To make sure a new allocation is made.) */ + previousString = currentString; + + /* Generate one final random number to determine how much of the random string should be copied. */ + randVal = DataProcess_Trivial_Random_Number_Generator(2, (randStringLength - 1), false); + + /* Check and see if giving a range of the source string outputs the correct sub-string. */ + printf("%s%s%s%i%s%s", rangeTest1MSG, randString, rangeTest2MSG, randVal, rangeTest3MSG, periodAndNewlineMSG); + retFromCall = DataProcess_Reallocate_C_String(¤tString, randStringLength, randVal); + if ((retFromCall == COMMON_ERROR_SUCCESS) && (currentString != previousString) && (currentString != randString)) + { + /* Set previousString to NULL. + (The string was deallocated by DataProcess_Reallocate_C_String() as it was a copy of currentString's pointer value.) + */ + previousString = NULL; + + /* Begin verification loop. */ + for (x = 0; ((x < randVal) && (x < randStringLength)); x++) + { + /* Check for identical data in both strings. */ + if (randString[x] != currentString[x]) + { + /* Data mismatch. */ + break; + } + } + + /* Check result of verification loop. */ + if ((x == randVal) || (x == randStringLength)) + { + /* Test the DataProcess_Reallocate_C_String_With_NULL_Terminator() function by setting the + last byte of the currentString to a non-zero value. + */ + if (currentString[(randVal - 1)] == 0x0) + { + currentString[(randVal - 1)] = 0x1; + } + + /* Copy the string pointer. (To verifiy a new allocation was made.) */ + previousString = currentString; + + /* Abuse x to store the current random value. */ + x = randVal; + + /* Now reallocate the string. */ + printf("%s", reallocationWithNullTermTestMSG); + retFromCall = DataProcess_Reallocate_C_String_With_NULL_Terminator(¤tString, randVal, &x); + if ((retFromCall == COMMON_ERROR_SUCCESS) && (currentString != NULL) && (currentString != previousString) && + (currentString[(randVal)] == '\0')) + { + /* Set previousString to NULL. + (The string was deallocated by DataProcess_Reallocate_C_String() as it was a copy of currentString's pointer value.) + */ + previousString = NULL; + + /* Begin verification loop. */ + for (x = 0; ((x < randVal) && (x < randStringLength)); x++) + { + /* Check for identical data in both strings. */ + if (randString[x] != currentString[x]) + { + /* Data mismatch. */ + break; + } + } + + /* Check result of verification loop. */ + if ((x == randVal) || (x == randStringLength)) + { + /* Copy the pointer. */ + previousString = currentString; + + /* Recall DataProcess_Reallocate_C_String_With_NULL_Terminator() with a NULL'd string. + The size of the string should not change in this case. + */ + printf("%s", reallocationWithPreExistingNullTermTestMSG); + retFromCall = DataProcess_Reallocate_C_String_With_NULL_Terminator(¤tString, randVal, &x); + if ((retFromCall == COMMON_ERROR_SUCCESS) && (currentString != NULL) && (currentString != previousString) && + ((randVal < randStringLength) ? (currentString[(randVal)] == '\0') : (currentString[(randStringLength + 1)]))) + { + /* Set previousString to NULL. + (The string was deallocated by DataProcess_Reallocate_C_String() as it was a copy of currentString's pointer value.) + */ + previousString = NULL; + + /* Begin verification loop. */ + for (x = 0; ((x < randVal) && (x < randStringLength)); x++) + { + /* Check for identical data in both strings. */ + if (randString[x] != currentString[x]) + { + /* Data mismatch. */ + break; + } + } + + /* Check result of verification loop. */ + if ((x == randVal) || (x == randStringLength)) + { + /* Test for invalid argument caused by invalid pointer to pointer. */ + printf("%s%s%s", InvalidArgStringPointerTestMSG, reallocateCStringFunctMSG, periodAndNewlineMSG); + retFromCall = DataProcess_Reallocate_C_String(NULL, 0, x); + if (retFromCall == COMMON_ERROR_INVALID_ARGUMENT) + { + /* Test for invalid argument caused by invalid pointer to pointer. */ + printf("%s%s%s", InvalidArgStringPointerTestMSG, reallocateCStringWithNullFunctMSG, periodAndNewlineMSG); + retFromCall = DataProcess_Reallocate_C_String_With_NULL_Terminator(NULL, 0, &x); + if (retFromCall == COMMON_ERROR_INVALID_ARGUMENT) + { + /* Test for invalid argument caused by invalid pointer to pointer. */ + printf("%s%s%s", InvalidArgLengthPointerTestMSG, reallocateCStringWithNullFunctMSG, periodAndNewlineMSG); + retFromCall = DataProcess_Reallocate_C_String_With_NULL_Terminator(¤tString, 0, NULL); + if (retFromCall == COMMON_ERROR_INVALID_ARGUMENT) + { + /* Test successful. */ + printf("%s%s", TEST_PASSED_MSG, periodAndNewlineMSG); + ret = 0; + } + else + { + /* Did not get COMMON_ERROR_INVALID_ARGUMENT error code from () due to invalid newLength pointer. */ + ret = -14; + printf("%s%s%s", InvalidArgLengthPointerFailMSG, reallocateCStringWithNullFunctMSG, periodAndNewlineMSG); + } + } + else + { + /* Did not get COMMON_ERROR_INVALID_ARGUMENT error code from () due to invalid string pointer. */ + ret = -13; + printf("%s%s%s", InvalidArgStringPointerFailMSG, reallocateCStringWithNullFunctMSG, periodAndNewlineMSG); + } + } + else + { + /* Did not get COMMON_ERROR_INVALID_ARGUMENT error code from DataProcess_Reallocate_C_String(). */ + ret = -12; + printf("%s%s%s", InvalidArgStringPointerFailMSG, reallocateCStringFunctMSG, periodAndNewlineMSG); + } + } + else + { + /* Reallocation with NULL byte failed. Data Mismatch. */ + ret = -11; + TEST_ERROR_LOG(reallocationWithPreExistingNullTermFailMSG); + printf("%s%s%s", dataMismatch1FailMSG, currentString, dataMismatch2FailMSG); + } + } + else + { + /* Reallocation with NULL byte failed. */ + ret = -10; + TEST_ERROR_LOG(reallocationWithPreExistingNullTermFailMSG); + ((retFromCall != COMMON_ERROR_SUCCESS) ? (printf("%s%i%s", errorCodeReturnedMSG, retFromCall, ".\n")) : + (currentString == NULL) ? (printf("%s", errorSuccessNoResultMSG)) : + (currentString == previousString) ? (printf("%s", errorSamePtrMSG)) : + (printf(reallocationWithNullTermFailNoNullMSG))); + } + } + else + { + /* Reallocation with NULL byte failed. Data Mismatch. */ + ret = -9; + TEST_ERROR_LOG(reallocationWithNullTermFailMSG); + printf("%s%s%s", dataMismatch1FailMSG, currentString, dataMismatch2FailMSG); + } + } + else + { + /* Reallocation with NULL byte failed. */ + ret = -8; + TEST_ERROR_LOG(reallocationWithNullTermFailMSG); + ((retFromCall != COMMON_ERROR_SUCCESS) ? (printf("%s%i%s", errorCodeReturnedMSG, retFromCall, ".\n")) : + (currentString == NULL) ? (printf("%s", errorSuccessNoResultMSG)) : + (currentString == previousString) ? (printf("%s", errorSamePtrMSG)) : + (x != randVal) ? (printf("%s%i%s%i%s" , reallocationWithNullTermFailInvalidSize1MSG, randVal, + reallocationWithNullTermFailInvalidSize2MSG, x, periodAndNewlineMSG)) : (printf(reallocationWithNullTermFailNoNullMSG))); + } + } + else + { + /* Error data mismatch. */ + ret = -7; + TEST_ERROR_LOG(rangeFailMSG); + printf("%s%s%i%s%s%s%s%s", randString, rangeTest2MSG, randVal, rangeTest3MSG, periodAndNewlineMSG, dataMismatch1FailMSG, currentString, dataMismatch2FailMSG); + } + } + else + { + /* Could not complete range test. */ + ret = -6; + TEST_ERROR_LOG(rangeFailMSG); + printf("%s%s%i%s", randString, rangeTest2MSG, randVal, rangeTest3MSG); + ((retFromCall != COMMON_ERROR_SUCCESS) ? (printf("%s%i%s", errorCodeReturnedMSG, retFromCall, ".\n")) : + (currentString == NULL) ? (printf("%s", errorSuccessNoResultMSG)) : (printf("%s", errorSamePtrMSG))); + } + } + else + { + /* Could not allocate memory? */ + ret = -5; + TEST_ERROR_LOG(useAsAllocatorFailMSG); + ((retFromCall != COMMON_ERROR_SUCCESS) ? (printf("%s%i%s", errorCodeReturnedMSG, retFromCall, ".\n")) : + (printf("%s", errorSuccessNoResultMSG))); + } + } + else + { + /* Could not allocate memory? */ + ret = -4; + TEST_ERROR_LOG(useAsAllocatorFailMSG); + ((retFromCall != COMMON_ERROR_SUCCESS) ? (printf("%s%i%s", errorCodeReturnedMSG, retFromCall, ".\n")) : + (printf("%s", errorSuccessNoResultMSG))); + } + } + else + { + /* Could not deallocate the byte. */ + ret = -3; + TEST_ERROR_LOG(byteDeallocationFailMSG); + } + } + else + { + /* Could not reallocate the byte. */ + ret = -2; + TEST_ERROR_LOG(byteReallocationFailMSG); + ((retFromCall != COMMON_ERROR_SUCCESS) ? (printf("%s%i%s", errorCodeReturnedMSG, retFromCall, ".\n")) : + ((currentString != NULL) ? (printf("%s", errorSuccessNoResultMSG)) : (printf("%s", errorSamePtrMSG)))); + } + + /* Flush output buffer. */ + fflush(stdout); + + /* Make sure to release memory if needed. */ + if (currentString != NULL) + { + DataProcess_Deallocate_CString(¤tString); + } + if (previousString != NULL) + { + DataProcess_Deallocate_CString(&previousString); + } + if (randString != NULL) + { + DataProcess_Deallocate_CString(&randString); + } + } + else + { + /* Could not allocate a byte? */ + ret = -1; + TEST_ERROR_LOG(byteAllocationFailMSG); + ((retFromCall != COMMON_ERROR_SUCCESS) ? (printf("%s%i%s", errorCodeReturnedMSG, retFromCall, ".\n")) : + (printf("%s", errorSuccessNoResultMSG))); + } + + /* End test section. */ + printf("%s", END_TEST_SECTION); + + /* Exit function. */ + return ret; + + /* Undefine the macros. */ +#undef TEST_ERROR_LOG +#undef TEST_ERROR_LOG_REAL +#undef TEST_FAILURE_MSG_HEAD +#undef TEST_PASSED_MSG +} + +/*! + * int Unit_Tests_DataProcess_sizet_cstring_converter_string_verification_number_conversion_function() + * + * Takes a given number between zero (0) and ten (10) and returns it's arabic numeral text character. + * + * If the given number is outside the range of zero (0) and ten (10) then -1 is returned. + */ +int Unit_Tests_DataProcess_sizet_cstring_converter_string_verification_number_conversion_function(const size_t number) +{ + /* Define numbersLength. */ +#define NUMBERSLENGTH 11 + + /* Init vars. */ + int ret = -1; /* The result of this function. */ + const char numbers[NUMBERSLENGTH] = {"0123456789"}; /* Array to contain the text versions of the given numbers. */ + + /* Check given number argument. */ + if ((0 <= number) && (number < 10)) + { + /* Get the number so we can return it. */ + ret = (char)(numbers[number]); + } + + /* Exit function. */ + return ret; + + /* Undef NUMBERSLENGTH. */ +#undef NUMBERSLENGTH +} + +/*! + * int Unit_Tests_DataProcess_sizet_cstring_converter_string_verification_function(const size_t randomNumber, const char * string, const size_t stringLength) + * + * Ok, the purpose of this function is to verify that a generated string matches the number it was made from. + * + * To that extent, we wind up reimplimenting the functionality of DataProcess_getCStringFromSizeT(), + * but instead of creating a string we are checking it for accuracy. + */ +int Unit_Tests_DataProcess_sizet_cstring_converter_string_verification_function(const size_t randomNumber, const char * string, const size_t stringLength) +{ + /* Define the error messaging macros. */ +#define TEST_FAILURE_MSG_HEAD "TEST_FAILURE: Unit_Tests_DataProcess_sizet_cstring_converter_string_verification_function(): " +#define TEST_ERROR_LOG_REAL(ERR_MSG) printf("%s", TEST_FAILURE_MSG_HEAD); printf("%s", ERR_MSG); +#define TEST_ERROR_LOG(ERR_MSG) TEST_ERROR_LOG_REAL(ERR_MSG) + + /* Define the numeric base of DataProcess_getCStringFromSizeT(). */ +#define TEST_NUMERIC_BASE 10 + + /* Init vars. */ + char cNumber = '0'; /* Used to hold the current number we are checking for in the given string. */ + int ret = -1; /* The result of this function. */ + size_t currentValue = 0; /* The current number being verified. */ + size_t x = 0; /* Counter used in verififcation loop. */ + + /* Check for invalid arguments. */ + if ((string != NULL) && (stringLength > 0)) + { + /* Set current value. */ + currentValue = randomNumber; + + /* Begin verification loop. */ + for (x = 0; ((ret == -1) && (x < (stringLength - 1)) && (((stringLength - 2) - x) >= 0) && (currentValue > 0)); x++) + { + /* Devide off the last digit and convert it to a text character. */ + cNumber = Unit_Tests_DataProcess_sizet_cstring_converter_string_verification_number_conversion_function((currentValue % TEST_NUMERIC_BASE)); + + /* Check the text character for a match in the given string. */ + if (string[((stringLength - 2) - x)] == cNumber) + { + /* Proceed to the next value in the string. */ + currentValue /= TEST_NUMERIC_BASE; + } + else + { + /* Invalid text string. */ + ret = -3; + } + } + + /* Check counter value for success. */ + if ((ret == -1) && (x == (stringLength - 1))) + { + /* String matches the number. */ + ret = 0; + } + else + { + /* Invalid string. */ + ret = -3; + } + } + else + { + /* Invalid argument. */ + ret = -2; + TEST_ERROR_LOG("Invalid argument.\n"); + } + + /* Exit function. */ + return ret; + + /* Undef macros. */ +#undef TEST_NUMERIC_BASE +#undef TEST_ERROR_LOG +#undef TEST_ERROR_LOG_REAL +#undef TEST_FAILURE_MSG_HEAD +} + +/*! + * int Unit_Tests_DataProcess_sizet_cstring_converter() + * + * This function tests the DataProcess_getCStringFromSizeT() function. + */ +int Unit_Tests_DataProcess_sizet_cstring_converter() +{ + /* Define the name of the function. */ +#define MSYS_FUNCT_NAME "Unit_Tests_DataProcess_sizet_cstring_converter()" +#define MSYS_TESTING_FUNCT_NAME "DataProcess_getCStringFromSizeT()" + + /* Define the passed test message. */ +#define TEST_PASSED_MSG "Unit_Tests_DataProcess_sizet_cstring_converter(): TEST_PASSED" + + /* Define the error messaging macros. */ +#define TEST_FAILURE_MSG_HEAD "TEST_FAILURE: Unit_Tests_DataProcess_sizet_cstring_converter(): " +#define TEST_ERROR_LOG_REAL(ERR_MSG) printf("%s", TEST_FAILURE_MSG_HEAD); printf("%s", ERR_MSG); +#define TEST_ERROR_LOG(ERR_MSG) TEST_ERROR_LOG_REAL(ERR_MSG) + + /* Define the limits on the random number range. (MINIMAL value should be less than the MAXIMUM value and both should be positive.) */ +#define TEST_MINIMAL_RANDOM_NUMBER_VALUE 1 +#define TEST_MAXIMUM_RANDOM_NUMBER_VALUE 100 + + /* Init vars. */ + int ret = 0; /* The result of this test function. */ + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; /* The result of a call to an engine function. */ + size_t randVal = 0; /* Used to generate a random number to use with DataProcess_getCStringFromSizeT(). */ + size_t currentStringLength = 0; /* The length of the currentString.... string. */ + char * currentString = NULL; /* The current string pointer. */ + char * previousString = NULL; /* The previous string pointer. */ + + /* Start test section. */ + printf("%s", START_TEST_SECTION); + + /* Warn user about TRNG use. */ + printf("%s", TRNGUseMayFailMSG); + fflush(stdout); + + /* Generate a random number. */ + printf("%s%s", MSYS_FUNCT_NAME, " Attempting to generate a random number.\n"); + randVal = DataProcess_Trivial_Random_Number_Generator(TEST_MINIMAL_RANDOM_NUMBER_VALUE, TEST_MAXIMUM_RANDOM_NUMBER_VALUE, true); + if (randVal != 0) + { + /* Attempt to generate the string version of the random number. */ + printf("%s%s%i%s", MSYS_FUNCT_NAME, " Attempting to generate the string version of the random number: <", randVal, ">.\n"); + retFromCall = DataProcess_getCStringFromSizeT(randVal, ¤tString, ¤tStringLength); + if ((retFromCall == COMMON_ERROR_SUCCESS) && (currentString != NULL) && (currentStringLength > 0)) + { + /* Check the result.... */ + printf("%s%s", MSYS_FUNCT_NAME, " checking result.\n"); + ret = Unit_Tests_DataProcess_sizet_cstring_converter_string_verification_function(randVal, currentString, currentStringLength); + if (ret == 0) + { + /* Copy the pointer. */ + previousString = currentString; + + /* Reset currentStringLength. */ + currentStringLength = 0; + + /* Check and see if the function will overwrite the given pointer. */ + printf("%s%s%s%s", MSYS_FUNCT_NAME, " checking to see if the given string pointer will be overwritten by ", MSYS_TESTING_FUNCT_NAME, periodAndNewlineMSG); + retFromCall = DataProcess_getCStringFromSizeT(randVal, ¤tString, ¤tStringLength); + if ((retFromCall == COMMON_ERROR_SUCCESS) && (currentString != NULL) && (currentString != previousString) && (currentStringLength > 0)) + { + /* Deallocate the strings. */ + DataProcess_Deallocate_CString(&previousString); + DataProcess_Deallocate_CString(¤tString); + currentStringLength = 0; + + /* Check for INVALID_ARGUMENT error code if DataProcess_getCStringFromSizeT() is given a bad string pointer. */ + printf("%s%s%s", InvalidArgStringPointerTestMSG, MSYS_TESTING_FUNCT_NAME, periodAndNewlineMSG); + retFromCall = DataProcess_getCStringFromSizeT(randVal, NULL, ¤tStringLength); + if (retFromCall == COMMON_ERROR_INVALID_ARGUMENT) + { + /* Check for INVALID_ARGUMENT error code if DataProcess_getCStringFromSizeT() is given a bad stringLength pointer. */ + printf("%s%s%s", InvalidArgLengthPointerTestMSG, MSYS_TESTING_FUNCT_NAME, periodAndNewlineMSG); + retFromCall = DataProcess_getCStringFromSizeT(randVal, ¤tString, NULL); + if (retFromCall == COMMON_ERROR_INVALID_ARGUMENT) + { + /* Test successful. */ + printf("%s%s", TEST_PASSED_MSG, periodAndNewlineMSG); + ret = 0; + } + else + { + /* Did not get invalid argument error code for bad string length pointer. */ + ret = -6; + TEST_ERROR_LOG(InvalidArgLengthPointerFailMSG); + printf("%s%s", MSYS_TESTING_FUNCT_NAME, periodAndNewlineMSG); + printf("%s%i%s", errorCodeReturnedMSG, retFromCall, periodAndNewlineMSG); + } + } + else + { + /* Did not get invalid argument error code for bad string pointer. */ + ret = -5; + TEST_ERROR_LOG(InvalidArgStringPointerFailMSG); + printf("%s%s", MSYS_TESTING_FUNCT_NAME, periodAndNewlineMSG); + printf("%s%i%s", errorCodeReturnedMSG, retFromCall, periodAndNewlineMSG); + } + } + else + { + /* Test of overwriting the given pointer failed. */ + ret = -4; + TEST_ERROR_LOG("overwriting the given pointer failed.\n"); + ((retFromCall != COMMON_ERROR_SUCCESS) ? (printf("%s%i%s", errorCodeReturnedMSG, retFromCall, periodAndNewlineMSG)) : + (currentString == previousString) ? (printf("%s", errorSamePtrMSG)) : + (printf("%s", errorSuccessNoResultMSG))); + } + } + else + { + /* Verification of string failed. */ + ret = -3; + TEST_ERROR_LOG("Verification of string failed.\n"); + printf("%s%i%s%s%s", "The random number <", randVal, "> does not match the generated string <", currentString, ">.\n"); + } + + /* Deallocate the result if needed. */ + if (currentString != NULL) + { + DataProcess_Deallocate_CString(¤tString); + currentStringLength = 0; + } + } + else + { + /* Could not generate c-string. */ + ret = -2; + TEST_ERROR_LOG("Could not generate c-string.\n"); + ((retFromCall != COMMON_ERROR_SUCCESS) ? (printf("%s%i%s", errorCodeReturnedMSG, retFromCall, periodAndNewlineMSG)) : + (printf("%s", errorSuccessNoResultMSG))); + } + } + else + { + /* Could not generate a random number. */ + ret = -1; + TEST_ERROR_LOG("Could not generate a random number.\n"); + } + + /* End test section. */ + printf("%s", END_TEST_SECTION); + + /* Flush output buffer. */ + fflush(stdout); + + /* Exit function. */ + return ret; + + /* Check for invalid random number range. */ +#if TEST_MINIMAL_RANDOM_NUMBER_VALUE < 1 +#error "Unit_Tests_DataProcess_sizet_cstring_converter(): TEST_MINIMAL_RANDOM_NUMBER_VALUE must be a greater than or equal to one (1)." +#endif /* TEST_MINIMAL_RANDOM_NUMBER_VALUE < 1 */ +#if TEST_MAXIMUM_RANDOM_NUMBER_VALUE < 2 +#error "Unit_Tests_DataProcess_sizet_cstring_converter(): TEST_MAXIMUM_RANDOM_NUMBER_VALUE must be a greater than or equal to two (2)." +#endif /* TEST_MAXIMUM_RANDOM_NUMBER_VALUE < 2 */ + + /* Undefine the macros. */ +#undef TEST_MAXIMUM_RANDOM_NUMBER_VALUE +#undef TEST_MINIMAL_RANDOM_NUMBER_VALUE +#undef TEST_ERROR_LOG +#undef TEST_ERROR_LOG_REAL +#undef TEST_FAILURE_MSG_HEAD +#undef TEST_PASSED_MSG +#undef MSYS_TESTING_FUNCT_NAME +#undef MSYS_FUNCT_NAME +} + +int Unit_Tests_DataProcess_Main() +{ + /* Init vars. */ + int ret = 0; /* Result of the tests. */ + int retFromTRNGTest = 0; /* Result of the TRNG test. */ + int retFromAllocatorTest = 0; /* Result of the allocator and deallocator tests. */ + int retFromSizeTCStringConversionTest = 0; /* Result of the size_t to c-string conversion tests. */ + + /* Begin tests for DataProcess_Trivial_Random_Number_Generator(). */ + retFromTRNGTest = Unit_Tests_DataProcess_TRNG(); + + /* Begin tests for DataProcess_Reallocate_C_String() and DataProcess_Deallocate_CString(). */ + retFromAllocatorTest = Unit_Tests_DataProcess_Allocator_and_Deallocator(); + + /* Begin tests for DataProcess_getCStringFromSizeT(). */ + retFromSizeTCStringConversionTest = Unit_Tests_DataProcess_sizet_cstring_converter(); + + /* Return ret. */ + return ret; +} diff --git a/src/Tests/Unit_Test_Data_Object.cpp b/src/Tests/Unit_Test_Data_Object.cpp index 43ba43c..baa190f 100644 --- a/src/Tests/Unit_Test_Data_Object.cpp +++ b/src/Tests/Unit_Test_Data_Object.cpp @@ -1077,14 +1077,14 @@ int Unit_Test_Data_Object() } // Tell User we are starting the insert test for (char). - cout << "DataProcess::Data_Object::insert() (char): "; + std::cout << "DataProcess::Data_Object::insert() (char): "; if (Unit_Test_Data_Object_Insert_char() == 0) { - cout << "PASS\n"; + std::cout << "PASS\n"; } else { - cout << "FAIL\n"; + std::cout << "FAIL\n"; return -1; } diff --git a/src/Tests/Unit_Tests.cpp b/src/Tests/Unit_Tests.cpp index 56f4df9..a1685d6 100644 --- a/src/Tests/Unit_Tests.cpp +++ b/src/Tests/Unit_Tests.cpp @@ -24,15 +24,23 @@ int main() { // Delcare vars. + int error_code_dataprocess = 0; short error_code_data_object = 0; short error_code_fileutills = 0; short error_code_thread_utils = 0; + int error_code_byte_order = 0; // Starting Unit tests. std::cout << "Multiverse_Engine_Project_Public Unit Tests Compiled on: " << TESTCOMPILEDATE << " " << TESTCOMPILETIME << "\n"; - std::cout << "Starting Unit tests for DataProcess::Data_Object. Please be pacent this can take some time.\n"; + std::cout << "Starting Unit tests for DataProcess functions.\n"; + error_code_dataprocess = Unit_Tests_DataProcess_Main(); + + std::cout << "Starting Unit tests for DataProcess::Data_Object. Please be patient this can take some time.\n"; error_code_data_object = Unit_Test_Data_Object(); + std::cout << "Starting unit tests for Byte_Order. Please wait.\n"; + error_code_byte_order = Unit_Test_Byte_Order_Main(); + /* Only call FileUtills tests if FileUtills was built. */ #ifdef MSYS_HAVE_FILEUTILLS std::cout << "Starting FileUtills Tests.\n"; diff --git a/src/Tests/Unit_Tests_Byte_Order.h b/src/Tests/Unit_Tests_Byte_Order.h new file mode 100644 index 0000000..6f57575 --- /dev/null +++ b/src/Tests/Unit_Tests_Byte_Order.h @@ -0,0 +1,80 @@ +/*! + Multiverse Engine Project 11/7/2015 Unit Tests Unit_Tests_Byte_Order.h + + Copyright (C) 2015 Multiverse Engine Project + + This program is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Official source repository and project information can be found at + https://github.com/codebase7/mengine +*/ + +/* Include guard. */ +#ifndef UNIT_TESTS_BYTE_ORDER_H +#define UNIT_TESTS_BYTE_ORDER_H + +/* Internal includes. */ +#include "../Common/Src/Byte_Order/Byte_Order.h" + +/* Define test functions. */ +/*! + * void Print_Random_Bits(const char bits) + * + * Wrapper around Common_Print_Bytes_In_Binary() and + * Common_Deallocate_Print_Bytes_CString() to print + * the given byte to the standard output. + * + * This function has no return. + */ +void Print_Random_Bits(const char bits); + +/*! + * char Generate_Random_Bit_Mask(const char bitMask) + * + * Generates some random bits between 1 and 254, retrying if it + * generates the given bitMask, while telling the user + * it is doing so. + * + * Returns the generated bit mask. + */ +char Generate_Random_Bit_Mask(const char bitMask); + +/*! + * char Generate_Random_Bits(const char notThisValue) + * + * Generates some random bits between 2 and 254, retrying if it + * generates the given notThisValue, while telling the user + * it is doing so. + * + * Returns the generated bits. + */ +char Generate_Random_Bits(const char notThisValue); + +int unit_test_byte_order_Common_Print_Bytes_In_Binary_check(); + +/*! + * int unit_test_byte_order_comparison_check() + * + * Performs tests on the Byte_Order_Bit_Comparison() function. + */ +int unit_test_byte_order_comparison_check(); + +/*! + * int Unit_Test_Byte_Order_Main() + * + * Main test function for Byte_Order. + */ +int Unit_Test_Byte_Order_Main(); + +#endif /* UNIT_TESTS_BYTE_ORDER_H */ + +/* End of Unit_Tests_Byte_Order.h */ diff --git a/src/Tests/Unit_Tests_Common_Error_Handler.cpp b/src/Tests/Unit_Tests_Common_Error_Handler.cpp index 1dcf0c9..bd345bc 100644 --- a/src/Tests/Unit_Tests_Common_Error_Handler.cpp +++ b/src/Tests/Unit_Tests_Common_Error_Handler.cpp @@ -24,12 +24,26 @@ /* External includes. */ #include -void Common_Error_Log_Callback(const unsigned int logLevel, const char * errorMsg) +void Common_Error_Log_Callback(const int channelID, const unsigned int logLevel, const char * errorMsg) { + /* Init vars. */ + size_t nameLength = 0; + const char * name = NULL; + int retFromCall = COMMON_ERROR_UNKNOWN_ERROR; + // Print to std::cout. if (errorMsg != NULL) { - std::cout << errorMsg; + /* Attempt to get the Channel Name. */ + retFromCall = Common_Error_Get_Logging_Channel_Name_By_ID_Number(channelID, &name, &nameLength); + if ((retFromCall == COMMON_ERROR_SUCCESS) && (name != NULL) && (nameLength > 0)) + { + std::cout << name << ": " << errorMsg; + } + else + { + std::cout << errorMsg; + } std::cout.flush(); } diff --git a/src/Tests/Unit_Tests_Common_Error_Handler.h b/src/Tests/Unit_Tests_Common_Error_Handler.h index 31bf453..9e42f76 100644 --- a/src/Tests/Unit_Tests_Common_Error_Handler.h +++ b/src/Tests/Unit_Tests_Common_Error_Handler.h @@ -26,12 +26,12 @@ #include "../Common/Src/Error_Handler/Common_Error_Handler.h" /*! - * void Common_Error_Log_Callback(const unsigned int logLevel, const char * errorMsg) + * void Common_Error_Log_Callback(const int channelID, const unsigned int logLevel, const char * errorMsg) * * Callback function for Common::Register_Error_Log_Callback(). * Displays given error message on standard output. */ -void Common_Error_Log_Callback(const unsigned int logLevel, const char * errorMsg); +void Common_Error_Log_Callback(const int channelID, const unsigned int logLevel, const char * errorMsg); #endif /* UNIT_TESTS_COMMON_ERROR_HANDLER_H */ diff --git a/src/Common/Src/Mutexes/stdbool.h b/src/stdbool.h similarity index 76% rename from src/Common/Src/Mutexes/stdbool.h rename to src/stdbool.h index e7b9d91..056709f 100644 --- a/src/Common/Src/Mutexes/stdbool.h +++ b/src/stdbool.h @@ -23,9 +23,18 @@ #ifndef MSYS_STD_BOOL_H #define MSYS_STD_BOOL_H +/* This is only needed for C. */ +#ifndef __cplusplus + +/* Only define this if STD_BOOL is not defined. */ +#ifndef _STDBOOL + +/* Only define this if __bool_true_false_are_defined is not defined. */ +#ifndef __bool_true_false_are_defined + /* Define true and false. */ -#define TRUE 0x01 /* Really this could be anything. */ -#define FALSE 0x00 /* Litteral NULL byte to conform to ANYTHING NOT NULL IS TRUE. */ +#define TRUE 1 /* Really this could be anything. */ +#define FALSE 0 /* Litteral NULL byte to conform to ANYTHING NOT NULL IS TRUE. */ #define true TRUE #define false FALSE @@ -34,6 +43,9 @@ typedef char bool; /* This is a char to conform to the expectation in C++ that s /* Define __bool_true_false_are_defined (ISO) */ #define __bool_true_false_are_defined 1 +#endif /* __bool_true_false_are_defined */ +#endif /* _STDBOOL */ +#endif /* __cplusplus */ #endif /* MSYS_STD_BOOL_H */